{"version":3,"file":"unify-videoplayer-videojs-bundle.iife.min.js","sources":["../../../../Vendor/auf/afLogger.js","../../src/trackers/aufVideoLogger.ts","../../src/utils/utils.ts","../../src/utils/video-logger.ts","../../src/enums/publishable-events.enum.ts","../../src/enums/video-plugins.enum.ts","../../src/enums/aspect-ratio.enum.ts","../../src/enums/dailymotion-internal-events.enum.ts","../../src/enums/player-position.enum.ts","../../src/enums/players.enum.ts","../../node_modules/pubsub-js/src/pubsub.js","../../src/plugins/analytics/analytics.ts","../../node_modules/lodash.debounce/index.js","../../src/plugins/autoplay/autoplay.ts","../../src/plugins/debug/debug.ts","../../node_modules/rxjs/src/internal/util/isFunction.ts","../../node_modules/rxjs/src/internal/config.ts","../../node_modules/rxjs/src/internal/util/hostReportError.ts","../../node_modules/rxjs/src/internal/Observer.ts","../../node_modules/rxjs/src/internal/util/isObject.ts","../../node_modules/rxjs/src/internal/util/UnsubscriptionError.ts","../../node_modules/rxjs/src/internal/Subscription.ts","../../node_modules/rxjs/src/internal/symbol/rxSubscriber.ts","../../node_modules/rxjs/src/internal/Subscriber.ts","../../node_modules/rxjs/src/internal/util/identity.ts","../../node_modules/rxjs/src/internal/util/pipe.ts","../../node_modules/rxjs/src/internal/Observable.ts","../../node_modules/rxjs/src/internal/util/toSubscriber.ts","../../node_modules/rxjs/src/internal/util/canReportError.ts","../../node_modules/rxjs/src/internal/util/subscribeToArray.ts","../../node_modules/rxjs/src/internal/symbol/iterator.ts","../../node_modules/rxjs/src/internal/util/isPromise.ts","../../node_modules/rxjs/src/internal/util/subscribeTo.ts","../../node_modules/rxjs/src/internal/util/subscribeToObservable.ts","../../node_modules/rxjs/src/internal/util/subscribeToPromise.ts","../../node_modules/rxjs/src/internal/util/subscribeToIterable.ts","../../node_modules/rxjs/src/internal/innerSubscribe.ts","../../node_modules/rxjs/src/internal/util/isScheduler.ts","../../node_modules/rxjs/src/internal/scheduled/scheduleArray.ts","../../node_modules/rxjs/src/internal/observable/fromArray.ts","../../node_modules/rxjs/src/internal/scheduled/scheduled.ts","../../node_modules/rxjs/src/internal/util/isInteropObservable.ts","../../node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts","../../node_modules/rxjs/src/internal/scheduled/schedulePromise.ts","../../node_modules/rxjs/src/internal/util/isIterable.ts","../../node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts","../../node_modules/rxjs/src/internal/observable/from.ts","../../node_modules/rxjs/src/internal/operators/map.ts","../../node_modules/rxjs/src/internal/operators/mergeMap.ts","../../node_modules/rxjs/src/internal/operators/mergeAll.ts","../../node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts","../../node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts","../../node_modules/rxjs/src/internal/SubjectSubscription.ts","../../node_modules/rxjs/src/internal/Subject.ts","../../node_modules/rxjs/src/internal/operators/mapTo.ts","../../src/enums/sticky-formats.enum.ts","../../node_modules/rxjs/src/internal/BehaviorSubject.ts","../../node_modules/redom/dist/redom.es.js","../../src/plugins/sticky/utils/get-classname.util.ts","../../src/plugins/sticky/enums/buttons-events.enum.ts","../../src/plugins/sticky/enums/visibility.enum.ts","../../src/plugins/sticky/components/base-element.ts","../../src/plugins/sticky/components/global/placeholder/placeholder.component.ts","../../node_modules/rxjs/src/internal/observable/fromEvent.ts","../../src/plugins/sticky/components/global/buttons/buttons.util.ts","../../src/plugins/sticky/components/global/buttons/button.component.ts","../../src/plugins/sticky/components/global/buttons-bar/buttons-bar.component.ts","../../node_modules/rxjs/src/internal/observable/merge.ts","../../src/plugins/sticky/components/layouts/base-layout.ts","../../src/plugins/sticky/sticky-core.ts","../../src/plugins/sticky/utils/merge-functions.util.ts","../../src/plugins/sticky/components/layouts/flying/flying.layout.component.ts","../../src/plugins/sticky/components/layouts/banner/banner-layout.component.ts","../../src/plugins/sticky/utils/session-storage.util.ts","../../src/plugins/sticky/utils/dom.util.ts","../../src/utils/time-utils.service.ts","../../src/plugins/sticky/utils/translate.util.ts","../../src/store.ts","../../src/manager.ts","../../src/adPlayers/_adapter.ts","../../src/adPlayers/ima.ts","../../node_modules/bowser/src/constants.js","../../node_modules/bowser/src/utils.js","../../node_modules/bowser/src/parser-browsers.js","../../node_modules/bowser/src/parser-os.js","../../node_modules/bowser/src/parser-platforms.js","../../node_modules/bowser/src/parser-engines.js","../../node_modules/bowser/src/parser.js","../../src/trackers/utils/ga-tracking.util.ts","../../src/trackers/GAVideoTracking.ts","../../src/spawner.ts","../../node_modules/bowser/src/bowser.js","../../src/main.ts","../../src/utils/detect-device.util.ts","../../src/utils/events.util.ts","../../src/players/_adapter.ts","../../node_modules/global/window.js","../../node_modules/dom-walk/index.js","../../node_modules/min-document/dom-comment.js","../../node_modules/min-document/dom-text.js","../../node_modules/min-document/event/dispatch-event.js","../../node_modules/min-document/event/add-event-listener.js","../../node_modules/min-document/event/remove-event-listener.js","../../node_modules/min-document/serialize.js","../../node_modules/min-document/dom-element.js","../../node_modules/min-document/dom-fragment.js","../../node_modules/min-document/event.js","../../node_modules/min-document/document.js","../../node_modules/min-document/index.js","../../node_modules/global/document.js","../../node_modules/@babel/runtime/helpers/extends.js","../../node_modules/keycode/index.js","../../node_modules/@babel/runtime/helpers/assertThisInitialized.js","../../node_modules/@babel/runtime/helpers/setPrototypeOf.js","../../node_modules/@babel/runtime/helpers/inheritsLoose.js","../../node_modules/safe-json-parse/tuple.js","../../node_modules/is-function/index.js","../../node_modules/@videojs/xhr/lib/http-handler.js","../../node_modules/@videojs/xhr/lib/index.js","../../node_modules/videojs-vtt.js/lib/vtt.js","../../node_modules/videojs-vtt.js/lib/vttcue.js","../../node_modules/videojs-vtt.js/lib/vttregion.js","../../node_modules/videojs-vtt.js/lib/browser-index.js","../../node_modules/@babel/runtime/helpers/isNativeReflectConstruct.js","../../node_modules/@babel/runtime/helpers/construct.js","../../node_modules/@babel/runtime/helpers/inherits.js","../../node_modules/url-toolkit/src/url-toolkit.js","../../node_modules/@videojs/vhs-utils/es/resolve-url.js","../../node_modules/@videojs/vhs-utils/es/stream.js","../../node_modules/@videojs/vhs-utils/es/decode-b64-to-uint8-array.js","../../node_modules/m3u8-parser/dist/m3u8-parser.es.js","../../node_modules/@videojs/vhs-utils/es/codecs.js","../../node_modules/@videojs/vhs-utils/es/media-types.js","../../node_modules/@xmldom/xmldom/lib/conventions.js","../../node_modules/@xmldom/xmldom/lib/dom.js","../../node_modules/@xmldom/xmldom/lib/entities.js","../../node_modules/@xmldom/xmldom/lib/sax.js","../../node_modules/@xmldom/xmldom/lib/dom-parser.js","../../node_modules/@videojs/vhs-utils/es/byte-helpers.js","../../node_modules/@xmldom/xmldom/lib/index.js","../../node_modules/mpd-parser/dist/mpd-parser.es.js","../../node_modules/@videojs/vhs-utils/es/media-groups.js","../../node_modules/mux.js/lib/utils/numbers.js","../../node_modules/mux.js/lib/tools/parse-sidx.js","../../node_modules/@videojs/vhs-utils/es/id3-helpers.js","../../node_modules/@videojs/vhs-utils/es/mp4-helpers.js","../../node_modules/@videojs/vhs-utils/es/ebml-helpers.js","../../node_modules/@videojs/vhs-utils/es/nal-helpers.js","../../node_modules/@videojs/vhs-utils/es/containers.js","../../node_modules/mux.js/lib/utils/clock.js","../../node_modules/video.js/dist/video.es.js","../../src/vendors/videojs-contrib-ads.js","../../src/vendors/videojs.ima-updated.js","../../src/players/video-js.ts","../../src/starters/videojs.starter.ts"],"sourcesContent":["/* globals XDomainRequest */\nvar Aflog = window.Aflog || {};\n\n// TODO: replace with a proper array queue to remove dependancy with afLogger object:\n// - before: Aflog.cmd.push(function() { afLogger.logConsole('async log'); } ):\n// - after: Aflog('logConsole', 'async log');\nAflog.Queue = (function () {\n var queue = function (cmd) {\n this.push(cmd);\n };\n\n queue.prototype = {\n constructor: queue,\n push: function () {\n for (var i = 0; i < arguments.length; i++) {\n try {\n if (typeof arguments[i] === 'function') {\n arguments[i]();\n }\n } catch (e) {\n if (window.afLogger) {\n afLogger.logError('Aflog command queue error: ' + e);\n }\n }\n }\n }\n };\n\n return queue;\n})();\n\nAflog.Logger =\n Aflog.Logger ||\n (function () {\n var BEACON_URL = 'https://pixels.afcdn.com/logpix.php'; // Logging beacon URL for all Unify sites\n var LEGACY_ERROR_PIXEL_PATH = '/reloaded/errpix.php'; // Legacy pixel (PHP stats&logs)\n\n var CHANNEL = 'JS Logger';\n\n var EXTERNAL_DOMAINS_REGEXP =\n /onmeda|netmums|itsrosy|livingly|lonny|mabelandmoxie|stylebistro|zimbio|lesnumeriques|cnetfrance|beaute-test|gamekult|zdnet|programmez|paroledemamans|avisdemamans|paroledesagesfemmes/i;\n var EXTERNAL_DOMAINS_REGEXP_LEGACY = /doctissimo/i;\n\n var SESSIONS_SERVICE_NAME = 'session'; // Service name used in dataviz tool\n var SESSIONS_SAMPLE_RATE = 10; // In percent of all events, set false to disable sampling and log everything\n\n var ERRORS_SERVICE_NAME = 'statslogs'; // Service name used in dataviz tool\n var ERRORS_SAMPLE_RATE = 10; // Default error rate, in percent of all JS errors\n\n var EVENTS_SAMPLE_RATE = 100; // Default sample rate, in percent of all JS events\n\n // Cloud Functions + BigQuery logging\n var REALTIME_SAMPLE_RATE = 0;\n var REALTIME_ENDPOINT =\n 'https://europe-west1-realtime-logging-228816.cloudfunctions.net/realtime-logs';\n var REALTIME_MAXQUEUE = 50;\n var REALTIME_TIMEOUT = 10000; // ms\n\n // TODO: move to HB logger!\n var REALTIME_LOGGING_HEADER_BIDDING_MAPPING = {\n // GLOBAL data\n content_type: 'datalayer.pageInfo.contentType',\n site: 'datalayer.siteInfo.platform',\n segment: 'datalayer.userInfo.segment',\n device: 'datalayer.userInfo.device',\n browser: '#UA_BROWSER#',\n browser_version: '#UA_BROWSER_VER#',\n os: '#UA_OS#',\n os_version: '#UA_OS_VER#',\n\n // HB Data\n account: 'headerBidding.account',\n adserver: 'headerBidding.adserver',\n bidder: 'headerBidding.bidder',\n cpm: 'headerBidding.cpm',\n format: 'headerBidding.format',\n size: 'headerBidding.size',\n target: 'headerBidding.target',\n\n // New Prebid Fields\n ad_unit_path: 'headerBidding.ad_unit_path',\n line_item_id: 'headerBidding.line_item_id',\n campaign_id: 'headerBidding.campaign_id',\n creative_id: 'headerBidding.creative_id'\n };\n\n var logger = function (options) {\n this.init(options);\n };\n\n let sessionDataDisabled;\n\n logger.prototype = {\n verbose: {},\n context: {},\n\n init: function (options) {\n // Init datalayer if any, otherwise try to fallback to Unify global datalayer\n this.datalayer =\n options && options.datalayer\n ? options.datalayer\n : window.af_dataLayer\n ? af_dataLayer[0]\n : null;\n\n sessionDataDisabled = options ? options.disableSessionData : false;\n\n this.initCommandQueue();\n this.initContext(options);\n this.initSessionsLogger();\n\n window.onbeforeunload = function () {\n this.sendLogsToBigQuery();\n return;\n }.bind(this);\n },\n\n // Replace command queue array with function calls\n initCommandQueue: function () {\n Aflog.cmd = new Aflog.Queue(Aflog.cmd);\n },\n\n initContext: function (options) {\n // Init global context if available in options\n if (options && options.context) {\n this.context = options.context;\n }\n\n // Retrieve basic informations about user network\n var connection = navigator.connection || {};\n this.context.network = {\n downlink: connection.downlink,\n effectiveType: connection.effectiveType,\n rtt: connection.rtt,\n saveData: connection.saveData\n };\n\n // Retrieve basic informations about browser & OS\n var bowser = window.bowser;\n if (!bowser) {\n return;\n }\n\n this.context.browser = getBowserContext(bowser);\n\n // TODO: useless, check with money team to remove it\n this.realtimeLoggingPlaceholders = {\n '#UA_BROWSER#': this.context.browser.name,\n '#UA_BROWSER_VER#': this.context.browser.version,\n '#UA_OS#': this.context.browser.osName,\n '#UA_OS_VER#': this.context.browser.osVersion\n };\n\n /***\n * @param d Bowser informations\n * @return Context informations from Bowser\n */\n function getBowserContext(d) {\n if (!d && !d.name && !d.browser) {\n console.error(\n '[Analytics] [VIDEO] Bowser package is not loaded !!'\n );\n return;\n }\n\n const browserInformations = {\n name: d.name || d.browser?.name,\n version: d.version || d.browser?.version\n };\n\n const osInformations = {\n osName: d.osname || d.os?.name,\n osVersion: d.osversion || d.os?.version\n };\n\n return {\n ...browserInformations,\n ...osInformations\n };\n }\n },\n addContext: function (data) {\n // In case Bowser is from NPM (Videoplayer)\n if (!this.context.browser) {\n // Reinit context as this script is IIFE so exectuted at the import time before bowser is executed\n this.initContext();\n }\n\n data = data || {};\n data.datalayer = data.datalayer || this.getFilteredDatalayer();\n data.session =\n data.session || !sessionDataDisabled\n ? this.getSessionData()\n : undefined;\n data.browser = this.context.browser;\n data.network = this.context.network;\n\n return data;\n },\n\n setVerbose: function (service, enabled) {\n if (!service) {\n this.logError('Failed activating verbose - missing service name');\n return;\n }\n\n var key = service.toLowerCase() + '_verbose';\n this.verbose[service] = enabled || this.getConfig(key) ? '1' : '0';\n localStorage.setItem(key, this.verbose[service]);\n },\n\n setDataLayer: function (datalayer) {\n this.datalayer = datalayer;\n },\n\n logConsole: function (logs, format, service, error) {\n if (!window.console) {\n return;\n }\n\n // Only display console logs when verbose mode is enable for current service\n if (service && !this.getConfig(service.toLowerCase() + '_verbose')) {\n return;\n }\n\n // Adjust display format according to log type\n format = format || 'log';\n if (typeof logs === 'object' && !Array.isArray(logs)) {\n format = 'table';\n } else if (service) {\n logs = [].concat('[' + service + '] ', logs);\n }\n\n // Log in console\n if (format === 'table') {\n console.table(logs);\n } else if (format === 'count') {\n console.count(logs);\n } else if (format === 'error' && error) {\n console.error(error);\n } else {\n console[format].apply(console, [].concat(logs));\n }\n },\n\n logError: function (message, pool, consoleOnly, data, error) {\n // Classic log in console\n // TODO: replace with custom decorate() function\n var prefix = pool ? '[' + pool + '] ' : '';\n\n this.logConsole(prefix + message, 'error', undefined, error);\n\n // Sampling to reduce costs\n var sampleRate =\n data && data.sampleRate !== undefined\n ? data.sampleRate\n : ERRORS_SAMPLE_RATE;\n if (\n consoleOnly ||\n (sampleRate && sampleRate < Math.floor(Math.random() * 100))\n ) {\n return;\n }\n\n // Add useful informations to error logs\n var data = data || {};\n data.pool = pool || 'JS';\n data.coef = Math.floor(100 / sampleRate); // Multiplier, used for dataviz tool\n data.revision = this.context.revision || 'N/A';\n data.stacktrace = data.stacktrace || 'N/A';\n data = this.addContext(data);\n\n // Send log to legacy stats&logs pixel (old way)\n // TODO: remove and log in stats&logs via the new pixel\n var reversedMessage = message.split('').reverse().join(''); // Prevent from being catched by SQL anti-injection\n var stackMessage = data.stacktrace.split('').reverse().join(''); // Prevent from being catched by SQL anti-injection\n var url =\n this.getLogPixelDomain() +\n LEGACY_ERROR_PIXEL_PATH +\n '?s=' +\n data.coef + // sampling\n '&d=' +\n encodeURIComponent(reversedMessage) +\n '&st=' +\n encodeURIComponent(stackMessage) +\n '&t=' +\n Math.round(Math.random() * 99999) + // random timestamp to prevent browser caching\n (pool ? '&c=' + encodeURIComponent(data.pool) : '');\n this.sendBeacon(url);\n\n // Send log to global pixel\n this.sendLogToPixel(ERRORS_SERVICE_NAME, message, data);\n },\n logErrorWithContext: function (message, pool, data) {\n this.logError(message, pool, false, data);\n },\n\n logEvent: function (service, message, data) {\n if (!service) {\n this.logError('Log event without specifying service');\n }\n\n // Add context informations to event logs\n data = data || {};\n data = this.addContext(data);\n\n // Add multiplier coef, for proper dataviz\n var sampleRate =\n data.sampleRate !== undefined ? data.sampleRate : EVENTS_SAMPLE_RATE;\n data.coef = Math.floor(100 / sampleRate);\n\n // Always log events in console for debugging\n this.logConsole([message, data], 'log', service);\n\n // Send beacon to logging pixel endpoint with sampling, to reduce costs\n var isSampled =\n (data && data.sampled) ||\n Math.floor(Math.random() * 100) > EVENTS_SAMPLE_RATE;\n if (!isSampled) {\n this.sendLogToPixel(service, message, data);\n }\n },\n\n // Format and send logs to the queue\n // TODO: mutualize with logEvent and add a \"sync\" flag to handle bulk mode\n logAnalytics: function (service, logs, applySampling) {\n // Arrify logs\n if (!(logs instanceof Array)) {\n logs = [logs];\n }\n\n if (logs.length < 1) {\n return;\n }\n\n var datalayer = this.getFilteredDatalayer();\n var sessionData = !sessionDataDisabled\n ? this.getSessionData()\n : undefined;\n\n for (var i = 0, l = logs.length; i < l; i++) {\n logs[i].sessionData = sessionData;\n logs[i].datalayer = datalayer;\n logs[i].url = window.location.href;\n }\n\n this.addLogsToQueue(service, logs, applySampling);\n },\n\n /*\n * Gets the current data for the current session for the user\n */\n getSessionData: function () {\n if (!window.afSession) {\n this.logError('Failed retrieving session data');\n return;\n }\n\n return {\n visitor: afSession.getVisitorId(),\n session: afSession.getSessionId(),\n pageview: afSession.getPageviewId(),\n wave: afSession.getWaveId(),\n rank: afSession.getRankId()\n };\n },\n\n getFilteredDatalayer: function () {\n // Fallback for sites without datalayer\n if (!this.datalayer) {\n return {\n siteInfo: {\n platform: document.domain.replace('www.', '').replace('m.', '')\n }\n };\n }\n\n var filteredDatalayer = {};\n if (this.datalayer.userInfo || this.datalayer.user) {\n var key = this.datalayer.userInfo ? 'userInfo' : 'user';\n\n filteredDatalayer.userInfo = {\n du: this.datalayer[key].du || this.datalayer[key].dom,\n device: this.datalayer[key].device,\n adblocker: this.datalayer[key].adblocker ? true : false,\n screenResolution: this.datalayer[key].screenResolution,\n segment: this.datalayer[key].segment\n };\n filteredDatalayer.vuid =\n this.datalayer[key].vuid || this.datalayer[key].id;\n }\n if (\n this.datalayer.pageInfo ||\n (this.datalayer.page && this.datalayer.page)\n ) {\n var key = this.datalayer.userInfo ? 'pageInfo' : 'page';\n\n filteredDatalayer[key] = {\n version: this.datalayer[key].version || null,\n contentType:\n this.datalayer[key].contentType || this.datalayer.content.type,\n section: this.datalayer[key].section,\n subsection:\n this.datalayer[key].subsection || this.datalayer[key].subSection,\n tag: this.datalayer[key].tag || this.datalayer[key].mainTag,\n category: this.datalayer[key].category || null,\n adstack: this.datalayer[key].adstack || null\n };\n }\n if (this.datalayer.campaignInfo || this.datalayer.campaignInfo) {\n var key = this.datalayer.userInfo ? 'campaignInfo' : 'utm';\n\n filteredDatalayer.campaignInfo = {\n utmSource:\n this.datalayer[key].utmSource || this.datalayer[key].source,\n utmCampaign:\n this.datalayer[key].utmCampaign || this.datalayer[key].campaign,\n utmMedium:\n this.datalayer[key].utmMedium || this.datalayer[key].medium,\n paid:\n this.datalayer[key].paid ||\n ['cpc', 'cpc-vertical', 'cpc-horizontal'].includes(\n this.datalayer[key].medium\n )\n };\n }\n if (this.datalayer.siteInfo || this.datalayer.site) {\n var key = this.datalayer.siteInfo ? 'siteInfo' : 'site';\n\n var isMobile = null;\n if (this.datalayer[key].isMobile !== 'undefined') {\n isMobile = this.datalayer[key].isMobile;\n } else if (filteredDatalayer.userInfo) {\n isMobile = filteredDatalayer.userInfo !== 'desktop' ? 1 : 0;\n }\n\n filteredDatalayer.siteInfo = {\n platform: this.datalayer[key].platform,\n isMobile: isMobile\n };\n }\n\n return filteredDatalayer;\n },\n\n // === COMMON LOGGER FOR SESSIONS ===\n\n initSessionsLogger: function () {\n // Only activate on sites with PubSub lib\n if (!window.PubSub) {\n return;\n }\n\n var that = this;\n\n // Send logs on each pageview ..\n PubSub.subscribe('datalayer.ready', function () {\n that.logSessions();\n });\n\n // .. and also each AJAX pageview (albums, games, etc.)\n PubSub.subscribe('tracking.call', function () {\n that.logSessions();\n });\n },\n\n logSessions: function () {\n if (\n SESSIONS_SAMPLE_RATE &&\n Math.floor(Math.random() * 100) > SESSIONS_SAMPLE_RATE\n ) {\n return;\n }\n\n this.logEvent(SESSIONS_SERVICE_NAME, 'pageview');\n },\n\n // === REAL-TIME LOGGING with Unify pixel ===\n\n sendLogToPixel: function (service, message, data) {\n var payload = JSON.stringify({\n service_name: service,\n channel: CHANNEL,\n message: message,\n data: data\n });\n this.sendBeacon(BEACON_URL, payload);\n },\n\n getLogPixelDomain: function () {\n var domain = location.hostname;\n\n // Remove subdomain if any\n var hostnameArr = location.hostname.split('.');\n if (hostnameArr.length > 2) {\n hostnameArr.shift();\n domain = hostnameArr.join('.');\n }\n\n // Add subdomain for log pixel\n if (EXTERNAL_DOMAINS_REGEXP.test(location.hostname)) {\n domain = 'https://aufeminin.' + domain;\n } else if (EXTERNAL_DOMAINS_REGEXP_LEGACY.test(location.hostname)) {\n domain = 'https://dfp.' + domain; // TODO: replace with standard domain name (used only by Doctissimo)\n } else if (location.hostname.indexOf('local.') >= 0) {\n domain = 'https://local.' + domain;\n } else {\n domain = 'https://www.' + domain;\n }\n\n return domain;\n },\n\n // === REAL-TIME LOGGING with Google Cloud Functions + BigQuery ===\n\n realtimeLogs: {},\n realtimeTimer: null,\n realtimeLogTime: null,\n realtimeLoggingMapping: {\n HEADER_BIDDING: REALTIME_LOGGING_HEADER_BIDDING_MAPPING,\n HEADER_BIDDING_BOOKED: REALTIME_LOGGING_HEADER_BIDDING_MAPPING,\n HEADER_BIDDING_RENDER: REALTIME_LOGGING_HEADER_BIDDING_MAPPING\n },\n\n addLogsToQueue: function (service, logs, applySampling) {\n // Sampling to reduce costs\n if (\n applySampling &&\n REALTIME_SAMPLE_RATE &&\n Math.floor(Math.random() * 100) > REALTIME_SAMPLE_RATE\n ) {\n return;\n }\n\n for (var i = 0, l = logs.length; i < l; i++) {\n var formattedLog = this.getFormattedRealtimeLog(service, logs[i]);\n if (typeof formattedLog !== 'undefined') {\n if (!this.realtimeLogs.hasOwnProperty(service)) {\n this.realtimeLogs[service] = [];\n }\n this.realtimeLogs[service].push(formattedLog);\n }\n }\n\n var nbLogs = 0;\n for (var type in this.realtimeLogs) {\n nbLogs += this.realtimeLogs[type].length;\n }\n\n if (nbLogs > REALTIME_MAXQUEUE) {\n this.sendLogsToBigQuery();\n } else {\n var that = this;\n this.realtimeTimer = window.setTimeout(function () {\n that.sendLogsToBigQuery();\n }, REALTIME_TIMEOUT);\n }\n },\n\n // Pyramid of doom spotted!\n // TODO: rework to avoid nested if statements\n getFormattedRealtimeLog: function (service, log) {\n var formattedLog = {};\n\n if (this.realtimeLoggingMapping.hasOwnProperty(service)) {\n var mapping = this.realtimeLoggingMapping[service];\n\n for (var key in mapping) {\n if (mapping.hasOwnProperty(key)) {\n var value = mapping[key];\n if (this.realtimeLoggingPlaceholders.hasOwnProperty(value)) {\n formattedLog[key] = this.realtimeLoggingPlaceholders[value];\n } else {\n var path = value.split('.');\n for (var i = 0; i < path.length; i++) {\n if (\n formattedLog.hasOwnProperty(key) &&\n formattedLog[key].hasOwnProperty(path[i])\n ) {\n formattedLog[key] = formattedLog[key][path[i]];\n } else if (\n !formattedLog.hasOwnProperty(key) &&\n log.hasOwnProperty(path[i])\n ) {\n formattedLog[key] = log[path[i]];\n } else {\n formattedLog[key] = null;\n break;\n }\n }\n }\n }\n }\n } else {\n return;\n }\n\n return formattedLog;\n },\n\n sendLogsToBigQuery: function () {\n var data = [];\n\n for (var service in this.realtimeLogs) {\n if (this.realtimeLogs[service].length > 0) {\n data.push({\n logtype: service,\n logs: this.realtimeLogs[service]\n });\n }\n }\n\n this.realtimeLogs = {};\n window.clearTimeout(this.realtimeTimer);\n\n if (data.length > 0) {\n this.logConsole(['real-time bulk logging', data], '', 'realtime');\n\n var headers = [{ header: 'Content-Type', value: 'application/json' }];\n\n // TODO: replace XHR request with sendBeacon (check with money team first)\n // var blob = new Blob([JSON.stringify(data)], headers);\n // return this.sendBeacon(REALTIME_ENDPOINT, blob);\n return this.sendXhrRequest('POST', REALTIME_ENDPOINT, data, headers);\n }\n },\n\n // === UTILS FUNCTIONS ===\n\n getConfig: function (key) {\n if (!this.hashs) {\n this.hashs = this.getLocationHash();\n }\n\n return (\n this.hashs[key] ||\n (window.localStorage && localStorage.getItem(key)) ||\n ''\n );\n },\n\n sendBeacon: function (url, data) {\n if (navigator.sendBeacon) {\n navigator.sendBeacon(url, data);\n } else {\n // Fallback to synchronous request for old browsers, bad because it blocks next page loading ..\n this.sendXhrRequest('POST', url, data);\n }\n },\n\n sendXhrRequest: function (method, url, payload, headers) {\n var request = window.XDomainRequest\n ? new XDomainRequest()\n : new XMLHttpRequest();\n request.open(method, url, true);\n\n if (!window.XDomainRequest && headers && headers.length) {\n for (var i = 0, l = headers.length; i < l; i++) {\n request.setRequestHeader(headers[i].header, headers[i].value);\n }\n }\n\n request.onerror = function (response) {\n this.logError('Error while sending XHR request to ' + url);\n };\n\n var body = JSON.stringify(payload);\n\n return request.send(body);\n },\n\n /*\n * List location.hash parameters into an object.\n * TODO: move to global utils object\n */\n getLocationHash: function () {\n var hashParams = {};\n var e,\n a = /\\+/g, // Regex for replacing addition symbol with a space\n r = /([^&;=]+)=?([^&;]*)/g,\n d = function (s) {\n return decodeURIComponent(s.replace(a, ' '));\n },\n q = window.location.hash.substring(1);\n\n while ((e = r.exec(q))) {\n hashParams[d(e[1])] = d(e[2]);\n }\n\n return hashParams;\n }\n };\n\n return logger;\n })();\n\nwindow.module = {};\nmodule.exports = Aflog.Logger;\nwindow.module = undefined;\n","import { PlayerPosition } from 'src/enums/player-position.enum';\nimport AfLogger from '@vendor/auf/afLogger';\nexport interface VideoLoggerOptions {\n\tcontext: VideoLoggerContext;\n}\n\ninterface VideoLoggerContext {\n\tadPlayer: any;\n\tplayer: {\n\t\tversion: string;\n\t\tname: string;\n\t\tvideoId: string;\n\t\tcontext: any;\n\t\tposition: PlayerPosition;\n\t};\n}\n\nenum VideoLogType {\n\tVIDEO_ERROR = 'VIDEO_ERROR',\n\tVIDEO_LOG = 'VIDEO_LOG'\n}\n\nconst afLogger = new AfLogger({ disableSessionData: true });\n\nexport class VideoLogger {\n\tprivate serviceName = 'video';\n\tprivate sampleRate = 10;\n\tprivate noisyErrorSampleRate = 1;\n\tprivate noisyErrors = [\n\t\t'play() can only be initiated by a user gesture',\n\t\t'The request is not allowed by the user agent',\n\t\t'The play() request was interrupted by a call to pause()',\n\t\t\"play() failed because the user didn't interact with the document first.\",\n\t\t'The operation was aborted.', // Safari error due to browser settings or unmuted autoplay\n\t\t'The operation is not supported.' // Safari error that can be caused by lot of player errors\n\t];\n\tprivate logged: Map> = new Map<\n\t\tstring,\n\t\tMap\n\t>([\n\t\t[VideoLogType.VIDEO_ERROR, new Map()],\n\t\t[VideoLogType.VIDEO_LOG, new Map()]\n\t]);\n\n\tprivate sampled = this.sampleRate < Math.floor(Math.random() * 100);\n\tprivate context: any;\n\tprivate logger: any;\n\n\tconstructor(options: VideoLoggerOptions) {\n\t\tthis.initContext(options.context);\n\t}\n\n\tsetVerbose = (isEnabled: boolean) =>\n\t\tafLogger.setVerbose(this.serviceName, isEnabled);\n\n\tlogError(message: string, category: string, data: any) {\n\t\tconst pool = `${this.serviceName} ${category ? ':' + category : ''}`;\n\n\t\t// Sampling to reduce cost & noise\n\t\tconst errorRate = this.getErrorRate(message);\n\t\tif (errorRate && Math.floor(Math.random() * 100) > errorRate) {\n\t\t\tafLogger.logConsole('[' + pool + '] ' + message, 'error');\n\t\t\treturn;\n\t\t}\n\n\t\tdata = this.addContext({ ...data, sampleRate: errorRate });\n\t\tafLogger.logErrorWithContext(message, pool, data);\n\t}\n\n\tlogEventOnce(message: string, videoData: any) {\n\t\tif (this.logged.get(VideoLogType.VIDEO_LOG)?.get(message)) return;\n\n\t\tthis.logged.get(VideoLogType.VIDEO_LOG)?.set(message, true);\n\t\tthis.logEvent(message, videoData);\n\t}\n\n\tlogEvent = (\n\t\tmessage,\n\t\tvideoData = {\n\t\t\tduration: undefined,\n\t\t\tfile: undefined,\n\t\t\tposition: undefined,\n\t\t\turl: undefined\n\t\t}\n\t) =>\n\t\tafLogger.logEvent(\n\t\t\tthis.serviceName,\n\t\t\tmessage,\n\t\t\tthis.addContext({\n\t\t\t\tsampled: this.sampled,\n\t\t\t\tsampleRate: this.sampleRate,\n\t\t\t\tvideo: {\n\t\t\t\t\tduration: videoData.duration,\n\t\t\t\t\tfile: videoData.file,\n\t\t\t\t\tposition: videoData.position,\n\t\t\t\t\turl: videoData.url\n\t\t\t\t}\n\t\t\t})\n\t\t);\n\n\tprivate initContext(context: VideoLoggerContext) {\n\t\tif (!context) return;\n\n\t\tthis.context = context;\n\t}\n\n\tprivate getErrorRate = (message) =>\n\t\tthis.noisyErrors.indexOf(message) > -1\n\t\t\t? this.noisyErrorSampleRate\n\t\t\t: this.sampleRate;\n\n\tprivate addContext = (data: any) => {\n\t\tconst result = { ...data, ...this.context };\n\t\treturn result;\n\t};\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.Tracker = window.AufVideo.Tracker || {};\nwindow.AufVideo.Tracker.VideoLogger = VideoLogger;\n","export class AufVideoUtils {\n\tpublic static addClickListener(\n\t\tcontainerId: string,\n\t\tclassNames: string[],\n\t\tcallback: (...args: any[]) => any,\n\t\toptions?: any\n\t) {\n\t\tclassNames.forEach(function (className) {\n\t\t\tconst elements = document\n\t\t\t\t.getElementById(containerId)!\n\t\t\t\t.getElementsByClassName(className);\n\n\t\t\telements[0].addEventListener('click', function (e) {\n\t\t\t\tcallback();\n\t\t\t\tif (options && options.stopPropagation) {\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tpublic static getCookieValue(cname: string): string {\n\t\tconst name = cname + '=';\n\t\tconst decodedCookie = decodeURIComponent(document.cookie);\n\t\tconst ca = decodedCookie.split(';');\n\t\tfor (let i = 0; i < ca.length; i++) {\n\t\t\tlet c = ca[i];\n\t\t\twhile (c.charAt(0) == ' ') {\n\t\t\t\tc = c.substring(1);\n\t\t\t}\n\t\t\tif (c.indexOf(name) == 0) {\n\t\t\t\treturn c.substring(name.length, c.length);\n\t\t\t}\n\t\t}\n\t\treturn '';\n\t}\n\n\tpublic static getDFPFormattedKeywords(keywords: string) {\n\t\tlet formattedKeywords = '';\n\n\t\t// First we clean keywords to be sure to respect DFP syntax\n\t\tconst cleanedKeywords = keywords\n\t\t\t.replace(/^\\W/, '') // Remove non-word character\n\t\t\t.replace(/;/g, '&') // Replace Smart keywords separator ; by &\n\t\t\t.replace(/&+/g, '&'); // Replace multiple &\n\n\t\tcleanedKeywords.split('&').forEach(function (keyValue) {\n\t\t\tconst keyValueArr = keyValue.split('=');\n\t\t\tconst key = keyValueArr[0];\n\t\t\tconst value = keyValueArr[1];\n\n\t\t\tif (!key || typeof value === 'undefined') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst keyQS = '&' + key + '=';\n\t\t\tconst keyQSPos = formattedKeywords.indexOf(keyQS);\n\n\t\t\t// Key already exists\n\t\t\tif (keyQSPos !== -1) {\n\t\t\t\tlet keyValues = formattedKeywords.substr(keyQSPos + keyQS.length);\n\n\t\t\t\t// Extract only values\n\t\t\t\tif (keyValues.indexOf('&') !== -1) {\n\t\t\t\t\tkeyValues = keyValues.substr(0, keyValues.indexOf('&'));\n\t\t\t\t}\n\n\t\t\t\t// Dedupe same values\n\t\t\t\tif (keyValues.indexOf(value) !== -1) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Add new value for the key\n\t\t\t\tformattedKeywords =\n\t\t\t\t\tformattedKeywords.substr(0, keyQSPos + keyQS.length) +\n\t\t\t\t\tvalue +\n\t\t\t\t\t',' +\n\t\t\t\t\tformattedKeywords.substr(keyQSPos + keyQS.length);\n\t\t\t} else {\n\t\t\t\tformattedKeywords += keyQS + value;\n\t\t\t}\n\t\t});\n\n\t\t// Remove first separator\n\t\tif (formattedKeywords.indexOf('&') === 0) {\n\t\t\tformattedKeywords = formattedKeywords.substr(1);\n\t\t}\n\n\t\treturn formattedKeywords;\n\t}\n\n\tpublic static throttle(\n\t\tfunc: (...args: any[]) => any,\n\t\twait: number,\n\t\toptions: { leading?: boolean; trailing?: boolean }\n\t) {\n\t\tlet context, args, result;\n\t\tlet timeout: number | null = null;\n\t\tlet previous = 0;\n\t\tif (!options) options = {};\n\t\tlet later = function () {\n\t\t\tprevious = options.leading === false ? 0 : Date.now();\n\t\t\ttimeout = null;\n\t\t\tresult = func.apply(context, args);\n\t\t\tif (!timeout) context = args = null;\n\t\t};\n\t\treturn function () {\n\t\t\tlet now = Date.now();\n\t\t\tif (!previous && options.leading === false) previous = now;\n\t\t\tlet remaining = wait - (now - previous);\n\t\t\tcontext = this;\n\t\t\targs = arguments;\n\t\t\tif (remaining <= 0 || remaining > wait) {\n\t\t\t\tif (timeout) {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\ttimeout = null;\n\t\t\t\t}\n\t\t\t\tprevious = now;\n\t\t\t\tresult = func.apply(context, args);\n\t\t\t\tif (!timeout) context = args = null;\n\t\t\t} else if (!timeout && options.trailing !== false) {\n\t\t\t\ttimeout = window.setTimeout(later, remaining);\n\t\t\t}\n\t\t\treturn result;\n\t\t};\n\t}\n\n\tpublic static isPreview() {\n\t\tconst search = window.location.search;\n\t\tconst params = search.substring(search.lastIndexOf('?') + 1).split('&');\n\n\t\treturn params.includes('preview');\n\t}\n\n\tpublic static injectScript(\n\t\td: Document,\n\t\tsrc: string,\n\t\tcb: Function,\n\t\tparams?: any[]\n\t) {\n\t\tvar script = d.createElement('script');\n\t\tscript.type = 'text/javascript';\n\t\tscript.async = true;\n\t\tscript.onload = function () {\n\t\t\t// remote script has loaded\n\t\t\tif (cb && typeof cb === 'function') {\n\t\t\t\tcb(params);\n\t\t\t}\n\t\t};\n\t\tscript.src = src;\n\t\td.getElementsByTagName('head')[0].appendChild(script);\n\t}\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.Utils = AufVideoUtils;\n","export type LogLevel = 'info' | 'debug' | 'warn' | 'error';\n\nexport class VideoConsoleLogger {\n\tconstructor() {}\n\n\t/**\n\t * Send colorized info console log\n\t *\n\t * Activate hidden logs this way: localStorage.setItem('log', JSON.stringify({videoPlayer: true}));\n\t *\n\t * @param msg {string} Message to be sent\n\t * @param hidden {boolean} - If true the message will be sent only if localStorage.logs.videoplayer is true\n\t * @param data {object} - Optional data to log\n\t */\n\tpublic info = (msg: string, data?: any, hidden: boolean = true) =>\n\t\tthis._writeLog(msg, 'info', hidden, data);\n\n\t/**\n\t * Send colorized warning console log\n\t *\n\t * Activate hidden logs this way: localStorage.setItem('log', JSON.stringify({videoPlayer: true}));\n\t *\n\t * @param msg {string} Message to be sent\n\t * @param hidden {boolean} - If true the message will be sent only if localStorage.logs.videoplayer is true\n\t * @param data {object} - Optional data to log\n\t */\n\tpublic warn = (msg: string, data?: any, hidden: boolean = true) =>\n\t\tthis._writeLog(msg, 'warn', hidden, data);\n\n\t/**\n\t * Send colorized debug console log\n\t *\n\t * Activate hidden logs this way: localStorage.setItem('log', JSON.stringify({videoPlayer: true}));\n\t *\n\t * @param msg {string} Message to be sent\n\t * @param hidden {boolean} - If true the message will be sent only if localStorage.logs.videoplayer is true\n\t * @param data {object} - Optional data to log\n\t */\n\tpublic debug = (msg: string, data?: any, hidden: boolean = true) =>\n\t\tthis._writeLog(msg, 'debug', hidden, data);\n\n\t/**\n\t * Send colorized error console log\n\t *\n\t * Activate hidden logs this way: localStorage.setItem('log', JSON.stringify({videoPlayer: true}));\n\t *\n\t * @param msg {string} Message to be sent\n\t * @param hidden {boolean} - If true the message will be sent only if localStorage.logs.videoplayer is true\n\t * @param data {object} - Optional data to log\n\t */\n\tpublic error = (msg: string, data?: any, hidden: boolean = true) =>\n\t\tthis._writeLog(msg, 'error', hidden, data);\n\n\t/**\n\t * Send colorized console logs\n\t *\n\t * Activate hidden logs this way: localStorage.setItem('log', JSON.stringify({videoPlayer: true}));\n\t *\n\t * @param msg {string} Message to be sent\n\t * @param level {LogLevel} Log level\n\t * @param hidden {boolean} - If true the message will be sent only if localStorage.logs.videoplayer is true\n\t * @param data {object} - Optional data to log\n\t */\n\tprivate _writeLog(\n\t\tmsg: string,\n\t\tlevel: LogLevel = 'info',\n\t\thidden: boolean = true,\n\t\tdata?: any\n\t): Function {\n\t\tif (\n\t\t\t(hidden && !localStorage.log) ||\n\t\t\t!JSON.parse(localStorage.log).videoPlayer\n\t\t) {\n\t\t\treturn () => {};\n\t\t}\n\n\t\tconst getColorString = (level: LogLevel): string => {\n\t\t\tlet frontColor: string;\n\t\t\tlet backgroundColor: string;\n\n\t\t\tswitch (level) {\n\t\t\t\tcase 'info':\n\t\t\t\t\t{\n\t\t\t\t\t\tfrontColor = 'yellow';\n\t\t\t\t\t\tbackgroundColor = 'Purple';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'debug':\n\t\t\t\t\t{\n\t\t\t\t\t\tfrontColor = 'orange';\n\t\t\t\t\t\tbackgroundColor = 'Purple';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'error':\n\t\t\t\t\t{\n\t\t\t\t\t\tfrontColor = 'red';\n\t\t\t\t\t\tbackgroundColor = 'Purple';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\t{\n\t\t\t\t\t\tfrontColor = 'white';\n\t\t\t\t\t\tbackgroundColor = 'Purple';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn `color: ${frontColor}; background: ${backgroundColor};`;\n\t\t};\n\n\t\tconst color = getColorString(level);\n\t\tmsg = `%c( Video Player - ${level} )%c ${msg}`;\n\n\t\tconst fn =\n\t\t\tlevel === 'error'\n\t\t\t\t? console.error.bind(window.console, msg, color, data)\n\t\t\t\t: console.log.bind(window.console, msg, color, data);\n\n\t\treturn fn;\n\t}\n}\n","export enum PublishableVideoPlayerEvents {\n\t// Global\n\tEND = 'video.player.end',\n\tPAUSE = 'video.player.pause',\n\tPLAY = 'video.player.play',\n\tREADY = 'video.player.ready',\n\tSEEKING = 'video.player.seek',\n\tSEEKED = 'video.player.seeked',\n\tSTART = 'video.player.start',\n\tUNMUTE = 'video.player.unmute',\n\tINITIALIZATION_ERROR = 'video.player.initialization.error',\n\tBEFORE_COMPLETE = 'video.player.beforeComplete',\n\tBEFORE_PLAY = 'video.player.beforePlay',\n\tCONTROLS_CHANGE = 'video.player.controlschange',\n\tFULLSCREEN_CHANGE = 'video.player.fullscreenchange',\n\tPLAYBACK_READY = 'video.player.playback_ready',\n\tVIDEO_CHANGE = 'video.player.videochange',\n\tVOLUME_CHANGE = 'video.player.volumechange',\n\tCRITICAL_PATH_READY = 'video.player.dailymotion-embed.criticalready',\n\tDAILYMOTION_EMBED_LAZY_READY = 'video.player.dailymotion-embed.lazy-ready'\n}\n\nexport enum PublishableVideoContentEvents {\n\tTIME_UPDATE = 'video.player.inProgress',\n\tVIDEO_END = 'video.player.complete',\n\tDURATION_CHANGE = 'video.player.content.duration_change',\n\tLOADED_METADATA = 'video.player.content.loaded_metadata',\n\tSUBTITLE_CHANGE = 'video.player.content.subtitle_change',\n\tSUBTITLES_AVAILABLE = 'video.player.content.subtitles_available',\n\tPLAYBACK_RESOLUTION = 'video.player.content.playback_resolution',\n\tPLAYING = 'video.player.content.playing',\n\tQUALITIES_AVAILABLE = 'video.player.content.qualities_available',\n\tQUALITIES_CHANGED = 'video.player.content.qualities_changed',\n\tPROGRESS = 'video.player.content.progress',\n\tVIDEO_START = 'video.player.content.start',\n\tWAITING = 'video.player.content.waiting'\n}\n\nexport enum PublishableVideoUserEvents {\n\tTOGGLE_PLAY_PAUSE = 'video.player.user.togglePlayPause'\n}\n\nexport enum PublishableVideoLogEvents {\n\tERROR = 'video.player.log.error'\n}\n\nexport enum PublishableVideoAdEvents {\n\tAD_CLICK = 'video.ad.click',\n\tAD_COMPANIONS = 'video.ad.companions',\n\tAD_END = 'video.ad.complete',\n\tAD_PAUSE = 'video.ad.pause',\n\tAD_PLAY = 'video.ad.play',\n\tAD_READY = 'video.ad.ready',\n\tAD_START = 'video.ad.start',\n\tAD_TAG_READY = 'video.ad.tag.ready',\n\tAD_TIMEUPDATE = 'video.ad.time_update',\n\tAD_IMPRESSION = 'video.ad.impression',\n\tAD_REQUEST = 'video.ad.request',\n\tAD_BLOCKED = 'video.ad.block',\n\tAD_RESUME = 'video.ad.resume',\n\tAD_LOADED = 'video.ad.loaded',\n\tAD_CONTENT_RESUME = 'video.ad.contentresume',\n\tAD_BID_FOUND = 'video.ad.bidfound',\n\tAD_CANCEL = 'video.ad.cancel',\n\tAD_UNFILLED = 'video.ad.unfilled',\n\tAD_DURATIONCHANGE = 'video.ad.duration_change',\n\tHEAVY_ADS = 'video.ad.heavy_ad_error'\n}\n\nexport enum PublishableVideoStoreEvents {\n\tADD_INSTANCE = 'video.store.addInstance'\n}\n\nexport enum PublishableVideoStickyEvents {\n\tSTICKY_READY = 'video.sticky.ready',\n\tSTICKY_CONTENT_START = 'video.sticky.content.start',\n\tSTICK = 'video.player.sticky.stick',\n\tUNSTICK = 'video.player.sticky.unstick',\n\tSTICKED = 'video.player.sticky.sticked',\n\tUNSTICKED = 'video.player.sticky.unsticked',\n\tSCROLL_TO_PLAYER = 'video.player.sticky.gotoplayer',\n\tCLOSE = 'video.player.sticky.close'\n}\n\n(window as any).PublishableVideoPlayerEvents = PublishableVideoPlayerEvents;\n(window as any).PublishableVideoContentEvents = PublishableVideoContentEvents;\n(window as any).PublishableVideoUserEvents = PublishableVideoUserEvents;\n(window as any).PublishableVideoLogEvents = PublishableVideoLogEvents;\n(window as any).PublishableVideoAdEvents = PublishableVideoAdEvents;\n(window as any).PublishableVideoStoreEvents = PublishableVideoStoreEvents;\n(window as any).PublishableVideoStickyEvents = PublishableVideoStickyEvents;\n","export enum VideoPlugins {\n AUTOPLAY = 'Autoplay',\n STICKY = 'Sticky',\n ANALYTICS = 'Analytics',\n DEBUG = 'Debug'\n}\n","export enum AspectRatio {\n Ratio_16_9 = '16-9'\n}\n","export enum DailymotionInternalEvents {\n\tAPI_READY = 'apiready',\n\tCONTROLS_CHANGE = 'controlschange',\n\tSTART = 'start',\n\tEND = 'end',\n\tENDED = 'ended',\n\tERROR = 'error',\n\tFULLSCREEN_CHANGE = 'fullscreenchange',\n\tPLAYBACK_READY = 'playback_ready',\n\tSEEKING = 'seeking',\n\tSEEKED = 'seeked',\n\tVIDEO_CHANGE = 'videochange',\n\tVOLUME_CHANGE = 'volumechange',\n VIDEO_START = 'video_start',\n VIDEO_END = 'video_end',\n PAUSE = 'pause',\n PLAY = 'play',\n PLAYING = 'playing',\n DURATION_CHANGE = 'durationchange',\n LOADED_METADATA = 'loadedmetadata',\n WAITING = 'waiting',\n SUBTITLE_CHANGE = 'subtitlechange',\n SUBTITLES_AVAILABLE = 'subtitlesavailable',\n QUALITIES_AVAILABLE = 'qualitiesavailable',\n QUALITIES_CHANGED = 'qualitieschanged',\n TIMEUPDATE = 'timeupdate',\n PROGRESS = 'progress',\n PLAYBACK_RESOLUTION = 'playback_resolution',\n AD_START = 'ad_start',\n AD_END = 'ad_end',\n AD_PAUSE = 'ad_pause',\n AD_PLAY = 'ad_play',\n AD_TIMEUPDATE = 'ad_timeupdate',\n AD_COMPANIONS = 'ad_companions',\n AD_CLICK = 'ad_click',\n AD_LOADED = 'ad_loaded',\n AD_IMPRESSION = 'ad_impression',\n AD_BUFFERSTART = 'ad_bufferStart',\n AD_BUFFERFINISH = 'ad_bufferFinish',\n\tPLAYER_HEAVYADSINTERVENTION = 'PLAYER_HEAVYADSINTERVENTION' // https://faq.dailymotion.com/hc/fr/articles/4414693854738-G%C3%A9rer-l-int%C3%A9gration-du-player-d%C3%A9tect%C3%A9-par-Heavy-Ad\n}\n\nexport enum DailymotionEmbedInternalEvents {\n\tPLAYER_ASPECTRATIOCHANGE = 'PLAYER_ASPECTRATIOCHANGE',\n\tPLAYER_CONTROLSCHANGE = 'PLAYER_CONTROLSCHANGE',\n\tPLAYER_CRITICALPATHREADY = 'PLAYER_CRITICALPATHREADY',\n\tPLAYER_END = 'PLAYER_END',\n\tPLAYER_ERROR = 'PLAYER_ERROR',\n\tPLAYER_PIPEXPANDEDCHANGE = 'PLAYER_PIPEXPANDEDCHANGE',\n\tPLAYER_PLAYBACKPERMISSION = 'PLAYER_PLAYBACKPERMISSION',\n\tPLAYER_PRESENTATIONMODECHANGE = 'PLAYER_PRESENTATIONMODECHANGE',\n\tPLAYER_SCALEMODECHANGE = 'PLAYER_SCALEMODECHANGE',\n\tPLAYER_START = 'PLAYER_START',\n\tPLAYER_VIDEOCHANGE = 'PLAYER_VIDEOCHANGE',\n\tPLAYER_VIEWABILITYCHANGE = 'PLAYER_VIEWABILITYCHANGE',\n\tPLAYER_VOLUMECHANGE = 'PLAYER_VOLUMECHANGE',\n\tPLAYER_HEAVYADSINTERVENTION = 'PLAYER_HEAVYADSINTERVENTION',\n\tVIDEO_BUFFERING = 'VIDEO_BUFFERING',\n\tVIDEO_DURATIONCHANGE = 'VIDEO_DURATIONCHANGE',\n\tVIDEO_END = 'VIDEO_END',\n\tVIDEO_PAUSE = 'VIDEO_PAUSE',\n\tVIDEO_PLAY = 'VIDEO_PLAY',\n\tVIDEO_PLAYING = 'VIDEO_PLAYING',\n\tVIDEO_PROGRESS = 'VIDEO_PROGRESS',\n\tVIDEO_QUALITIESREADY = 'VIDEO_QUALITIESREADY',\n\tVIDEO_QUALITYCHANGE = 'VIDEO_QUALITYCHANGE',\n\tVIDEO_SEEKEND = 'VIDEO_SEEKEND',\n\tVIDEO_SEEKSTART = 'VIDEO_SEEKSTART',\n\tVIDEO_SUBTITLESCHANGE = 'VIDEO_SUBTITLESCHANGE',\n\tVIDEO_SUBTITLESREADY = 'VIDEO_SUBTITLESREADY',\n\tVIDEO_START = 'VIDEO_START',\n\tVIDEO_TIMECHANGE = 'VIDEO_TIMECHANGE',\n\tAD_COMPANIONSREADY = 'AD_COMPANIONSREADY',\n\tAD_DURATIONCHANGE = 'AD_DURATIONCHANGE',\n\tAD_END = 'AD_END',\n\tAD_IMPRESSION = 'AD_IMPRESSION',\n\tAD_LOADED = 'AD_LOADED',\n\tAD_PAUSE = 'AD_PAUSE',\n\tAD_PLAY = 'AD_PLAY',\n\tAD_START = 'AD_START',\n\tAD_TIMECHANGE = 'AD_TIMECHANGE',\n\tAD_CLICK = 'AD_CLICK'\n}\n","export enum PlayerPosition {\n ATF = 'ATF',\n MTF_CONTENT = 'MTF_CONTENT',\n BTF = 'BTF'\n}\n","export enum Players {\n\tDAILYMOTION = 'dailymotion',\n\tDAILYMOTION_EMBED = 'dailymotion-embed',\n\tJWPLAYER = 'jwplayer',\n\tVIDEOJS = 'videojs'\n}\n\n(window as any).VideoPlayers = Players;\n","/**\n * Copyright (c) 2010,2011,2012,2013,2014 Morgan Roderick http://roderick.dk\n * License: MIT - http://mrgnrdrck.mit-license.org\n *\n * https://github.com/mroderick/PubSubJS\n */\n\n(function (root, factory){\n 'use strict';\n\n var PubSub = {};\n\n if (root.PubSub) {\n PubSub = root.PubSub;\n console.warn(\"PubSub already loaded, using existing version\");\n } else {\n root.PubSub = PubSub;\n factory(PubSub);\n }\n // CommonJS and Node.js module support\n if (typeof exports === 'object'){\n if (module !== undefined && module.exports) {\n exports = module.exports = PubSub; // Node.js specific `module.exports`\n }\n exports.PubSub = PubSub; // CommonJS module 1.1.1 spec\n module.exports = exports = PubSub; // CommonJS\n }\n // AMD support\n /* eslint-disable no-undef */\n else if (typeof define === 'function' && define.amd){\n define(function() { return PubSub; });\n /* eslint-enable no-undef */\n }\n\n}(( typeof window === 'object' && window ) || this, function (PubSub){\n 'use strict';\n\n var messages = {},\n lastUid = -1,\n ALL_SUBSCRIBING_MSG = '*';\n\n function hasKeys(obj){\n var key;\n\n for (key in obj){\n if ( Object.prototype.hasOwnProperty.call(obj, key) ){\n return true;\n }\n }\n return false;\n }\n\n /**\n * Returns a function that throws the passed exception, for use as argument for setTimeout\n * @alias throwException\n * @function\n * @param { Object } ex An Error object\n */\n function throwException( ex ){\n return function reThrowException(){\n throw ex;\n };\n }\n\n function callSubscriberWithDelayedExceptions( subscriber, message, data ){\n try {\n subscriber( message, data );\n } catch( ex ){\n setTimeout( throwException( ex ), 0);\n }\n }\n\n function callSubscriberWithImmediateExceptions( subscriber, message, data ){\n subscriber( message, data );\n }\n\n function deliverMessage( originalMessage, matchedMessage, data, immediateExceptions ){\n var subscribers = messages[matchedMessage],\n callSubscriber = immediateExceptions ? callSubscriberWithImmediateExceptions : callSubscriberWithDelayedExceptions,\n s;\n\n if ( !Object.prototype.hasOwnProperty.call( messages, matchedMessage ) ) {\n return;\n }\n\n for (s in subscribers){\n if ( Object.prototype.hasOwnProperty.call(subscribers, s)){\n callSubscriber( subscribers[s], originalMessage, data );\n }\n }\n }\n\n function createDeliveryFunction( message, data, immediateExceptions ){\n return function deliverNamespaced(){\n var topic = String( message ),\n position = topic.lastIndexOf( '.' );\n\n // deliver the message as it is now\n deliverMessage(message, message, data, immediateExceptions);\n\n // trim the hierarchy and deliver message to each level\n while( position !== -1 ){\n topic = topic.substr( 0, position );\n position = topic.lastIndexOf('.');\n deliverMessage( message, topic, data, immediateExceptions );\n }\n\n deliverMessage(message, ALL_SUBSCRIBING_MSG, data, immediateExceptions);\n };\n }\n\n function hasDirectSubscribersFor( message ) {\n var topic = String( message ),\n found = Boolean(Object.prototype.hasOwnProperty.call( messages, topic ) && hasKeys(messages[topic]));\n\n return found;\n }\n\n function messageHasSubscribers( message ){\n var topic = String( message ),\n found = hasDirectSubscribersFor(topic) || hasDirectSubscribersFor(ALL_SUBSCRIBING_MSG),\n position = topic.lastIndexOf( '.' );\n\n while ( !found && position !== -1 ){\n topic = topic.substr( 0, position );\n position = topic.lastIndexOf( '.' );\n found = hasDirectSubscribersFor(topic);\n }\n\n return found;\n }\n\n function publish( message, data, sync, immediateExceptions ){\n message = (typeof message === 'symbol') ? message.toString() : message;\n\n var deliver = createDeliveryFunction( message, data, immediateExceptions ),\n hasSubscribers = messageHasSubscribers( message );\n\n if ( !hasSubscribers ){\n return false;\n }\n\n if ( sync === true ){\n deliver();\n } else {\n setTimeout( deliver, 0 );\n }\n return true;\n }\n\n /**\n * Publishes the message, passing the data to it's subscribers\n * @function\n * @alias publish\n * @param { String } message The message to publish\n * @param {} data The data to pass to subscribers\n * @return { Boolean }\n */\n PubSub.publish = function( message, data ){\n return publish( message, data, false, PubSub.immediateExceptions );\n };\n\n /**\n * Publishes the message synchronously, passing the data to it's subscribers\n * @function\n * @alias publishSync\n * @param { String } message The message to publish\n * @param {} data The data to pass to subscribers\n * @return { Boolean }\n */\n PubSub.publishSync = function( message, data ){\n return publish( message, data, true, PubSub.immediateExceptions );\n };\n\n /**\n * Subscribes the passed function to the passed message. Every returned token is unique and should be stored if you need to unsubscribe\n * @function\n * @alias subscribe\n * @param { String } message The message to subscribe to\n * @param { Function } func The function to call when a new message is published\n * @return { String }\n */\n PubSub.subscribe = function( message, func ){\n if ( typeof func !== 'function'){\n return false;\n }\n\n message = (typeof message === 'symbol') ? message.toString() : message;\n\n // message is not registered yet\n if ( !Object.prototype.hasOwnProperty.call( messages, message ) ){\n messages[message] = {};\n }\n\n // forcing token as String, to allow for future expansions without breaking usage\n // and allow for easy use as key names for the 'messages' object\n var token = 'uid_' + String(++lastUid);\n messages[message][token] = func;\n\n // return token for unsubscribing\n return token;\n };\n\n PubSub.subscribeAll = function( func ){\n return PubSub.subscribe(ALL_SUBSCRIBING_MSG, func);\n };\n\n /**\n * Subscribes the passed function to the passed message once\n * @function\n * @alias subscribeOnce\n * @param { String } message The message to subscribe to\n * @param { Function } func The function to call when a new message is published\n * @return { PubSub }\n */\n PubSub.subscribeOnce = function( message, func ){\n var token = PubSub.subscribe( message, function(){\n // before func apply, unsubscribe message\n PubSub.unsubscribe( token );\n func.apply( this, arguments );\n });\n return PubSub;\n };\n\n /**\n * Clears all subscriptions\n * @function\n * @public\n * @alias clearAllSubscriptions\n */\n PubSub.clearAllSubscriptions = function clearAllSubscriptions(){\n messages = {};\n };\n\n /**\n * Clear subscriptions by the topic\n * @function\n * @public\n * @alias clearAllSubscriptions\n * @return { int }\n */\n PubSub.clearSubscriptions = function clearSubscriptions(topic){\n var m;\n for (m in messages){\n if (Object.prototype.hasOwnProperty.call(messages, m) && m.indexOf(topic) === 0){\n delete messages[m];\n }\n }\n };\n\n /**\n Count subscriptions by the topic\n * @function\n * @public\n * @alias countSubscriptions\n * @return { Array }\n */\n PubSub.countSubscriptions = function countSubscriptions(topic){\n var m;\n // eslint-disable-next-line no-unused-vars\n var token;\n var count = 0;\n for (m in messages) {\n if (Object.prototype.hasOwnProperty.call(messages, m) && m.indexOf(topic) === 0) {\n for (token in messages[m]) {\n count++;\n }\n break;\n }\n }\n return count;\n };\n\n\n /**\n Gets subscriptions by the topic\n * @function\n * @public\n * @alias getSubscriptions\n */\n PubSub.getSubscriptions = function getSubscriptions(topic){\n var m;\n var list = [];\n for (m in messages){\n if (Object.prototype.hasOwnProperty.call(messages, m) && m.indexOf(topic) === 0){\n list.push(m);\n }\n }\n return list;\n };\n\n /**\n * Removes subscriptions\n *\n * - When passed a token, removes a specific subscription.\n *\n\t * - When passed a function, removes all subscriptions for that function\n *\n\t * - When passed a topic, removes all subscriptions for that topic (hierarchy)\n * @function\n * @public\n * @alias subscribeOnce\n * @param { String | Function } value A token, function or topic to unsubscribe from\n * @example // Unsubscribing with a token\n * var token = PubSub.subscribe('mytopic', myFunc);\n * PubSub.unsubscribe(token);\n * @example // Unsubscribing with a function\n * PubSub.unsubscribe(myFunc);\n * @example // Unsubscribing from a topic\n * PubSub.unsubscribe('mytopic');\n */\n PubSub.unsubscribe = function(value){\n var descendantTopicExists = function(topic) {\n var m;\n for ( m in messages ){\n if ( Object.prototype.hasOwnProperty.call(messages, m) && m.indexOf(topic) === 0 ){\n // a descendant of the topic exists:\n return true;\n }\n }\n\n return false;\n },\n isTopic = typeof value === 'string' && ( Object.prototype.hasOwnProperty.call(messages, value) || descendantTopicExists(value) ),\n isToken = !isTopic && typeof value === 'string',\n isFunction = typeof value === 'function',\n result = false,\n m, message, t;\n\n if (isTopic){\n PubSub.clearSubscriptions(value);\n return;\n }\n\n for ( m in messages ){\n if ( Object.prototype.hasOwnProperty.call( messages, m ) ){\n message = messages[m];\n\n if ( isToken && message[value] ){\n delete message[value];\n result = value;\n // tokens are unique, so we can just stop here\n break;\n }\n\n if (isFunction) {\n for ( t in message ){\n if (Object.prototype.hasOwnProperty.call(message, t) && message[t] === value){\n delete message[t];\n result = true;\n }\n }\n }\n }\n }\n\n return result;\n };\n}));\n","import {\n\tPublishableVideoAdEvents,\n\tPublishableVideoContentEvents,\n\tPublishableVideoLogEvents,\n\tPublishableVideoPlayerEvents,\n\tPublishableVideoStickyEvents\n} from '../../enums/publishable-events.enum';\nimport { ListenerAction } from '../../interfaces/listener-action';\nimport { Store } from '../../store';\nimport PubSub from 'pubsub-js';\nimport { Players } from 'src/enums';\nimport { DailymotionEmbedPlayer } from 'src/players/dailymotion-embed';\n\nexport interface AnalyticsPluginOptions {\n\tstore: Store;\n}\n\nexport class AnalyticsPlugin {\n\tpublic name = 'analytics';\n\tprivate _store: Store;\n\tprivate _events: Map> = new Map<\n\t\tstring,\n\t\tMap\n\t>();\n\n\tprivate _playerListenersActions: ListenerAction[] = [\n\t\t{\n\t\t\tmessage: PublishableVideoLogEvents.ERROR,\n\t\t\tactionFn: (msg, data) =>\n\t\t\t\tthis._logError(data.message, data.category, data.id)\n\t\t},\n\t\t{\n\t\t\tmessage: 'video.player.log.event',\n\t\t\tactionFn: (msg, data) => {\n\t\t\t\tvar event = data.event;\n\t\t\t\tdelete data.event;\n\t\t\t\tthis._logEventOnce(event, data);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.READY,\n\t\t\tactionFn: (msg, data) => this._logEventOnce('player ready', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.START,\n\t\t\tactionFn: (msg, data) => {\n\t\t\t\tthis._logEventOnce('player start', data);\n\t\t\t\tthis._logEventOnce('ad opportunities', data); // TODO: remove when NR video dashboard has been migrated to the other event\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.PLAY,\n\t\t\tactionFn: (msg, data) => this._logEvent('player play', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoContentEvents.VIDEO_END,\n\t\t\tactionFn: (msg, data) => this._logEventOnce('player complete', data)\n\t\t},\n\t\t{\n\t\t\tmessage: 'video.player.revolver',\n\t\t\tactionFn: (msg, data) => this._logEventOnce('player revolver', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoStickyEvents.CLOSE,\n\t\t\tactionFn: (msg, data) => this._logEventOnce('sticky player closed', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.UNMUTE,\n\t\t\tactionFn: (msg, data) => this._logEvent('player unmute', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.INITIALIZATION_ERROR,\n\t\t\tactionFn: (msg, data) =>\n\t\t\t\tthis._logEvent('player initialization error', data)\n\t\t}\n\t];\n\n\tprivate _adPlayerListenersActions: ListenerAction[] = [\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_BLOCKED,\n\t\t\tactionFn: (msg, data) => this._logEventOnce('adblock detected', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_READY,\n\t\t\tactionFn: (msg, data) => this._logEvent('ad player ready', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_LOADED,\n\t\t\tactionFn: (msg, data) =>\n\t\t\t\tthis._logEvent('ad ' + data.videoBreak + ' ready', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_UNFILLED,\n\t\t\tactionFn: (msg, data) => this._logEvent('ad unfilled', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_PLAY,\n\t\t\tactionFn: (msg, data) =>\n\t\t\t\tthis._logEventOnceByVideo(\n\t\t\t\t\tdata.id,\n\t\t\t\t\t'ad ' + data.videoBreak + ' play',\n\t\t\t\t\tdata\n\t\t\t\t)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_START,\n\t\t\tactionFn: (msg, data) =>\n\t\t\t\tthis._logEventOnce('ad ' + data.videoBreak + ' start', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_REQUEST,\n\t\t\tactionFn: (msg, data) =>\n\t\t\t\tthis._logEventOnce('ad ' + data.videoBreak + ' call', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_END,\n\t\t\tactionFn: (msg, data) =>\n\t\t\t\tthis._logEvent('ad ' + data.videoBreak + ' end', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_CLICK,\n\t\t\tactionFn: (msg, data) =>\n\t\t\t\tthis._logEvent('ad ' + data.videoBreak + ' click', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_IMPRESSION,\n\t\t\tactionFn: (msg, data) =>\n\t\t\t\tthis._logEvent('ad ' + data.videoBreak + ' impression', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_CONTENT_RESUME,\n\t\t\tactionFn: (msg, data) => this._logEvent('ad content resume', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_BID_FOUND,\n\t\t\tactionFn: (msg, data) => this._logEvent('ad bid found', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.HEAVY_ADS,\n\t\t\tactionFn: (msg, data) => this._logEvent('heavy ad error', data)\n\t\t}\n\t];\n\n\tconstructor(options: AnalyticsPluginOptions) {\n\t\tthis._store = options.store;\n\t\tthis.init();\n\t}\n\n\tpublic init() {\n\t\tthis._initListeners([\n\t\t\t...this._playerListenersActions,\n\t\t\t...this._adPlayerListenersActions\n\t\t]);\n\t}\n\n\tprivate _getLogger = (instanceId: string) => {\n\t\ttry {\n\t\t\tconst storeInstance = this._store.getInstance(instanceId);\n\t\t\treturn storeInstance?.logger;\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\n\t\t\tconsole.error(instanceId + ' store instance not found');\n\t\t}\n\t};\n\n\tprivate _logError = (message: string, category: string, instanceId: string) =>\n\t\tthis._getLogger(instanceId).logError(message, category);\n\n\tprivate _logEvent = (message, data) =>\n\t\tthis._getLogger(data.id).logEvent(message, data);\n\n\tprivate _logEventOnce = (message, data) =>\n\t\tthis._getLogger(data.id).logEventOnce(message, data);\n\n\tprivate async _logEventOnceByVideo(\n\t\tinstanceId: string,\n\t\taction: string,\n\t\tdata: any\n\t) {\n\t\tconst instance = this._store.getInstance(instanceId);\n\t\tconst player = instance?.player;\n\n\t\tif (!player || !instance)\n\t\t\tthrow new Error('Missing Store Instance or player');\n\n\t\tconst videoId =\n\t\t\tplayer.name === Players.DAILYMOTION_EMBED\n\t\t\t\t? await (player as DailymotionEmbedPlayer).getVideo()\n\t\t\t\t: player.videoId;\n\n\t\tthis._events[instanceId] = this._events[instanceId] || {};\n\n\t\tif (this._events[instanceId][action] === videoId) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._logEvent(action, data);\n\t\tthis._events[instanceId][action] = videoId;\n\t}\n\n\tprivate _initListeners = (listenersActions: ListenerAction[]) =>\n\t\tlistenersActions.forEach((listenAction) =>\n\t\t\tPubSub.subscribe(listenAction.message, listenAction.actionFn)\n\t\t);\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.Analytics = AnalyticsPlugin;\n","/**\n * lodash (Custom Build) \n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the `TypeError` message for \"Functions\" methods. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\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\n/** 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 objectToString = objectProto.toString;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\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. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `maxWait` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n result = wait - timeSinceLastCall;\n\n return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `maxWait` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `lastArgs` which means `func` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\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/**\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/**\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) && objectToString.call(value) == symbolTag);\n}\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = value.replace(reTrim, '');\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nmodule.exports = debounce;\n","import { VideoConsoleLogger } from 'src/utils/video-logger';\nimport { Players } from '../../enums/players.enum';\nimport {\n\tPublishableVideoAdEvents,\n\tPublishableVideoContentEvents,\n\tPublishableVideoPlayerEvents,\n\tPublishableVideoStickyEvents,\n\tPublishableVideoUserEvents\n} from '../../enums/publishable-events.enum';\nimport { ListenerAction } from '../../interfaces/listener-action';\nimport { Store, StoreInstance } from '../../store';\nimport debounce from 'lodash.debounce';\nimport PubSub from 'pubsub-js';\nimport { StickyPlugin } from '../sticky/sticky-core';\n\nconst logger = new VideoConsoleLogger();\n\nexport interface AutoplayPluginOptions {\n\tstore: Store;\n}\n\nexport class AutoplayPlugin {\n\tpublic name = 'autoplay';\n\tprivate _store: Store;\n\tprivate _stickyEnabled: boolean;\n\tprivate _enabled = false;\n\tprivate _storeInstances: Map = new Map<\n\t\tstring,\n\t\tStoreInstance\n\t>();\n\tpublic scrollEvent: (...args: any[]) => void =\n\t\tthis._autoplayMainViewablePlayer.bind(this);\n\n\tpublic async _autoplayMainViewablePlayer(\n\t\tforceEnable?: boolean\n\t): Promise {\n\t\tif (!this._enabled && !forceEnable) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst currentInstance = this._store.getCurrentPlayableInstance();\n\n\t\t// Stop trying to autoplay if an instance is already playing and still viewable\n\t\tconst videoContainerViewable = currentInstance\n\t\t\t? this._store.isViewable(currentInstance)\n\t\t\t: false;\n\t\tconst playing = currentInstance\n\t\t\t? await this._store.isPlaying(currentInstance)\n\t\t\t: false;\n\t\tconst instanceIsPlayingAndViewable = playing && videoContainerViewable;\n\n\t\tif (instanceIsPlayingAndViewable) return;\n\n\t\tconst canAutoplay = (\n\t\t\tplaying: boolean,\n\t\t\tvideoContainerViewable: boolean,\n\t\t\tvideoStarted: boolean,\n\t\t\tadPaused: boolean\n\t\t) =>\n\t\t\t!playing && !adPaused\n\t\t\t\t? !videoStarted\n\t\t\t\t\t? videoContainerViewable\n\t\t\t\t\t: false\n\t\t\t\t: false;\n\n\t\tconst canPause = (\n\t\t\tplaying: boolean,\n\t\t\tvideoContainerViewable: boolean,\n\t\t\tisStickyEnabled: boolean,\n\t\t\tisSticked: boolean\n\t\t) =>\n\t\t\tplaying && !videoContainerViewable && !isStickyEnabled && !isSticked && !this._stickyClosing;\n\n\t\tconst playableInstances = Array.from(this._storeInstances.values()).filter(\n\t\t\t(instance) =>\n\t\t\t\tinstance.autoplay &&\n\t\t\t\tinstance.autoplay.enabled &&\n\t\t\t\tinstance.autoplay.startOnSight\n\t\t);\n\n\t\t// Every permits to break if return a falsy, we must return truthy to continue iterating\n\t\tfor (const instance of playableInstances) {\n\t\t\tconst adPaused: boolean =\n\t\t\t\tinstance.adPlayer &&\n\t\t\t\tinstance.adPlayer.adsState &&\n\t\t\t\tinstance.adPlayer.adsState.paused;\n\t\t\tconst playing = await this._store.isPlaying(instance);\n\t\t\tconst viewable = this._store.isViewable(instance);\n\t\t\tconst videoStarted = instance.player.videoStarted;\n\t\t\tconst isSticky = instance.player.isSticked;\n\t\t\tconst isStickyEnabled = this._stickyEnabled;\n\t\t\tconst playVideo = canAutoplay(playing, viewable, videoStarted, adPaused);\n\t\t\tconst pauseVideo = canPause(playing, viewable, isStickyEnabled, isSticky);\n\n\t\t\tif (playVideo) {\n\t\t\t\tlogger.debug('Should PLAY video')();\n\t\t\t\tlogger.info(\n\t\t\t\t\t`[${instance.player.id}] canAutoplay(${playing}, ${viewable}, ${videoStarted}, ${adPaused})`\n\t\t\t\t)();\n\t\t\t\tthis._store.getActivePlayer(instance).play(); // TODO: Use an async handler and delete sleep\n\t\t\t\tthis._sleep();\n\t\t\t} else if (pauseVideo) {\n\t\t\t\tlogger.debug('Should PAUSE video')();\n\t\t\t\t[instance.adPlayer, instance.player]\n\t\t\t\t\t.filter((p) => !!p)\n\t\t\t\t\t.forEach((player) => {\n\t\t\t\t\t\tplayer.pause();\n\t\t\t\t\t});\n\n\t\t\t\t// Permit to restick after a sticky disable (Taboola ...)\n\t\t\t\t// TODO: Refactor Taboola GTM tag and behavior\n\t\t\t\tinstance.sticky.enabled = true;\n\t\t\t}\n\n\t\t\tif (playVideo || pauseVideo) {\n\t\t\t\tthis._store.setCurrentPlayableInstanceId(instance.player.id);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _stickyClosing = false;\n\n\tprivate _listenersActions: ListenerAction[] = [\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.READY,\n\t\t\tactionFn: (msg, data) => {\n\t\t\t\tthis._registerInstance.call(this, data.id);\n\t\t\t\tthis._debouncedAutoplay.call(this);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoContentEvents.VIDEO_END,\n\t\t\tactionFn: (msg, data) => this._unregisterInstance(data.id)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_READY,\n\t\t\tactionFn: () => this._debouncedAutoplay.call(this)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoUserEvents.TOGGLE_PLAY_PAUSE,\n\t\t\tactionFn: (msg, data) => this._toggle.bind(this, data.id)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoStickyEvents.CLOSE,\n\t\t\tactionFn: () => {\n\t\t\t\tthis._stickyEnabled = false;\n\t\t\t\tconst instance =\n\t\t\t\t\tthis._store.getCurrentPlayableInstance() as StoreInstance;\n\t\t\t\tthis._stickyCloseHandler.call(this, instance);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_END,\n\t\t\tactionFn: () => {\n\t\t\t\tconst instance =\n\t\t\t\t\tthis._store.getCurrentPlayableInstance() as StoreInstance;\n\t\t\t\tconst isSticky = instance.player.isSticked;\n\n\t\t\t\tif (!isSticky && this._stickyClosing) {\n\t\t\t\t\tthis._stickyCloseHandler.call(this, instance);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.DAILYMOTION_EMBED_LAZY_READY,\n\t\t\tactionFn: () => this._autoplayMainViewablePlayer(true)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoStickyEvents.STICKED,\n\t\t\tactionFn: () => {\n\t\t\t\tthis._stickyEnabled = true;\n\t\t\t\tthis._debouncedAutoplay.call(this);\n\t\t\t}\n\t\t}\n\t];\n\n\tconstructor(options: AutoplayPluginOptions) {\n\t\tthis._store = options.store;\n\t\tthis._initListeners(this._listenersActions);\n\t}\n\n\tprivate _initListeners = (listenersActions: ListenerAction[]) =>\n\t\tlistenersActions.forEach((listenAction) =>\n\t\t\tPubSub.subscribe(listenAction.message, listenAction.actionFn.bind(this))\n\t\t);\n\n\tprivate _stickyCloseHandler(instance: StoreInstance) {\n\t\tif (!instance) {\n\t\t\tthrow new Error('Missing mandatory `instance` parameter');\n\t\t}\n\t\tif (!instance.adPlayer) {\n\t\t\tthrow new Error('Missing mandatory `instance.adPlayer` parameter');\n\t\t}\n\n\t\tconst adsState = instance.adPlayer.adsState || {};\n\n\t\tthis._stickyClosing = isPlayingAds(instance, this._stickyClosing, adsState);\n\n\t\tif (this._stickyClosing) return;\n\n\t\tthis._store.getActivePlayer(instance).pause();\n\t\tthis._stickyClosing = !this._stickyClosing;\n\n\t\tfunction isPlayingAds(\n\t\t\tinstance: StoreInstance,\n\t\t\tstickyClosing: boolean,\n\t\t\tadsState: any\n\t\t) {\n\t\t\tlogger.debug(`getIsStickyClosing()`)();\n\n\t\t\tconst isPlayingAds =\n\t\t\t\t!stickyClosing &&\n\t\t\t\ttypeof adsState.playing === 'boolean' &&\n\t\t\t\tadsState.playing &&\n\t\t\t\t!adsState.ended;\n\n\t\t\tlogger.debug('isPlayingAds: ' + isPlayingAds)();\n\t\t\treturn isPlayingAds;\n\t\t}\n\t}\n\n\tprivate _registerInstance(id: string) {\n\t\tlogger.debug(`_registerInstance(${id})`)();\n\t\tconst instance = this._store.getInstance(id);\n\n\t\tif (!instance || !instance.autoplay || !instance.autoplay.startOnSight)\n\t\t\treturn;\n\n\t\tinstance.autoplay.enabled = true;\n\t\tthis._storeInstances.set(id, instance);\n\t\tthis._enabled = true;\n\t}\n\n\tprivate _unregisterInstance(id: string) {\n\t\tif (!this._storeInstances.has(id)) return;\n\n\t\tthis._storeInstances.delete(id);\n\t}\n\n\tprivate _debouncedAutoplay = () =>\n\t\tdebounce(this._autoplayMainViewablePlayer, 200, {\n\t\t\tleading: true,\n\t\t\tmaxWait: 200,\n\t\t\ttrailing: true\n\t\t}).call(this);\n\n\tprivate _toggle(id: string): void {\n\t\tconst instance = this._store.getInstance(id);\n\t\tif (!instance || !instance.autoplay) return;\n\n\t\tinstance.autoplay.enabled = !instance.autoplay.enabled;\n\t}\n\n\tprivate _sleep(timeout: number = 1000): void {\n\t\tthis._enabled = false;\n\t\tsetTimeout(() => (this._enabled = true), timeout);\n\t}\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.Autoplay = (options: AutoplayPluginOptions) =>\n\tnew AutoplayPlugin(options);\n","import { PublishableVideoPlayerEvents } from '../../enums/publishable-events.enum';\nimport { Store } from '../../store';\nimport PubSub from 'pubsub-js';\n\nexport interface DebugPluginOptions {\n\tstore: Store;\n}\n\nexport class DebugPlugin {\n\tpublic name = 'debug';\n\tprivate _store: Store;\n\n\tconstructor(options: DebugPluginOptions) {\n\t\tthis._store = options.store;\n\t\tthis._initListeners();\n\t}\n\n\tprivate _initListeners = () =>\n\t\tPubSub.subscribe(PublishableVideoPlayerEvents.READY, (msg, data) =>\n\t\t\tthis._showDebugElement(data.id)\n\t\t);\n\n\tprivate _showDebugElement(playerId: string) {\n\t\tconst instance = this._store.getInstance(playerId);\n\t\tif (!instance) return;\n\n\t\tconst player = instance.player;\n\n\t\tconst container = document.createElement('div');\n\t\tcontainer.style.cursor = 'pointer';\n\t\tcontainer.classList.add('debug-module-container', 'hidden');\n\t\tcontainer.innerHTML = '🐞';\n\t\tcontainer.onclick = () => console.info('debug', instance);\n\n\t\tconst playerContainer = document.getElementById(player.id + '-container');\n\t\tif (!playerContainer) throw new Error('Player container not found !');\n\t\tplayerContainer.classList.add('video-player.debug');\n\t\tplayerContainer.appendChild(container);\n\t}\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.Debug = DebugPlugin;\n","export function isFunction(x: any): x is Function {\n return typeof x === 'function';\n}\n","let _enable_super_gross_mode_that_will_cause_bad_things = false;\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like what Promise contructor should used to create Promises\n */\nexport const config = {\n /**\n * The promise constructor used by default for methods such as\n * {@link toPromise} and {@link forEach}\n */\n Promise: undefined as PromiseConstructorLike,\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BY TIME\n * FOR MIGRATION REASONS.\n */\n set useDeprecatedSynchronousErrorHandling(value: boolean) {\n if (value) {\n const error = new Error();\n console.warn('DEPRECATED! RxJS was set to use deprecated synchronous error handling behavior by code at: \\n' + error.stack);\n } else if (_enable_super_gross_mode_that_will_cause_bad_things) {\n console.log('RxJS: Back to a better error behavior. Thank you. <3');\n }\n _enable_super_gross_mode_that_will_cause_bad_things = value;\n },\n\n get useDeprecatedSynchronousErrorHandling() {\n return _enable_super_gross_mode_that_will_cause_bad_things;\n },\n};\n","/**\n * Throws an error on another job so that it's picked up by the runtime's\n * uncaught error handling mechanism.\n * @param err the error to throw\n */\nexport function hostReportError(err: any) {\n setTimeout(() => { throw err; }, 0);\n}","import { Observer } from './types';\nimport { config } from './config';\nimport { hostReportError } from './util/hostReportError';\n\nexport const empty: Observer = {\n closed: true,\n next(value: any): void { /* noop */},\n error(err: any): void {\n if (config.useDeprecatedSynchronousErrorHandling) {\n throw err;\n } else {\n hostReportError(err);\n }\n },\n complete(): void { /*noop*/ }\n};\n","export function isObject(x: any): x is Object {\n return x !== null && typeof x === 'object';\n}\n","export interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n new(errors: any[]): UnsubscriptionError;\n}\n\nconst UnsubscriptionErrorImpl = (() => {\n function UnsubscriptionErrorImpl(this: any, errors: any[]) {\n Error.call(this);\n this.message = errors ?\n `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}` : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n return this;\n }\n\n UnsubscriptionErrorImpl.prototype = Object.create(Error.prototype);\n\n return UnsubscriptionErrorImpl;\n})();\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = UnsubscriptionErrorImpl as any;","import { isArray } from './util/isArray';\nimport { isObject } from './util/isObject';\nimport { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic } from './types';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n *\n * @class Subscription\n */\nexport class Subscription implements SubscriptionLike {\n /** @nocollapse */\n public static EMPTY: Subscription = (function(empty: any) {\n empty.closed = true;\n return empty;\n }(new Subscription()));\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n * @type {boolean}\n */\n public closed: boolean = false;\n\n /** @internal */\n protected _parentOrParents: Subscription | Subscription[] = null;\n /** @internal */\n private _subscriptions: SubscriptionLike[] = null;\n\n /**\n * @param {function(): void} [unsubscribe] A function describing how to\n * perform the disposal of resources when the `unsubscribe` method is called.\n */\n constructor(unsubscribe?: () => void) {\n if (unsubscribe) {\n (this as any)._ctorUnsubscribe = true;\n (this as any)._unsubscribe = unsubscribe;\n }\n }\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n * @return {void}\n */\n unsubscribe(): void {\n let errors: any[];\n\n if (this.closed) {\n return;\n }\n\n let { _parentOrParents, _ctorUnsubscribe, _unsubscribe, _subscriptions } = (this as any);\n\n this.closed = true;\n this._parentOrParents = null;\n // null out _subscriptions first so any child subscriptions that attempt\n // to remove themselves from this subscription will noop\n this._subscriptions = null;\n\n if (_parentOrParents instanceof Subscription) {\n _parentOrParents.remove(this);\n } else if (_parentOrParents !== null) {\n for (let index = 0; index < _parentOrParents.length; ++index) {\n const parent = _parentOrParents[index];\n parent.remove(this);\n }\n }\n\n if (isFunction(_unsubscribe)) {\n // It's only possible to null _unsubscribe - to release the reference to\n // any teardown function passed in the constructor - if the property was\n // actually assigned in the constructor, as there are some classes that\n // are derived from Subscriber (which derives from Subscription) that\n // implement an _unsubscribe method as a mechanism for obtaining\n // unsubscription notifications and some of those subscribers are\n // recycled. Also, in some of those subscribers, _unsubscribe switches\n // from a prototype method to an instance property - see notifyNext in\n // RetryWhenSubscriber.\n if (_ctorUnsubscribe) {\n (this as any)._unsubscribe = undefined;\n }\n try {\n _unsubscribe.call(this);\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? flattenUnsubscriptionErrors(e.errors) : [e];\n }\n }\n\n if (isArray(_subscriptions)) {\n let index = -1;\n let len = _subscriptions.length;\n\n while (++index < len) {\n const sub = _subscriptions[index];\n if (isObject(sub)) {\n try {\n sub.unsubscribe();\n } catch (e) {\n errors = errors || [];\n if (e instanceof UnsubscriptionError) {\n errors = errors.concat(flattenUnsubscriptionErrors(e.errors));\n } else {\n errors.push(e);\n }\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n\n /**\n * Adds a tear down to be called during the unsubscribe() of this\n * Subscription. Can also be used to add a child subscription.\n *\n * If the tear down being added is a subscription that is already\n * unsubscribed, is the same reference `add` is being called on, or is\n * `Subscription.EMPTY`, it will not be added.\n *\n * If this subscription is already in an `closed` state, the passed\n * tear down logic will be executed immediately.\n *\n * When a parent subscription is unsubscribed, any child subscriptions that were added to it are also unsubscribed.\n *\n * @param {TeardownLogic} teardown The additional logic to execute on\n * teardown.\n * @return {Subscription} Returns the Subscription used or created to be\n * added to the inner subscriptions list. This Subscription can be used with\n * `remove()` to remove the passed teardown logic from the inner subscriptions\n * list.\n */\n add(teardown: TeardownLogic): Subscription {\n let subscription = (teardown);\n\n if (!teardown) {\n return Subscription.EMPTY;\n }\n\n switch (typeof teardown) {\n case 'function':\n subscription = new Subscription(<(() => void)>teardown);\n case 'object':\n if (subscription === this || subscription.closed || typeof subscription.unsubscribe !== 'function') {\n // This also covers the case where `subscription` is `Subscription.EMPTY`, which is always in `closed` state.\n return subscription;\n } else if (this.closed) {\n subscription.unsubscribe();\n return subscription;\n } else if (!(subscription instanceof Subscription)) {\n const tmp = subscription;\n subscription = new Subscription();\n subscription._subscriptions = [tmp];\n }\n break;\n default: {\n throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.');\n }\n }\n\n // Add `this` as parent of `subscription` if that's not already the case.\n let { _parentOrParents } = subscription;\n if (_parentOrParents === null) {\n // If we don't have a parent, then set `subscription._parents` to\n // the `this`, which is the common case that we optimize for.\n subscription._parentOrParents = this;\n } else if (_parentOrParents instanceof Subscription) {\n if (_parentOrParents === this) {\n // The `subscription` already has `this` as a parent.\n return subscription;\n }\n // If there's already one parent, but not multiple, allocate an\n // Array to store the rest of the parent Subscriptions.\n subscription._parentOrParents = [_parentOrParents, this];\n } else if (_parentOrParents.indexOf(this) === -1) {\n // Only add `this` to the _parentOrParents list if it's not already there.\n _parentOrParents.push(this);\n } else {\n // The `subscription` already has `this` as a parent.\n return subscription;\n }\n\n // Optimize for the common case when adding the first subscription.\n const subscriptions = this._subscriptions;\n if (subscriptions === null) {\n this._subscriptions = [subscription];\n } else {\n subscriptions.push(subscription);\n }\n\n return subscription;\n }\n\n /**\n * Removes a Subscription from the internal list of subscriptions that will\n * unsubscribe during the unsubscribe process of this Subscription.\n * @param {Subscription} subscription The subscription to remove.\n * @return {void}\n */\n remove(subscription: Subscription): void {\n const subscriptions = this._subscriptions;\n if (subscriptions) {\n const subscriptionIndex = subscriptions.indexOf(subscription);\n if (subscriptionIndex !== -1) {\n subscriptions.splice(subscriptionIndex, 1);\n }\n }\n }\n}\n\nfunction flattenUnsubscriptionErrors(errors: any[]) {\n return errors.reduce((errs, err) => errs.concat((err instanceof UnsubscriptionError) ? err.errors : err), []);\n}\n","/** @deprecated do not use, this is no longer checked by RxJS internals */\nexport const rxSubscriber = (() =>\n typeof Symbol === 'function'\n ? Symbol('rxSubscriber')\n : '@@rxSubscriber_' + Math.random())();\n\n/**\n * @deprecated use rxSubscriber instead\n */\nexport const $$rxSubscriber = rxSubscriber;\n","import { isFunction } from './util/isFunction';\nimport { empty as emptyObserver } from './Observer';\nimport { Observer, PartialObserver, TeardownLogic } from './types';\nimport { Subscription } from './Subscription';\nimport { rxSubscriber as rxSubscriberSymbol } from '../internal/symbol/rxSubscriber';\nimport { config } from './config';\nimport { hostReportError } from './util/hostReportError';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n *\n * @class Subscriber\n */\nexport class Subscriber extends Subscription implements Observer {\n\n [rxSubscriberSymbol]() { return this; }\n\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param {function(x: ?T): void} [next] The `next` callback of an Observer.\n * @param {function(e: ?any): void} [error] The `error` callback of an\n * Observer.\n * @param {function(): void} [complete] The `complete` callback of an\n * Observer.\n * @return {Subscriber} A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @nocollapse\n */\n static create(next?: (x?: T) => void,\n error?: (e?: any) => void,\n complete?: () => void): Subscriber {\n const subscriber = new Subscriber(next, error, complete);\n subscriber.syncErrorThrowable = false;\n return subscriber;\n }\n\n /** @internal */ syncErrorValue: any = null;\n /** @internal */ syncErrorThrown: boolean = false;\n /** @internal */ syncErrorThrowable: boolean = false;\n\n protected isStopped: boolean = false;\n protected destination: PartialObserver | Subscriber; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @param {Observer|function(value: T): void} [destinationOrNext] A partially\n * defined Observer or a `next` callback function.\n * @param {function(e: ?any): void} [error] The `error` callback of an\n * Observer.\n * @param {function(): void} [complete] The `complete` callback of an\n * Observer.\n */\n constructor(destinationOrNext?: PartialObserver | ((value: T) => void),\n error?: (e?: any) => void,\n complete?: () => void) {\n super();\n\n switch (arguments.length) {\n case 0:\n this.destination = emptyObserver;\n break;\n case 1:\n if (!destinationOrNext) {\n this.destination = emptyObserver;\n break;\n }\n if (typeof destinationOrNext === 'object') {\n if (destinationOrNext instanceof Subscriber) {\n this.syncErrorThrowable = destinationOrNext.syncErrorThrowable;\n this.destination = destinationOrNext;\n destinationOrNext.add(this);\n } else {\n this.syncErrorThrowable = true;\n this.destination = new SafeSubscriber(this, > destinationOrNext);\n }\n break;\n }\n default:\n this.syncErrorThrowable = true;\n this.destination = new SafeSubscriber(this, <((value: T) => void)> destinationOrNext, error, complete);\n break;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param {T} [value] The `next` value.\n * @return {void}\n */\n next(value?: T): void {\n if (!this.isStopped) {\n this._next(value);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param {any} [err] The `error` exception.\n * @return {void}\n */\n error(err?: any): void {\n if (!this.isStopped) {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n * @return {void}\n */\n complete(): void {\n if (!this.isStopped) {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (this.closed) {\n return;\n }\n this.isStopped = true;\n super.unsubscribe();\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n this.destination.error(err);\n this.unsubscribe();\n }\n\n protected _complete(): void {\n this.destination.complete();\n this.unsubscribe();\n }\n\n /** @deprecated This is an internal implementation detail, do not use. */\n _unsubscribeAndRecycle(): Subscriber {\n const { _parentOrParents } = this;\n this._parentOrParents = null;\n this.unsubscribe();\n this.closed = false;\n this.isStopped = false;\n this._parentOrParents = _parentOrParents;\n return this;\n }\n}\n\n/**\n * We need this JSDoc comment for affecting ESDoc.\n * @ignore\n * @extends {Ignored}\n */\nexport class SafeSubscriber extends Subscriber {\n\n private _context: any;\n\n constructor(private _parentSubscriber: Subscriber,\n observerOrNext?: PartialObserver | ((value: T) => void),\n error?: (e?: any) => void,\n complete?: () => void) {\n super();\n\n let next: ((value: T) => void);\n let context: any = this;\n\n if (isFunction(observerOrNext)) {\n next = (<((value: T) => void)> observerOrNext);\n } else if (observerOrNext) {\n next = (> observerOrNext).next;\n error = (> observerOrNext).error;\n complete = (> observerOrNext).complete;\n if (observerOrNext !== emptyObserver) {\n context = Object.create(observerOrNext);\n if (isFunction(context.unsubscribe)) {\n this.add(<() => void> context.unsubscribe.bind(context));\n }\n context.unsubscribe = this.unsubscribe.bind(this);\n }\n }\n\n this._context = context;\n this._next = next;\n this._error = error;\n this._complete = complete;\n }\n\n next(value?: T): void {\n if (!this.isStopped && this._next) {\n const { _parentSubscriber } = this;\n if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {\n this.__tryOrUnsub(this._next, value);\n } else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) {\n this.unsubscribe();\n }\n }\n }\n\n error(err?: any): void {\n if (!this.isStopped) {\n const { _parentSubscriber } = this;\n const { useDeprecatedSynchronousErrorHandling } = config;\n if (this._error) {\n if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {\n this.__tryOrUnsub(this._error, err);\n this.unsubscribe();\n } else {\n this.__tryOrSetError(_parentSubscriber, this._error, err);\n this.unsubscribe();\n }\n } else if (!_parentSubscriber.syncErrorThrowable) {\n this.unsubscribe();\n if (useDeprecatedSynchronousErrorHandling) {\n throw err;\n }\n hostReportError(err);\n } else {\n if (useDeprecatedSynchronousErrorHandling) {\n _parentSubscriber.syncErrorValue = err;\n _parentSubscriber.syncErrorThrown = true;\n } else {\n hostReportError(err);\n }\n this.unsubscribe();\n }\n }\n }\n\n complete(): void {\n if (!this.isStopped) {\n const { _parentSubscriber } = this;\n if (this._complete) {\n const wrappedComplete = () => this._complete.call(this._context);\n\n if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {\n this.__tryOrUnsub(wrappedComplete);\n this.unsubscribe();\n } else {\n this.__tryOrSetError(_parentSubscriber, wrappedComplete);\n this.unsubscribe();\n }\n } else {\n this.unsubscribe();\n }\n }\n }\n\n private __tryOrUnsub(fn: Function, value?: any): void {\n try {\n fn.call(this._context, value);\n } catch (err) {\n this.unsubscribe();\n if (config.useDeprecatedSynchronousErrorHandling) {\n throw err;\n } else {\n hostReportError(err);\n }\n }\n }\n\n private __tryOrSetError(parent: Subscriber, fn: Function, value?: any): boolean {\n if (!config.useDeprecatedSynchronousErrorHandling) {\n throw new Error('bad call');\n }\n try {\n fn.call(this._context, value);\n } catch (err) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n parent.syncErrorValue = err;\n parent.syncErrorThrown = true;\n return true;\n } else {\n hostReportError(err);\n return true;\n }\n }\n return false;\n }\n\n /** @internal This is an internal implementation detail, do not use. */\n _unsubscribe(): void {\n const { _parentSubscriber } = this;\n this._context = null;\n this._parentSubscriber = null;\n _parentSubscriber.unsubscribe();\n }\n}\n","export function identity(x: T): T {\n return x;\n}\n","import { noop } from './noop';\nimport { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\n/* tslint:disable:max-line-length */\nexport function pipe(): UnaryFunction;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction, fn4: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction, fn4: UnaryFunction, fn5: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction, fn4: UnaryFunction, fn5: UnaryFunction, fn6: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction, fn4: UnaryFunction, fn5: UnaryFunction, fn6: UnaryFunction, fn7: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction, fn4: UnaryFunction, fn5: UnaryFunction, fn6: UnaryFunction, fn7: UnaryFunction, fn8: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction, fn4: UnaryFunction, fn5: UnaryFunction, fn6: UnaryFunction, fn7: UnaryFunction, fn8: UnaryFunction, fn9: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction, fn4: UnaryFunction, fn5: UnaryFunction, fn6: UnaryFunction, fn7: UnaryFunction, fn8: UnaryFunction, fn9: UnaryFunction, ...fns: UnaryFunction[]): UnaryFunction;\n/* tslint:enable:max-line-length */\n\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n","import { Operator } from './Operator';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, PartialObserver, Subscribable } from './types';\nimport { canReportError } from './util/canReportError';\nimport { toSubscriber } from './util/toSubscriber';\nimport { iif } from './observable/iif';\nimport { throwError } from './observable/throwError';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n *\n * @class Observable\n */\nexport class Observable implements Subscribable {\n\n /** Internal implementation detail, do not use directly. */\n public _isScalar: boolean = false;\n\n /** @deprecated This is an internal implementation detail, do not use. */\n source: Observable;\n\n /** @deprecated This is an internal implementation detail, do not use. */\n operator: Operator;\n\n /**\n * @constructor\n * @param {Function} subscribe the function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new cold Observable by calling the Observable constructor\n * @static true\n * @owner Observable\n * @method create\n * @param {Function} subscribe? the subscriber function to be passed to the Observable constructor\n * @return {Observable} a new cold observable\n * @nocollapse\n * @deprecated use new Observable() instead\n */\n static create: Function = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n }\n\n /**\n * Creates a new Observable, with this Observable as the source, and the passed\n * operator defined as the new observable's operator.\n * @method lift\n * @param {Operator} operator the operator defining the operation to take on the observable\n * @return {Observable} a new observable with the Operator applied\n */\n lift(operator: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observer?: PartialObserver): Subscription;\n /** @deprecated Use an observer instead of a complete callback */\n subscribe(next: null | undefined, error: null | undefined, complete: () => void): Subscription;\n /** @deprecated Use an observer instead of an error callback */\n subscribe(next: null | undefined, error: (error: any) => void, complete?: () => void): Subscription;\n /** @deprecated Use an observer instead of a complete callback */\n subscribe(next: (value: T) => void, error: null | undefined, complete: () => void): Subscription;\n subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided, all errors will\n * be left uncaught.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of Observer,\n * if you do not need to listen for something, you can omit a function, preferably by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to `error` function, just as before, if not provided, errors emitted by an Observable will be thrown.\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * ## Example\n * ### Subscribe with an Observer\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // \"Adding: 1\"\n * // \"Adding: 2\"\n * // \"Adding: 3\"\n * // \"Sum equals: 6\"\n * ```\n *\n * ### Subscribe with functions\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // \"Adding: 1\"\n * // \"Adding: 2\"\n * // \"Adding: 3\"\n * // \"Sum equals: 6\"\n * ```\n *\n * ### Cancel a subscription\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe(\n * num => console.log(num),\n * undefined,\n * () => {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * );\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // \"unsubscribed!\" after 2.5s\n * ```\n *\n * @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,\n * or the first of three possible handlers, which is the handler for each value emitted from the subscribed\n * Observable.\n * @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown as unhandled.\n * @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.\n * @return {ISubscription} a subscription reference to the registered handlers\n * @method subscribe\n */\n subscribe(observerOrNext?: PartialObserver | ((value: T) => void),\n error?: (error: any) => void,\n complete?: () => void): Subscription {\n\n const { operator } = this;\n const sink = toSubscriber(observerOrNext, error, complete);\n\n if (operator) {\n sink.add(operator.call(sink, this.source));\n } else {\n sink.add(\n this.source || (config.useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ?\n this._subscribe(sink) :\n this._trySubscribe(sink)\n );\n }\n\n if (config.useDeprecatedSynchronousErrorHandling) {\n if (sink.syncErrorThrowable) {\n sink.syncErrorThrowable = false;\n if (sink.syncErrorThrown) {\n throw sink.syncErrorValue;\n }\n }\n }\n\n return sink;\n }\n\n /** @deprecated This is an internal implementation detail, do not use. */\n _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n sink.syncErrorThrown = true;\n sink.syncErrorValue = err;\n }\n if (canReportError(sink)) {\n sink.error(err);\n } else {\n console.warn(err);\n }\n }\n }\n\n /**\n * @method forEach\n * @param {Function} next a handler for each value emitted by the observable\n * @param {PromiseConstructor} [promiseCtor] a constructor function used to instantiate the Promise\n * @return {Promise} a promise that either resolves on observable completion or\n * rejects with the handled error\n */\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n // Must be declared in a separate statement to avoid a ReferenceError when\n // accessing subscription below in the closure due to Temporal Dead Zone.\n let subscription: Subscription;\n subscription = this.subscribe((value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n if (subscription) {\n subscription.unsubscribe();\n }\n }\n }, reject, resolve);\n }) as Promise;\n }\n\n /** @internal This is an internal implementation detail, do not use. */\n _subscribe(subscriber: Subscriber): TeardownLogic {\n const { source } = this;\n return source && source.subscribe(subscriber);\n }\n\n // `if` and `throw` are special snow flakes, the compiler sees them as reserved words. Deprecated in\n // favor of iif and throwError functions.\n /**\n * @nocollapse\n * @deprecated In favor of iif creation function: import { iif } from 'rxjs';\n */\n static if: typeof iif;\n /**\n * @nocollapse\n * @deprecated In favor of throwError creation function: import { throwError } from 'rxjs';\n */\n static throw: typeof throwError;\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @method Symbol.observable\n * @return {Observable} this instance of the observable\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction, op4: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction, op4: OperatorFunction, op5: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction, op4: OperatorFunction, op5: OperatorFunction, op6: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction, op4: OperatorFunction, op5: OperatorFunction, op6: OperatorFunction, op7: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction, op4: OperatorFunction, op5: OperatorFunction, op6: OperatorFunction, op7: OperatorFunction, op8: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction, op4: OperatorFunction, op5: OperatorFunction, op6: OperatorFunction, op7: OperatorFunction, op8: OperatorFunction, op9: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction, op4: OperatorFunction, op5: OperatorFunction, op6: OperatorFunction, op7: OperatorFunction, op8: OperatorFunction, op9: OperatorFunction, ...operations: OperatorFunction[]): Observable<{}>;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n * @method pipe\n * @return {Observable} the Observable result of all of the operators having\n * been called in the order they were passed in.\n *\n * ### Example\n * ```ts\n * import { interval } from 'rxjs';\n * import { map, filter, scan } from 'rxjs/operators';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x))\n * ```\n */\n pipe(...operations: OperatorFunction[]): Observable {\n if (operations.length === 0) {\n return this as any;\n }\n\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n toPromise(this: Observable): Promise;\n toPromise(this: Observable, PromiseCtor: typeof Promise): Promise;\n toPromise(this: Observable, PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: any;\n this.subscribe((x: T) => value = x, (err: any) => reject(err), () => resolve(value));\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n if (!promiseCtor) {\n promiseCtor = config.Promise || Promise;\n }\n\n if (!promiseCtor) {\n throw new Error('no Promise impl found');\n }\n\n return promiseCtor;\n}\n","import { Subscriber } from '../Subscriber';\nimport { rxSubscriber as rxSubscriberSymbol } from '../symbol/rxSubscriber';\nimport { empty as emptyObserver } from '../Observer';\nimport { PartialObserver } from '../types';\n\nexport function toSubscriber(\n nextOrObserver?: PartialObserver | ((value: T) => void),\n error?: (error: any) => void,\n complete?: () => void): Subscriber {\n\n if (nextOrObserver) {\n if (nextOrObserver instanceof Subscriber) {\n return (> nextOrObserver);\n }\n\n if (nextOrObserver[rxSubscriberSymbol]) {\n return nextOrObserver[rxSubscriberSymbol]();\n }\n }\n\n if (!nextOrObserver && !error && !complete) {\n return new Subscriber(emptyObserver);\n }\n\n return new Subscriber(nextOrObserver, error, complete);\n}\n","import { Subscriber } from '../Subscriber';\nimport { Subject } from '../Subject';\n\n/**\n * Determines whether the ErrorObserver is closed or stopped or has a\n * destination that is closed or stopped - in which case errors will\n * need to be reported via a different mechanism.\n * @param observer the observer\n */\nexport function canReportError(observer: Subscriber | Subject): boolean {\n while (observer) {\n const { closed, destination, isStopped } = observer as any;\n if (closed || isStopped) {\n return false;\n } else if (destination && destination instanceof Subscriber) {\n observer = destination;\n } else {\n observer = null;\n }\n }\n return true;\n}\n","import { Subscriber } from '../Subscriber';\n\n/**\n * Subscribes to an ArrayLike with a subscriber\n * @param array The array or array-like to subscribe to\n */\nexport const subscribeToArray = (array: ArrayLike) => (subscriber: Subscriber) => {\n for (let i = 0, len = array.length; i < len && !subscriber.closed; i++) {\n subscriber.next(array[i]);\n }\n subscriber.complete();\n};\n","export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n\n/**\n * @deprecated use {@link iterator} instead\n */\nexport const $$iterator = iterator;\n","/**\n * Tests to see if the object is an ES2015 (ES6) Promise\n * @see {@link https://www.ecma-international.org/ecma-262/6.0/#sec-promise-objects}\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return !!value && typeof (value).subscribe !== 'function' && typeof (value as any).then === 'function';\n}\n","import { ObservableInput } from '../types';\nimport { subscribeToArray } from './subscribeToArray';\nimport { subscribeToPromise } from './subscribeToPromise';\nimport { subscribeToIterable } from './subscribeToIterable';\nimport { subscribeToObservable } from './subscribeToObservable';\nimport { isArrayLike } from './isArrayLike';\nimport { isPromise } from './isPromise';\nimport { isObject } from './isObject';\nimport { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { Subscription } from '../Subscription';\nimport { Subscriber } from '../Subscriber';\n\nexport const subscribeTo = (result: ObservableInput): (subscriber: Subscriber) => Subscription | void => {\n if (!!result && typeof result[Symbol_observable] === 'function') {\n return subscribeToObservable(result as any);\n } else if (isArrayLike(result)) {\n return subscribeToArray(result);\n } else if (isPromise(result)) {\n return subscribeToPromise(result as Promise);\n } else if (!!result && typeof result[Symbol_iterator] === 'function') {\n return subscribeToIterable(result as any);\n } else {\n const value = isObject(result) ? 'an invalid object' : `'${result}'`;\n const msg = `You provided ${value} where a stream was expected.`\n + ' You can provide an Observable, Promise, Array, or Iterable.';\n throw new TypeError(msg);\n }\n};\n","import { Subscriber } from '../Subscriber';\nimport { observable as Symbol_observable } from '../symbol/observable';\n\n/**\n * Subscribes to an object that implements Symbol.observable with the given\n * Subscriber.\n * @param obj An object that implements Symbol.observable\n */\nexport const subscribeToObservable = (obj: any) => (subscriber: Subscriber) => {\n const obs = obj[Symbol_observable]();\n if (typeof obs.subscribe !== 'function') {\n // Should be caught by observable subscribe function error handling.\n throw new TypeError('Provided object does not correctly implement Symbol.observable');\n } else {\n return obs.subscribe(subscriber);\n }\n};\n","import { Subscriber } from '../Subscriber';\nimport { hostReportError } from './hostReportError';\n\nexport const subscribeToPromise = (promise: PromiseLike) => (subscriber: Subscriber) => {\n promise.then(\n (value) => {\n if (!subscriber.closed) {\n subscriber.next(value);\n subscriber.complete();\n }\n },\n (err: any) => subscriber.error(err)\n )\n .then(null, hostReportError);\n return subscriber;\n};\n","import { Subscriber } from '../Subscriber';\nimport { iterator as Symbol_iterator } from '../symbol/iterator';\n\nexport const subscribeToIterable = (iterable: Iterable) => (subscriber: Subscriber) => {\n const iterator = (iterable as any)[Symbol_iterator]();\n\n do {\n let item: IteratorResult;\n try {\n item = iterator.next();\n } catch (err) {\n subscriber.error(err);\n return subscriber;\n }\n if (item.done) {\n subscriber.complete();\n break;\n }\n subscriber.next(item.value);\n if (subscriber.closed) {\n break;\n }\n } while (true);\n\n // Finalize the iterator if it happens to be a Generator\n if (typeof iterator.return === 'function') {\n subscriber.add(() => {\n if (iterator.return) {\n iterator.return();\n }\n });\n }\n\n return subscriber;\n};\n","/** @prettier */\nimport { Subscription } from './Subscription';\nimport { Subscriber } from './Subscriber';\nimport { Observable } from './Observable';\nimport { subscribeTo } from './util/subscribeTo';\n\ninterface SimpleOuterSubscriberLike {\n /**\n * A handler for inner next notifications from the inner subscription\n * @param innerValue the value nexted by the inner producer\n */\n notifyNext(innerValue: T): void;\n /**\n * A handler for inner error notifications from the inner subscription\n * @param err the error from the inner producer\n */\n notifyError(err: any): void;\n /**\n * A handler for inner complete notifications from the inner subscription.\n */\n notifyComplete(): void;\n}\n\nexport class SimpleInnerSubscriber extends Subscriber {\n constructor(private parent: SimpleOuterSubscriberLike) {\n super();\n }\n\n protected _next(value: T): void {\n this.parent.notifyNext(value);\n }\n\n protected _error(error: any): void {\n this.parent.notifyError(error);\n this.unsubscribe();\n }\n\n protected _complete(): void {\n this.parent.notifyComplete();\n this.unsubscribe();\n }\n}\n\nexport class ComplexInnerSubscriber extends Subscriber {\n constructor(private parent: ComplexOuterSubscriber, public outerValue: T, public outerIndex: number) {\n super();\n }\n\n protected _next(value: R): void {\n this.parent.notifyNext(this.outerValue, value, this.outerIndex, this);\n }\n\n protected _error(error: any): void {\n this.parent.notifyError(error);\n this.unsubscribe();\n }\n\n protected _complete(): void {\n this.parent.notifyComplete(this);\n this.unsubscribe();\n }\n}\n\nexport class SimpleOuterSubscriber extends Subscriber implements SimpleOuterSubscriberLike {\n notifyNext(innerValue: R): void {\n this.destination.next(innerValue);\n }\n\n notifyError(err: any): void {\n this.destination.error(err);\n }\n\n notifyComplete(): void {\n this.destination.complete();\n }\n}\n\n/**\n * DO NOT USE (formerly \"OuterSubscriber\")\n * TODO: We want to refactor this and remove it. It is retaining values it shouldn't for long\n * periods of time.\n */\nexport class ComplexOuterSubscriber extends Subscriber {\n /**\n * @param _outerValue Used by: bufferToggle, delayWhen, windowToggle\n * @param innerValue Used by: subclass default, combineLatest, race, bufferToggle, windowToggle, withLatestFrom\n * @param _outerIndex Used by: combineLatest, race, withLatestFrom\n * @param _innerSub Used by: delayWhen\n */\n notifyNext(_outerValue: T, innerValue: R, _outerIndex: number, _innerSub: ComplexInnerSubscriber): void {\n this.destination.next(innerValue);\n }\n\n notifyError(error: any): void {\n this.destination.error(error);\n }\n\n /**\n * @param _innerSub Used by: race, bufferToggle, delayWhen, windowToggle, windowWhen\n */\n notifyComplete(_innerSub: ComplexInnerSubscriber): void {\n this.destination.complete();\n }\n}\n\nexport function innerSubscribe(result: any, innerSubscriber: Subscriber): Subscription | undefined {\n if (innerSubscriber.closed) {\n return undefined;\n }\n if (result instanceof Observable) {\n return result.subscribe(innerSubscriber);\n }\n let subscription: Subscription;\n try {\n subscription = subscribeTo(result)(innerSubscriber) as Subscription;\n } catch (error) {\n innerSubscriber.error(error);\n }\n return subscription;\n}\n","import { SchedulerLike } from '../types';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && typeof (value).schedule === 'function';\n}\n","import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\nimport { Subscription } from '../Subscription';\n\nexport function scheduleArray(input: ArrayLike, scheduler: SchedulerLike) {\n return new Observable(subscriber => {\n const sub = new Subscription();\n let i = 0;\n sub.add(scheduler.schedule(function () {\n if (i === input.length) {\n subscriber.complete();\n return;\n }\n subscriber.next(input[i++]);\n if (!subscriber.closed) {\n sub.add(this.schedule());\n }\n }));\n return sub;\n });\n}\n","import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\nimport { subscribeToArray } from '../util/subscribeToArray';\nimport { scheduleArray } from '../scheduled/scheduleArray';\n\nexport function fromArray(input: ArrayLike, scheduler?: SchedulerLike) {\n if (!scheduler) {\n return new Observable(subscribeToArray(input));\n } else {\n return scheduleArray(input, scheduler);\n }\n}\n","import { scheduleObservable } from './scheduleObservable';\nimport { schedulePromise } from './schedulePromise';\nimport { scheduleArray } from './scheduleArray';\nimport { scheduleIterable } from './scheduleIterable';\nimport { ObservableInput, SchedulerLike, Observable } from 'rxjs';\nimport { isInteropObservable } from '../util/isInteropObservable';\nimport { isPromise } from '../util/isPromise';\nimport { isArrayLike } from '../util/isArrayLike';\nimport { isIterable } from '../util/isIterable';\n\n/**\n * Converts from a common {@link ObservableInput} type to an observable where subscription and emissions\n * are scheduled on the provided scheduler.\n *\n * @see from\n * @see of\n *\n * @param input The observable, array, promise, iterable, etc you would like to schedule\n * @param scheduler The scheduler to use to schedule the subscription and emissions from\n * the returned observable.\n */\nexport function scheduled(input: ObservableInput, scheduler: SchedulerLike): Observable {\n if (input != null) {\n if (isInteropObservable(input)) {\n return scheduleObservable(input, scheduler);\n } else if (isPromise(input)) {\n return schedulePromise(input, scheduler);\n } else if (isArrayLike(input)) {\n return scheduleArray(input, scheduler);\n } else if (isIterable(input) || typeof input === 'string') {\n return scheduleIterable(input, scheduler);\n }\n }\n\n throw new TypeError((input !== null && typeof input || input) + ' is not observable');\n}\n","import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return input && typeof input[Symbol_observable] === 'function';\n}\n","import { Observable } from '../Observable';\nimport { Subscription } from '../Subscription';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { InteropObservable, SchedulerLike, Subscribable } from '../types';\n\nexport function scheduleObservable(input: InteropObservable, scheduler: SchedulerLike) {\n return new Observable(subscriber => {\n const sub = new Subscription();\n sub.add(scheduler.schedule(() => {\n const observable: Subscribable = input[Symbol_observable]();\n sub.add(observable.subscribe({\n next(value) { sub.add(scheduler.schedule(() => subscriber.next(value))); },\n error(err) { sub.add(scheduler.schedule(() => subscriber.error(err))); },\n complete() { sub.add(scheduler.schedule(() => subscriber.complete())); },\n }));\n }));\n return sub;\n });\n}\n","import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\nimport { Subscription } from '../Subscription';\n\nexport function schedulePromise(input: PromiseLike, scheduler: SchedulerLike) {\n return new Observable(subscriber => {\n const sub = new Subscription();\n sub.add(scheduler.schedule(() => input.then(\n value => {\n sub.add(scheduler.schedule(() => {\n subscriber.next(value);\n sub.add(scheduler.schedule(() => subscriber.complete()));\n }));\n },\n err => {\n sub.add(scheduler.schedule(() => subscriber.error(err)));\n }\n )));\n return sub;\n });\n}\n","import { iterator as Symbol_iterator } from '../symbol/iterator';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return input && typeof input[Symbol_iterator] === 'function';\n}\n","import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\nimport { Subscription } from '../Subscription';\nimport { iterator as Symbol_iterator } from '../symbol/iterator';\n\nexport function scheduleIterable(input: Iterable, scheduler: SchedulerLike) {\n if (!input) {\n throw new Error('Iterable cannot be null');\n }\n return new Observable(subscriber => {\n const sub = new Subscription();\n let iterator: Iterator;\n sub.add(() => {\n // Finalize generators\n if (iterator && typeof iterator.return === 'function') {\n iterator.return();\n }\n });\n sub.add(scheduler.schedule(() => {\n iterator = input[Symbol_iterator]();\n sub.add(scheduler.schedule(function () {\n if (subscriber.closed) {\n return;\n }\n let value: T;\n let done: boolean;\n try {\n const result = iterator.next();\n value = result.value;\n done = result.done;\n } catch (err) {\n subscriber.error(err);\n return;\n }\n if (done) {\n subscriber.complete();\n } else {\n subscriber.next(value);\n this.schedule();\n }\n }));\n }));\n return sub;\n });\n}\n","import { Observable } from '../Observable';\nimport { subscribeTo } from '../util/subscribeTo';\nimport { ObservableInput, SchedulerLike, ObservedValueOf } from '../types';\nimport { scheduled } from '../scheduled/scheduled';\n\nexport function from>(input: O): Observable>;\n/** @deprecated use {@link scheduled} instead. */\nexport function from>(input: O, scheduler: SchedulerLike): Observable>;\n\n/**\n * Creates an Observable from an Array, an array-like object, a Promise, an iterable object, or an Observable-like object.\n *\n * Converts almost anything to an Observable.\n *\n * ![](from.png)\n *\n * `from` converts various other objects and data types into Observables. It also converts a Promise, an array-like, or an\n * iterable\n * object into an Observable that emits the items in that promise, array, or iterable. A String, in this context, is treated\n * as an array of characters. Observable-like objects (contains a function named with the ES2015 Symbol for Observable) can also be\n * converted through this operator.\n *\n * ## Examples\n *\n * ### Converts an array to an Observable\n *\n * ```ts\n * import { from } from 'rxjs';\n *\n * const array = [10, 20, 30];\n * const result = from(array);\n *\n * result.subscribe(x => console.log(x));\n *\n * // Logs:\n * // 10\n * // 20\n * // 30\n * ```\n *\n * ---\n *\n * ### Convert an infinite iterable (from a generator) to an Observable\n *\n * ```ts\n * import { from } from 'rxjs';\n * import { take } from 'rxjs/operators';\n *\n * function* generateDoubles(seed) {\n * let i = seed;\n * while (true) {\n * yield i;\n * i = 2 * i; // double it\n * }\n * }\n *\n * const iterator = generateDoubles(3);\n * const result = from(iterator).pipe(take(10));\n *\n * result.subscribe(x => console.log(x));\n *\n * // Logs:\n * // 3\n * // 6\n * // 12\n * // 24\n * // 48\n * // 96\n * // 192\n * // 384\n * // 768\n * // 1536\n * ```\n *\n * ---\n *\n * ### With async scheduler\n *\n * ```ts\n * import { from, asyncScheduler } from 'rxjs';\n *\n * console.log('start');\n *\n * const array = [10, 20, 30];\n * const result = from(array, asyncScheduler);\n *\n * result.subscribe(x => console.log(x));\n *\n * console.log('end');\n *\n * // Logs:\n * // start\n * // end\n * // 10\n * // 20\n * // 30\n * ```\n *\n * @see {@link fromEvent}\n * @see {@link fromEventPattern}\n *\n * @param {ObservableInput} A subscription object, a Promise, an Observable-like,\n * an Array, an iterable, or an array-like object to be converted.\n * @param {SchedulerLike} An optional {@link SchedulerLike} on which to schedule the emission of values.\n * @return {Observable}\n * @name from\n * @owner Observable\n */\nexport function from(input: ObservableInput, scheduler?: SchedulerLike): Observable {\n if (!scheduler) {\n if (input instanceof Observable) {\n return input;\n }\n return new Observable(subscribeTo(input));\n } else {\n return scheduled(input, scheduler);\n }\n}\n","import { Operator } from '../Operator';\nimport { Subscriber } from '../Subscriber';\nimport { Observable } from '../Observable';\nimport { OperatorFunction } from '../types';\n\n/**\n * Applies a given `project` function to each value emitted by the source\n * Observable, and emits the resulting values as an Observable.\n *\n * Like [Array.prototype.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map),\n * it passes each source value through a transformation function to get\n * corresponding output values.\n *\n * ![](map.png)\n *\n * Similar to the well known `Array.prototype.map` function, this operator\n * applies a projection to each value and emits that projection in the output\n * Observable.\n *\n * ## Example\n * Map every click to the clientX position of that click\n * ```ts\n * import { fromEvent } from 'rxjs';\n * import { map } from 'rxjs/operators';\n *\n * const clicks = fromEvent(document, 'click');\n * const positions = clicks.pipe(map(ev => ev.clientX));\n * positions.subscribe(x => console.log(x));\n * ```\n *\n * @see {@link mapTo}\n * @see {@link pluck}\n *\n * @param {function(value: T, index: number): R} project The function to apply\n * to each `value` emitted by the source Observable. The `index` parameter is\n * the number `i` for the i-th emission that has happened since the\n * subscription, starting from the number `0`.\n * @param {any} [thisArg] An optional argument to define what `this` is in the\n * `project` function.\n * @return {Observable} An Observable that emits the values from the source\n * Observable transformed by the given `project` function.\n * @method map\n * @owner Observable\n */\nexport function map(project: (value: T, index: number) => R, thisArg?: any): OperatorFunction {\n return function mapOperation(source: Observable): Observable {\n if (typeof project !== 'function') {\n throw new TypeError('argument is not a function. Are you looking for `mapTo()`?');\n }\n return source.lift(new MapOperator(project, thisArg));\n };\n}\n\nexport class MapOperator implements Operator {\n constructor(private project: (value: T, index: number) => R, private thisArg: any) {\n }\n\n call(subscriber: Subscriber, source: any): any {\n return source.subscribe(new MapSubscriber(subscriber, this.project, this.thisArg));\n }\n}\n\n/**\n * We need this JSDoc comment for affecting ESDoc.\n * @ignore\n * @extends {Ignored}\n */\nclass MapSubscriber extends Subscriber {\n count: number = 0;\n private thisArg: any;\n\n constructor(destination: Subscriber,\n private project: (value: T, index: number) => R,\n thisArg: any) {\n super(destination);\n this.thisArg = thisArg || this;\n }\n\n // NOTE: This looks unoptimized, but it's actually purposefully NOT\n // using try/catch optimizations.\n protected _next(value: T) {\n let result: R;\n try {\n result = this.project.call(this.thisArg, value, this.count++);\n } catch (err) {\n this.destination.error(err);\n return;\n }\n this.destination.next(result);\n }\n}\n","import { Observable } from '../Observable';\nimport { Operator } from '../Operator';\nimport { Subscriber } from '../Subscriber';\nimport { Subscription } from '../Subscription';\nimport { ObservableInput, OperatorFunction, ObservedValueOf } from '../types';\nimport { map } from './map';\nimport { from } from '../observable/from';\nimport { SimpleOuterSubscriber, SimpleInnerSubscriber, innerSubscribe } from '../innerSubscribe';\n\n/* tslint:disable:max-line-length */\nexport function mergeMap>(project: (value: T, index: number) => O, concurrent?: number): OperatorFunction>;\n/** @deprecated resultSelector no longer supported, use inner map instead */\nexport function mergeMap>(project: (value: T, index: number) => O, resultSelector: undefined, concurrent?: number): OperatorFunction>;\n/** @deprecated resultSelector no longer supported, use inner map instead */\nexport function mergeMap>(project: (value: T, index: number) => O, resultSelector: (outerValue: T, innerValue: ObservedValueOf, outerIndex: number, innerIndex: number) => R, concurrent?: number): OperatorFunction;\n/* tslint:enable:max-line-length */\n\n/**\n * Projects each source value to an Observable which is merged in the output\n * Observable.\n *\n * Maps each value to an Observable, then flattens all of\n * these inner Observables using {@link mergeAll}.\n *\n * ![](mergeMap.png)\n *\n * Returns an Observable that emits items based on applying a function that you\n * supply to each item emitted by the source Observable, where that function\n * returns an Observable, and then merging those resulting Observables and\n * emitting the results of this merger.\n *\n * ## Example\n * Map and flatten each letter to an Observable ticking every 1 second\n * ```ts\n * import { of, interval } from 'rxjs';\n * import { mergeMap, map } from 'rxjs/operators';\n *\n * const letters = of('a', 'b', 'c');\n * const result = letters.pipe(\n * mergeMap(x => interval(1000).pipe(map(i => x+i))),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following:\n * // a0\n * // b0\n * // c0\n * // a1\n * // b1\n * // c1\n * // continues to list a,b,c with respective ascending integers\n * ```\n *\n * @see {@link concatMap}\n * @see {@link exhaustMap}\n * @see {@link merge}\n * @see {@link mergeAll}\n * @see {@link mergeMapTo}\n * @see {@link mergeScan}\n * @see {@link switchMap}\n *\n * @param {function(value: T, ?index: number): ObservableInput} project A function\n * that, when applied to an item emitted by the source Observable, returns an\n * Observable.\n * @param {number} [concurrent=Number.POSITIVE_INFINITY] Maximum number of input\n * Observables being subscribed to concurrently.\n * @return {Observable} An Observable that emits the result of applying the\n * projection function (and the optional deprecated `resultSelector`) to each item\n * emitted by the source Observable and merging the results of the Observables\n * obtained from this transformation.\n */\nexport function mergeMap>(\n project: (value: T, index: number) => O,\n resultSelector?: ((outerValue: T, innerValue: ObservedValueOf, outerIndex: number, innerIndex: number) => R) | number,\n concurrent: number = Number.POSITIVE_INFINITY\n): OperatorFunction|R> {\n if (typeof resultSelector === 'function') {\n // DEPRECATED PATH\n return (source: Observable) => source.pipe(\n mergeMap((a, i) => from(project(a, i)).pipe(\n map((b: any, ii: number) => resultSelector(a, b, i, ii)),\n ), concurrent)\n );\n } else if (typeof resultSelector === 'number') {\n concurrent = resultSelector;\n }\n return (source: Observable) => source.lift(new MergeMapOperator(project, concurrent));\n}\n\nexport class MergeMapOperator implements Operator {\n constructor(private project: (value: T, index: number) => ObservableInput,\n private concurrent: number = Number.POSITIVE_INFINITY) {\n }\n\n call(observer: Subscriber, source: any): any {\n return source.subscribe(new MergeMapSubscriber(\n observer, this.project, this.concurrent\n ));\n }\n}\n\n/**\n * We need this JSDoc comment for affecting ESDoc.\n * @ignore\n * @extends {Ignored}\n */\nexport class MergeMapSubscriber extends SimpleOuterSubscriber {\n private hasCompleted: boolean = false;\n private buffer: T[] = [];\n private active: number = 0;\n protected index: number = 0;\n\n constructor(destination: Subscriber,\n private project: (value: T, index: number) => ObservableInput,\n private concurrent: number = Number.POSITIVE_INFINITY) {\n super(destination);\n }\n\n protected _next(value: T): void {\n if (this.active < this.concurrent) {\n this._tryNext(value);\n } else {\n this.buffer.push(value);\n }\n }\n\n protected _tryNext(value: T) {\n let result: ObservableInput;\n const index = this.index++;\n try {\n result = this.project(value, index);\n } catch (err) {\n this.destination.error!(err);\n return;\n }\n this.active++;\n this._innerSub(result);\n }\n\n private _innerSub(ish: ObservableInput): void {\n const innerSubscriber = new SimpleInnerSubscriber(this);\n const destination = this.destination as Subscription;\n destination.add(innerSubscriber);\n const innerSubscription = innerSubscribe(ish, innerSubscriber);\n // The returned subscription will usually be the subscriber that was\n // passed. However, interop subscribers will be wrapped and for\n // unsubscriptions to chain correctly, the wrapper needs to be added, too.\n if (innerSubscription !== innerSubscriber) {\n destination.add(innerSubscription);\n }\n }\n\n protected _complete(): void {\n this.hasCompleted = true;\n if (this.active === 0 && this.buffer.length === 0) {\n this.destination.complete!();\n }\n this.unsubscribe();\n }\n\n notifyNext(innerValue: R): void {\n this.destination.next!(innerValue);\n }\n\n notifyComplete(): void {\n const buffer = this.buffer;\n this.active--;\n if (buffer.length > 0) {\n this._next(buffer.shift()!);\n } else if (this.active === 0 && this.hasCompleted) {\n this.destination.complete!();\n }\n }\n}\n\n/**\n * @deprecated renamed. Use {@link mergeMap}\n */\nexport const flatMap = mergeMap;","\nimport { mergeMap } from './mergeMap';\nimport { identity } from '../util/identity';\nimport { OperatorFunction, ObservableInput } from '../types';\n\n/**\n * Converts a higher-order Observable into a first-order Observable which\n * concurrently delivers all values that are emitted on the inner Observables.\n *\n * Flattens an Observable-of-Observables.\n *\n * ![](mergeAll.png)\n *\n * `mergeAll` subscribes to an Observable that emits Observables, also known as\n * a higher-order Observable. Each time it observes one of these emitted inner\n * Observables, it subscribes to that and delivers all the values from the\n * inner Observable on the output Observable. The output Observable only\n * completes once all inner Observables have completed. Any error delivered by\n * a inner Observable will be immediately emitted on the output Observable.\n *\n * ## Examples\n * Spawn a new interval Observable for each click event, and blend their outputs as one Observable\n * ```ts\n * import { fromEvent, interval } from 'rxjs';\n * import { map, mergeAll } from 'rxjs/operators';\n *\n * const clicks = fromEvent(document, 'click');\n * const higherOrder = clicks.pipe(map((ev) => interval(1000)));\n * const firstOrder = higherOrder.pipe(mergeAll());\n * firstOrder.subscribe(x => console.log(x));\n * ```\n *\n * Count from 0 to 9 every second for each click, but only allow 2 concurrent timers\n * ```ts\n * import { fromEvent, interval } from 'rxjs';\n * import { take, map, mergeAll } from 'rxjs/operators';\n *\n * const clicks = fromEvent(document, 'click');\n * const higherOrder = clicks.pipe(\n * map((ev) => interval(1000).pipe(take(10))),\n * );\n * const firstOrder = higherOrder.pipe(mergeAll(2));\n * firstOrder.subscribe(x => console.log(x));\n * ```\n *\n * @see {@link combineAll}\n * @see {@link concatAll}\n * @see {@link exhaust}\n * @see {@link merge}\n * @see {@link mergeMap}\n * @see {@link mergeMapTo}\n * @see {@link mergeScan}\n * @see {@link switchAll}\n * @see {@link switchMap}\n * @see {@link zipAll}\n *\n * @param {number} [concurrent=Number.POSITIVE_INFINITY] Maximum number of inner\n * Observables being subscribed to concurrently.\n * @return {Observable} An Observable that emits values coming from all the\n * inner Observables emitted by the source Observable.\n * @method mergeAll\n * @owner Observable\n */\nexport function mergeAll(concurrent: number = Number.POSITIVE_INFINITY): OperatorFunction, T> {\n return mergeMap(identity, concurrent);\n}\n","import { Operator } from '../Operator';\nimport { Subscriber } from '../Subscriber';\nimport { Observable } from '../Observable';\nimport { MonoTypeOperatorFunction, TeardownLogic } from '../types';\n\n/* tslint:disable:max-line-length */\nexport function distinctUntilChanged(compare?: (x: T, y: T) => boolean): MonoTypeOperatorFunction;\nexport function distinctUntilChanged(compare: (x: K, y: K) => boolean, keySelector: (x: T) => K): MonoTypeOperatorFunction;\n/* tslint:enable:max-line-length */\n\n/**\n * Returns an Observable that emits all items emitted by the source Observable that are distinct by comparison from the previous item.\n *\n * If a comparator function is provided, then it will be called for each item to test for whether or not that value should be emitted.\n *\n * If a comparator function is not provided, an equality check is used by default.\n *\n * ## Example\n * A simple example with numbers\n * ```ts\n * import { of } from 'rxjs';\n * import { distinctUntilChanged } from 'rxjs/operators';\n *\n * of(1, 1, 2, 2, 2, 1, 1, 2, 3, 3, 4).pipe(\n * distinctUntilChanged(),\n * )\n * .subscribe(x => console.log(x)); // 1, 2, 1, 2, 3, 4\n * ```\n *\n * An example using a compare function\n * ```typescript\n * import { of } from 'rxjs';\n * import { distinctUntilChanged } from 'rxjs/operators';\n *\n * interface Person {\n * age: number,\n * name: string\n * }\n *\n * of(\n * { age: 4, name: 'Foo'},\n * { age: 7, name: 'Bar'},\n * { age: 5, name: 'Foo'},\n * { age: 6, name: 'Foo'},\n * ).pipe(\n * distinctUntilChanged((p: Person, q: Person) => p.name === q.name),\n * )\n * .subscribe(x => console.log(x));\n *\n * // displays:\n * // { age: 4, name: 'Foo' }\n * // { age: 7, name: 'Bar' }\n * // { age: 5, name: 'Foo' }\n * ```\n *\n * @see {@link distinct}\n * @see {@link distinctUntilKeyChanged}\n *\n * @param {function} [compare] Optional comparison function called to test if an item is distinct from the previous item in the source.\n * @return {Observable} An Observable that emits items from the source Observable with distinct values.\n * @method distinctUntilChanged\n * @owner Observable\n */\nexport function distinctUntilChanged(compare?: (x: K, y: K) => boolean, keySelector?: (x: T) => K): MonoTypeOperatorFunction {\n return (source: Observable) => source.lift(new DistinctUntilChangedOperator(compare, keySelector));\n}\n\nclass DistinctUntilChangedOperator implements Operator {\n constructor(private compare: (x: K, y: K) => boolean,\n private keySelector: (x: T) => K) {\n }\n\n call(subscriber: Subscriber, source: any): TeardownLogic {\n return source.subscribe(new DistinctUntilChangedSubscriber(subscriber, this.compare, this.keySelector));\n }\n}\n\n/**\n * We need this JSDoc comment for affecting ESDoc.\n * @ignore\n * @extends {Ignored}\n */\nclass DistinctUntilChangedSubscriber extends Subscriber {\n private key: K;\n private hasKey: boolean = false;\n\n constructor(destination: Subscriber,\n compare: (x: K, y: K) => boolean,\n private keySelector: (x: T) => K) {\n super(destination);\n if (typeof compare === 'function') {\n this.compare = compare;\n }\n }\n\n private compare(x: any, y: any): boolean {\n return x === y;\n }\n\n protected _next(value: T): void {\n let key: any;\n try {\n const { keySelector } = this;\n key = keySelector ? keySelector(value) : value;\n } catch (err) {\n return this.destination.error(err);\n }\n let result = false;\n if (this.hasKey) {\n try {\n const { compare } = this;\n result = compare(this.key, key);\n } catch (err) {\n return this.destination.error(err);\n }\n } else {\n this.hasKey = true;\n }\n if (!result) {\n this.key = key;\n this.destination.next(value);\n }\n }\n}\n","export interface ObjectUnsubscribedError extends Error {\n}\n\nexport interface ObjectUnsubscribedErrorCtor {\n new(): ObjectUnsubscribedError;\n}\n\nconst ObjectUnsubscribedErrorImpl = (() => {\n function ObjectUnsubscribedErrorImpl(this: any) {\n Error.call(this);\n this.message = 'object unsubscribed';\n this.name = 'ObjectUnsubscribedError';\n return this;\n }\n\n ObjectUnsubscribedErrorImpl.prototype = Object.create(Error.prototype);\n\n return ObjectUnsubscribedErrorImpl;\n})();\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = ObjectUnsubscribedErrorImpl as any;","import { Subject } from './Subject';\nimport { Observer } from './types';\nimport { Subscription } from './Subscription';\n\n/**\n * We need this JSDoc comment for affecting ESDoc.\n * @ignore\n * @extends {Ignored}\n */\nexport class SubjectSubscription extends Subscription {\n closed: boolean = false;\n\n constructor(public subject: Subject, public subscriber: Observer) {\n super();\n }\n\n unsubscribe() {\n if (this.closed) {\n return;\n }\n\n this.closed = true;\n\n const subject = this.subject;\n const observers = subject.observers;\n\n this.subject = null;\n\n if (!observers || observers.length === 0 || subject.isStopped || subject.closed) {\n return;\n }\n\n const subscriberIndex = observers.indexOf(this.subscriber);\n\n if (subscriberIndex !== -1) {\n observers.splice(subscriberIndex, 1);\n }\n }\n}\n","import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { SubjectSubscription } from './SubjectSubscription';\nimport { rxSubscriber as rxSubscriberSymbol } from '../internal/symbol/rxSubscriber';\n\n/**\n * @class SubjectSubscriber\n */\nexport class SubjectSubscriber extends Subscriber {\n constructor(protected destination: Subject) {\n super(destination);\n }\n}\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n *\n * @class Subject\n */\nexport class Subject extends Observable implements SubscriptionLike {\n\n [rxSubscriberSymbol]() {\n return new SubjectSubscriber(this);\n }\n\n observers: Observer[] = [];\n\n closed = false;\n\n isStopped = false;\n\n hasError = false;\n\n thrownError: any = null;\n\n constructor() {\n super();\n }\n\n /**@nocollapse\n * @deprecated use new Subject() instead\n */\n static create: Function = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n }\n\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator;\n return subject;\n }\n\n next(value?: T) {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n if (!this.isStopped) {\n const { observers } = this;\n const len = observers.length;\n const copy = observers.slice();\n for (let i = 0; i < len; i++) {\n copy[i].next(value);\n }\n }\n }\n\n error(err: any) {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n this.hasError = true;\n this.thrownError = err;\n this.isStopped = true;\n const { observers } = this;\n const len = observers.length;\n const copy = observers.slice();\n for (let i = 0; i < len; i++) {\n copy[i].error(err);\n }\n this.observers.length = 0;\n }\n\n complete() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n this.isStopped = true;\n const { observers } = this;\n const len = observers.length;\n const copy = observers.slice();\n for (let i = 0; i < len; i++) {\n copy[i].complete();\n }\n this.observers.length = 0;\n }\n\n unsubscribe() {\n this.isStopped = true;\n this.closed = true;\n this.observers = null;\n }\n\n /** @deprecated This is an internal implementation detail, do not use. */\n _trySubscribe(subscriber: Subscriber): TeardownLogic {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n } else {\n return super._trySubscribe(subscriber);\n }\n }\n\n /** @deprecated This is an internal implementation detail, do not use. */\n _subscribe(subscriber: Subscriber): Subscription {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n } else if (this.hasError) {\n subscriber.error(this.thrownError);\n return Subscription.EMPTY;\n } else if (this.isStopped) {\n subscriber.complete();\n return Subscription.EMPTY;\n } else {\n this.observers.push(subscriber);\n return new SubjectSubscription(this, subscriber);\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create customize Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return {Observable} Observable that the Subject casts to\n */\n asObservable(): Observable {\n const observable = new Observable();\n (observable).source = this;\n return observable;\n }\n}\n\n/**\n * @class AnonymousSubject\n */\nexport class AnonymousSubject extends Subject {\n constructor(protected destination?: Observer, source?: Observable) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n const { destination } = this;\n if (destination && destination.next) {\n destination.next(value);\n }\n }\n\n error(err: any) {\n const { destination } = this;\n if (destination && destination.error) {\n this.destination.error(err);\n }\n }\n\n complete() {\n const { destination } = this;\n if (destination && destination.complete) {\n this.destination.complete();\n }\n }\n\n /** @deprecated This is an internal implementation detail, do not use. */\n _subscribe(subscriber: Subscriber): Subscription {\n const { source } = this;\n if (source) {\n return this.source.subscribe(subscriber);\n } else {\n return Subscription.EMPTY;\n }\n }\n}\n","import { Operator } from '../Operator';\nimport { Subscriber } from '../Subscriber';\nimport { Observable } from '../Observable';\nimport { OperatorFunction } from '../types';\n\n/**\n * Emits the given constant value on the output Observable every time the source\n * Observable emits a value.\n *\n * Like {@link map}, but it maps every source value to\n * the same output value every time.\n *\n * ![](mapTo.png)\n *\n * Takes a constant `value` as argument, and emits that whenever the source\n * Observable emits a value. In other words, ignores the actual source value,\n * and simply uses the emission moment to know when to emit the given `value`.\n *\n * ## Example\n * Map every click to the string 'Hi'\n * ```ts\n * import { fromEvent } from 'rxjs';\n * import { mapTo } from 'rxjs/operators';\n *\n * const clicks = fromEvent(document, 'click');\n * const greetings = clicks.pipe(mapTo('Hi'));\n * greetings.subscribe(x => console.log(x));\n * ```\n *\n * @see {@link map}\n *\n * @param {any} value The value to map each source value to.\n * @return {Observable} An Observable that emits the given `value` every time\n * the source Observable emits something.\n * @method mapTo\n * @owner Observable\n */\nexport function mapTo(value: R): OperatorFunction {\n return (source: Observable) => source.lift(new MapToOperator(value));\n}\n\nclass MapToOperator implements Operator {\n\n value: R;\n\n constructor(value: R) {\n this.value = value;\n }\n\n call(subscriber: Subscriber, source: any): any {\n return source.subscribe(new MapToSubscriber(subscriber, this.value));\n }\n}\n\n/**\n * We need this JSDoc comment for affecting ESDoc.\n * @ignore\n * @extends {Ignored}\n */\nclass MapToSubscriber extends Subscriber {\n\n value: R;\n\n constructor(destination: Subscriber, value: R) {\n super(destination);\n this.value = value;\n }\n\n protected _next(x: T) {\n this.destination.next(this.value);\n }\n}\n","export enum StickyFormats {\n\tFLYING = 'flying',\n\tBANNER = 'banner'\n}\n","import { Subject } from './Subject';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { SubscriptionLike } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\n\n/**\n * A variant of Subject that requires an initial value and emits its current\n * value whenever it is subscribed to.\n *\n * @class BehaviorSubject\n */\nexport class BehaviorSubject extends Subject {\n\n constructor(private _value: T) {\n super();\n }\n\n get value(): T {\n return this.getValue();\n }\n\n /** @deprecated This is an internal implementation detail, do not use. */\n _subscribe(subscriber: Subscriber): Subscription {\n const subscription = super._subscribe(subscriber);\n if (subscription && !(subscription).closed) {\n subscriber.next(this._value);\n }\n return subscription;\n }\n\n getValue(): T {\n if (this.hasError) {\n throw this.thrownError;\n } else if (this.closed) {\n throw new ObjectUnsubscribedError();\n } else {\n return this._value;\n }\n }\n\n next(value: T): void {\n super.next(this._value = value);\n }\n}\n","function createElement (query, ns) {\n var ref = parse(query);\n var tag = ref.tag;\n var id = ref.id;\n var className = ref.className;\n var element = ns ? document.createElementNS(ns, tag) : document.createElement(tag);\n\n if (id) {\n element.id = id;\n }\n\n if (className) {\n if (ns) {\n element.setAttribute('class', className);\n } else {\n element.className = className;\n }\n }\n\n return element;\n}\n\nfunction parse (query) {\n var chunks = query.split(/([.#])/);\n var className = '';\n var id = '';\n\n for (var i = 1; i < chunks.length; i += 2) {\n switch (chunks[i]) {\n case '.':\n className += \" \" + (chunks[i + 1]);\n break;\n\n case '#':\n id = chunks[i + 1];\n }\n }\n\n return {\n className: className.trim(),\n tag: chunks[0] || 'div',\n id: id\n };\n}\n\nfunction unmount (parent, child) {\n var parentEl = getEl(parent);\n var childEl = getEl(child);\n\n if (child === childEl && childEl.__redom_view) {\n // try to look up the view if not provided\n child = childEl.__redom_view;\n }\n\n if (childEl.parentNode) {\n doUnmount(child, childEl, parentEl);\n\n parentEl.removeChild(childEl);\n }\n\n return child;\n}\n\nfunction doUnmount (child, childEl, parentEl) {\n var hooks = childEl.__redom_lifecycle;\n\n if (hooksAreEmpty(hooks)) {\n childEl.__redom_lifecycle = {};\n return;\n }\n\n var traverse = parentEl;\n\n if (childEl.__redom_mounted) {\n trigger(childEl, 'onunmount');\n }\n\n while (traverse) {\n var parentHooks = traverse.__redom_lifecycle || {};\n\n for (var hook in hooks) {\n if (parentHooks[hook]) {\n parentHooks[hook] -= hooks[hook];\n }\n }\n\n if (hooksAreEmpty(parentHooks)) {\n traverse.__redom_lifecycle = null;\n }\n\n traverse = traverse.parentNode;\n }\n}\n\nfunction hooksAreEmpty (hooks) {\n if (hooks == null) {\n return true;\n }\n for (var key in hooks) {\n if (hooks[key]) {\n return false;\n }\n }\n return true;\n}\n\n/* global Node, ShadowRoot */\n\nvar hookNames = ['onmount', 'onremount', 'onunmount'];\nvar shadowRootAvailable = typeof window !== 'undefined' && 'ShadowRoot' in window;\n\nfunction mount (parent, child, before, replace) {\n var parentEl = getEl(parent);\n var childEl = getEl(child);\n\n if (child === childEl && childEl.__redom_view) {\n // try to look up the view if not provided\n child = childEl.__redom_view;\n }\n\n if (child !== childEl) {\n childEl.__redom_view = child;\n }\n\n var wasMounted = childEl.__redom_mounted;\n var oldParent = childEl.parentNode;\n\n if (wasMounted && (oldParent !== parentEl)) {\n doUnmount(child, childEl, oldParent);\n }\n\n if (before != null) {\n if (replace) {\n var beforeEl = getEl(before);\n\n if (beforeEl.__redom_mounted) {\n trigger(before.el, 'onunmount');\n }\n\n parentEl.replaceChild(childEl, beforeEl);\n } else {\n parentEl.insertBefore(childEl, getEl(before));\n }\n } else {\n parentEl.appendChild(childEl);\n }\n\n doMount(child, childEl, parentEl, oldParent);\n\n return child;\n}\n\nfunction trigger (el, eventName) {\n if (eventName === 'onmount' || eventName === 'onremount') {\n el.__redom_mounted = true;\n } else if (eventName === 'onunmount') {\n el.__redom_mounted = false;\n }\n\n var hooks = el.__redom_lifecycle;\n\n if (!hooks) {\n return;\n }\n\n var view = el.__redom_view;\n var hookCount = 0;\n\n view && view[eventName] && view[eventName]();\n\n for (var hook in hooks) {\n if (hook) {\n hookCount++;\n }\n }\n\n if (hookCount) {\n var traverse = el.firstChild;\n\n while (traverse) {\n var next = traverse.nextSibling;\n\n trigger(traverse, eventName);\n\n traverse = next;\n }\n }\n}\n\nfunction doMount (child, childEl, parentEl, oldParent) {\n var hooks = childEl.__redom_lifecycle || (childEl.__redom_lifecycle = {});\n var remount = (parentEl === oldParent);\n var hooksFound = false;\n\n for (var i = 0, list = hookNames; i < list.length; i += 1) {\n var hookName = list[i];\n\n if (!remount) { // if already mounted, skip this phase\n if (child !== childEl) { // only Views can have lifecycle events\n if (hookName in child) {\n hooks[hookName] = (hooks[hookName] || 0) + 1;\n }\n }\n }\n if (hooks[hookName]) {\n hooksFound = true;\n }\n }\n\n if (!hooksFound) {\n childEl.__redom_lifecycle = {};\n return;\n }\n\n var traverse = parentEl;\n var triggered = false;\n\n if (remount || (traverse && traverse.__redom_mounted)) {\n trigger(childEl, remount ? 'onremount' : 'onmount');\n triggered = true;\n }\n\n while (traverse) {\n var parent = traverse.parentNode;\n var parentHooks = traverse.__redom_lifecycle || (traverse.__redom_lifecycle = {});\n\n for (var hook in hooks) {\n parentHooks[hook] = (parentHooks[hook] || 0) + hooks[hook];\n }\n\n if (triggered) {\n break;\n } else {\n if (traverse.nodeType === Node.DOCUMENT_NODE ||\n (shadowRootAvailable && (traverse instanceof ShadowRoot)) ||\n (parent && parent.__redom_mounted)\n ) {\n trigger(traverse, remount ? 'onremount' : 'onmount');\n triggered = true;\n }\n traverse = parent;\n }\n }\n}\n\nfunction setStyle (view, arg1, arg2) {\n var el = getEl(view);\n\n if (typeof arg1 === 'object') {\n for (var key in arg1) {\n setStyleValue(el, key, arg1[key]);\n }\n } else {\n setStyleValue(el, arg1, arg2);\n }\n}\n\nfunction setStyleValue (el, key, value) {\n el.style[key] = value == null ? '' : value;\n}\n\n/* global SVGElement */\n\nvar xlinkns = 'http://www.w3.org/1999/xlink';\n\nfunction setAttr (view, arg1, arg2) {\n setAttrInternal(view, arg1, arg2);\n}\n\nfunction setAttrInternal (view, arg1, arg2, initial) {\n var el = getEl(view);\n\n var isObj = typeof arg1 === 'object';\n\n if (isObj) {\n for (var key in arg1) {\n setAttrInternal(el, key, arg1[key], initial);\n }\n } else {\n var isSVG = el instanceof SVGElement;\n var isFunc = typeof arg2 === 'function';\n\n if (arg1 === 'style' && typeof arg2 === 'object') {\n setStyle(el, arg2);\n } else if (isSVG && isFunc) {\n el[arg1] = arg2;\n } else if (arg1 === 'dataset') {\n setData(el, arg2);\n } else if (!isSVG && (arg1 in el || isFunc) && (arg1 !== 'list')) {\n el[arg1] = arg2;\n } else {\n if (isSVG && (arg1 === 'xlink')) {\n setXlink(el, arg2);\n return;\n }\n if (initial && arg1 === 'class') {\n arg2 = el.className + ' ' + arg2;\n }\n if (arg2 == null) {\n el.removeAttribute(arg1);\n } else {\n el.setAttribute(arg1, arg2);\n }\n }\n }\n}\n\nfunction setXlink (el, arg1, arg2) {\n if (typeof arg1 === 'object') {\n for (var key in arg1) {\n setXlink(el, key, arg1[key]);\n }\n } else {\n if (arg2 != null) {\n el.setAttributeNS(xlinkns, arg1, arg2);\n } else {\n el.removeAttributeNS(xlinkns, arg1, arg2);\n }\n }\n}\n\nfunction setData (el, arg1, arg2) {\n if (typeof arg1 === 'object') {\n for (var key in arg1) {\n setData(el, key, arg1[key]);\n }\n } else {\n if (arg2 != null) {\n el.dataset[arg1] = arg2;\n } else {\n delete el.dataset[arg1];\n }\n }\n}\n\nfunction text (str) {\n return document.createTextNode((str != null) ? str : '');\n}\n\nfunction parseArgumentsInternal (element, args, initial) {\n for (var i = 0, list = args; i < list.length; i += 1) {\n var arg = list[i];\n\n if (arg !== 0 && !arg) {\n continue;\n }\n\n var type = typeof arg;\n\n if (type === 'function') {\n arg(element);\n } else if (type === 'string' || type === 'number') {\n element.appendChild(text(arg));\n } else if (isNode(getEl(arg))) {\n mount(element, arg);\n } else if (arg.length) {\n parseArgumentsInternal(element, arg, initial);\n } else if (type === 'object') {\n setAttrInternal(element, arg, null, initial);\n }\n }\n}\n\nfunction ensureEl (parent) {\n return typeof parent === 'string' ? html(parent) : getEl(parent);\n}\n\nfunction getEl (parent) {\n return (parent.nodeType && parent) || (!parent.el && parent) || getEl(parent.el);\n}\n\nfunction isNode (arg) {\n return arg && arg.nodeType;\n}\n\nfunction html (query) {\n var args = [], len = arguments.length - 1;\n while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];\n\n var element;\n\n var type = typeof query;\n\n if (type === 'string') {\n element = createElement(query);\n } else if (type === 'function') {\n var Query = query;\n element = new (Function.prototype.bind.apply( Query, [ null ].concat( args) ));\n } else {\n throw new Error('At least one argument required');\n }\n\n parseArgumentsInternal(getEl(element), args, true);\n\n return element;\n}\n\nvar el = html;\nvar h = html;\n\nhtml.extend = function extendHtml () {\n var args = [], len = arguments.length;\n while ( len-- ) args[ len ] = arguments[ len ];\n\n return html.bind.apply(html, [ this ].concat( args ));\n};\n\nfunction setChildren (parent) {\n var children = [], len = arguments.length - 1;\n while ( len-- > 0 ) children[ len ] = arguments[ len + 1 ];\n\n var parentEl = getEl(parent);\n var current = traverse(parent, children, parentEl.firstChild);\n\n while (current) {\n var next = current.nextSibling;\n\n unmount(parent, current);\n\n current = next;\n }\n}\n\nfunction traverse (parent, children, _current) {\n var current = _current;\n\n var childEls = Array(children.length);\n\n for (var i = 0; i < children.length; i++) {\n childEls[i] = children[i] && getEl(children[i]);\n }\n\n for (var i$1 = 0; i$1 < children.length; i$1++) {\n var child = children[i$1];\n\n if (!child) {\n continue;\n }\n\n var childEl = childEls[i$1];\n\n if (childEl === current) {\n current = current.nextSibling;\n continue;\n }\n\n if (isNode(childEl)) {\n var next = current && current.nextSibling;\n var exists = child.__redom_index != null;\n var replace = exists && next === childEls[i$1 + 1];\n\n mount(parent, child, current, replace);\n\n if (replace) {\n current = next;\n }\n\n continue;\n }\n\n if (child.length != null) {\n current = traverse(parent, child, current);\n }\n }\n\n return current;\n}\n\nfunction listPool (View, key, initData) {\n return new ListPool(View, key, initData);\n}\n\nvar ListPool = function ListPool (View, key, initData) {\n this.View = View;\n this.initData = initData;\n this.oldLookup = {};\n this.lookup = {};\n this.oldViews = [];\n this.views = [];\n\n if (key != null) {\n this.key = typeof key === 'function' ? key : propKey(key);\n }\n};\n\nListPool.prototype.update = function update (data, context) {\n var ref = this;\n var View = ref.View;\n var key = ref.key;\n var initData = ref.initData;\n var keySet = key != null;\n\n var oldLookup = this.lookup;\n var newLookup = {};\n\n var newViews = Array(data.length);\n var oldViews = this.views;\n\n for (var i = 0; i < data.length; i++) {\n var item = data[i];\n var view = (void 0);\n\n if (keySet) {\n var id = key(item);\n\n view = oldLookup[id] || new View(initData, item, i, data);\n newLookup[id] = view;\n view.__redom_id = id;\n } else {\n view = oldViews[i] || new View(initData, item, i, data);\n }\n view.update && view.update(item, i, data, context);\n\n var el = getEl(view.el);\n\n el.__redom_view = view;\n newViews[i] = view;\n }\n\n this.oldViews = oldViews;\n this.views = newViews;\n\n this.oldLookup = oldLookup;\n this.lookup = newLookup;\n};\n\nfunction propKey (key) {\n return function (item) {\n return item[key];\n };\n}\n\nfunction list (parent, View, key, initData) {\n return new List(parent, View, key, initData);\n}\n\nvar List = function List (parent, View, key, initData) {\n this.View = View;\n this.initData = initData;\n this.views = [];\n this.pool = new ListPool(View, key, initData);\n this.el = ensureEl(parent);\n this.keySet = key != null;\n};\n\nList.prototype.update = function update (data, context) {\n if ( data === void 0 ) data = [];\n\n var ref = this;\n var keySet = ref.keySet;\n var oldViews = this.views;\n\n this.pool.update(data, context);\n\n var ref$1 = this.pool;\n var views = ref$1.views;\n var lookup = ref$1.lookup;\n\n if (keySet) {\n for (var i = 0; i < oldViews.length; i++) {\n var oldView = oldViews[i];\n var id = oldView.__redom_id;\n\n if (lookup[id] == null) {\n oldView.__redom_index = null;\n unmount(this, oldView);\n }\n }\n }\n\n for (var i$1 = 0; i$1 < views.length; i$1++) {\n var view = views[i$1];\n\n view.__redom_index = i$1;\n }\n\n setChildren(this, views);\n\n if (keySet) {\n this.lookup = lookup;\n }\n this.views = views;\n};\n\nList.extend = function extendList (parent, View, key, initData) {\n return List.bind(List, parent, View, key, initData);\n};\n\nlist.extend = List.extend;\n\n/* global Node */\n\nfunction place (View, initData) {\n return new Place(View, initData);\n}\n\nvar Place = function Place (View, initData) {\n this.el = text('');\n this.visible = false;\n this.view = null;\n this._placeholder = this.el;\n\n if (View instanceof Node) {\n this._el = View;\n } else if (View.el instanceof Node) {\n this._el = View;\n this.view = View;\n } else {\n this._View = View;\n }\n\n this._initData = initData;\n};\n\nPlace.prototype.update = function update (visible, data) {\n var placeholder = this._placeholder;\n var parentNode = this.el.parentNode;\n\n if (visible) {\n if (!this.visible) {\n if (this._el) {\n mount(parentNode, this._el, placeholder);\n unmount(parentNode, placeholder);\n\n this.el = getEl(this._el);\n this.visible = visible;\n } else {\n var View = this._View;\n var view = new View(this._initData);\n\n this.el = getEl(view);\n this.view = view;\n\n mount(parentNode, view, placeholder);\n unmount(parentNode, placeholder);\n }\n }\n this.view && this.view.update && this.view.update(data);\n } else {\n if (this.visible) {\n if (this._el) {\n mount(parentNode, placeholder, this._el);\n unmount(parentNode, this._el);\n\n this.el = placeholder;\n this.visible = visible;\n\n return;\n }\n mount(parentNode, placeholder, this.view);\n unmount(parentNode, this.view);\n\n this.el = placeholder;\n this.view = null;\n }\n }\n this.visible = visible;\n};\n\n/* global Node */\n\nfunction router (parent, Views, initData) {\n return new Router(parent, Views, initData);\n}\n\nvar Router = function Router (parent, Views, initData) {\n this.el = ensureEl(parent);\n this.Views = Views;\n this.initData = initData;\n};\n\nRouter.prototype.update = function update (route, data) {\n if (route !== this.route) {\n var Views = this.Views;\n var View = Views[route];\n\n this.route = route;\n\n if (View && (View instanceof Node || View.el instanceof Node)) {\n this.view = View;\n } else {\n this.view = View && new View(this.initData, data);\n }\n\n setChildren(this.el, [this.view]);\n }\n this.view && this.view.update && this.view.update(data, route);\n};\n\nvar ns = 'http://www.w3.org/2000/svg';\n\nfunction svg (query) {\n var args = [], len = arguments.length - 1;\n while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];\n\n var element;\n\n var type = typeof query;\n\n if (type === 'string') {\n element = createElement(query, ns);\n } else if (type === 'function') {\n var Query = query;\n element = new (Function.prototype.bind.apply( Query, [ null ].concat( args) ));\n } else {\n throw new Error('At least one argument required');\n }\n\n parseArgumentsInternal(getEl(element), args, true);\n\n return element;\n}\n\nvar s = svg;\n\nsvg.extend = function extendSvg () {\n var args = [], len = arguments.length;\n while ( len-- ) args[ len ] = arguments[ len ];\n\n return svg.bind.apply(svg, [ this ].concat( args ));\n};\n\nsvg.ns = ns;\n\nexport { List, ListPool, Place, Router, el, h, html, list, listPool, mount, place, router, s, setAttr, setChildren, setData, setStyle, setXlink, svg, text, unmount };\n","export const getClassname = (\n\tclassList: string[] = [],\n\tcustomClassName: string | string[] = ''\n): string => {\n\tconst customClassList =\n\t\ttypeof customClassName === 'string' ? [customClassName] : customClassName;\n\n\tconst toMerge = customClassList\n\t\t? [...classList, ...customClassList]\n\t\t: [...classList];\n\n\treturn toMerge.join(' ').trim();\n};\n","export enum StickyButtonsEvents {\n\tGO_TO_PLAYER = 'gotoplayer',\n\tCLOSE = 'close'\n}\n","export enum Visibility {\n\tVISIBLE = 'visible',\n\tHIDDEN = 'hidden'\n}\n","export class StickyBaseElement {\n\tel: HTMLElement;\n\n\tconstructor(el: HTMLElement, className?: string) {\n\t\tthis.el = el;\n\t\tthis.el.className = className ?? '';\n\t}\n\n\thide() {\n\t\tthis.el.hidden = true;\n\t}\n\n\tshow() {\n\t\tthis.el.hidden = false;\n\t}\n}\n","import { el, mount } from 'redom';\nimport { getClassname } from 'src/plugins/sticky/utils/get-classname.util';\nimport { StickyBaseElement } from '../../base-element';\nimport { StickyPlaceholderOptions } from './placeholder.interface';\n\nconst DEFAULT_CLASSNAME = ['video-player-sticky-bg'];\n\nexport class StickyPlaceholder extends StickyBaseElement {\n\tel: HTMLDivElement;\n\n\tconstructor(settings: StickyPlaceholderOptions = {}) {\n\t\tconst { customClass } = settings;\n\n\t\tsuper(el('div'), getClassname(DEFAULT_CLASSNAME, customClass));\n\t}\n\n\tmount = (node: ParentNode) => mount(node, this);\n}\n","import { Observable } from '../Observable';\nimport { isArray } from '../util/isArray';\nimport { isFunction } from '../util/isFunction';\nimport { Subscriber } from '../Subscriber';\nimport { map } from '../operators/map';\n\nconst toString: Function = (() => Object.prototype.toString)();\n\nexport interface NodeStyleEventEmitter {\n addListener: (eventName: string | symbol, handler: NodeEventHandler) => this;\n removeListener: (eventName: string | symbol, handler: NodeEventHandler) => this;\n}\n\nexport type NodeEventHandler = (...args: any[]) => void;\n\n// For APIs that implement `addListener` and `removeListener` methods that may\n// not use the same arguments or return EventEmitter values\n// such as React Native\nexport interface NodeCompatibleEventEmitter {\n addListener: (eventName: string, handler: NodeEventHandler) => void | {};\n removeListener: (eventName: string, handler: NodeEventHandler) => void | {};\n}\n\nexport interface JQueryStyleEventEmitter {\n on: (eventName: string, handler: Function) => void;\n off: (eventName: string, handler: Function) => void;\n}\n\nexport interface HasEventTargetAddRemove {\n addEventListener(type: string, listener: ((evt: E) => void) | null, options?: boolean | AddEventListenerOptions): void;\n removeEventListener(type: string, listener?: ((evt: E) => void) | null, options?: EventListenerOptions | boolean): void;\n}\n\nexport type EventTargetLike = HasEventTargetAddRemove | NodeStyleEventEmitter | NodeCompatibleEventEmitter | JQueryStyleEventEmitter;\n\nexport type FromEventTarget = EventTargetLike | ArrayLike>;\n\nexport interface EventListenerOptions {\n capture?: boolean;\n passive?: boolean;\n once?: boolean;\n}\n\nexport interface AddEventListenerOptions extends EventListenerOptions {\n once?: boolean;\n passive?: boolean;\n}\n\n/* tslint:disable:max-line-length */\nexport function fromEvent(target: FromEventTarget, eventName: string): Observable;\n/** @deprecated resultSelector no longer supported, pipe to map instead */\nexport function fromEvent(target: FromEventTarget, eventName: string, resultSelector: (...args: any[]) => T): Observable;\nexport function fromEvent(target: FromEventTarget, eventName: string, options: EventListenerOptions): Observable;\n/** @deprecated resultSelector no longer supported, pipe to map instead */\nexport function fromEvent(target: FromEventTarget, eventName: string, options: EventListenerOptions, resultSelector: (...args: any[]) => T): Observable;\n/* tslint:enable:max-line-length */\n\n/**\n * Creates an Observable that emits events of a specific type coming from the\n * given event target.\n *\n * Creates an Observable from DOM events, or Node.js\n * EventEmitter events or others.\n *\n * ![](fromEvent.png)\n *\n * `fromEvent` accepts as a first argument event target, which is an object with methods\n * for registering event handler functions. As a second argument it takes string that indicates\n * type of event we want to listen for. `fromEvent` supports selected types of event targets,\n * which are described in detail below. If your event target does not match any of the ones listed,\n * you should use {@link fromEventPattern}, which can be used on arbitrary APIs.\n * When it comes to APIs supported by `fromEvent`, their methods for adding and removing event\n * handler functions have different names, but they all accept a string describing event type\n * and function itself, which will be called whenever said event happens.\n *\n * Every time resulting Observable is subscribed, event handler function will be registered\n * to event target on given event type. When that event fires, value\n * passed as a first argument to registered function will be emitted by output Observable.\n * When Observable is unsubscribed, function will be unregistered from event target.\n *\n * Note that if event target calls registered function with more than one argument, second\n * and following arguments will not appear in resulting stream. In order to get access to them,\n * you can pass to `fromEvent` optional project function, which will be called with all arguments\n * passed to event handler. Output Observable will then emit value returned by project function,\n * instead of the usual value.\n *\n * Remember that event targets listed below are checked via duck typing. It means that\n * no matter what kind of object you have and no matter what environment you work in,\n * you can safely use `fromEvent` on that object if it exposes described methods (provided\n * of course they behave as was described above). So for example if Node.js library exposes\n * event target which has the same method names as DOM EventTarget, `fromEvent` is still\n * a good choice.\n *\n * If the API you use is more callback then event handler oriented (subscribed\n * callback function fires only once and thus there is no need to manually\n * unregister it), you should use {@link bindCallback} or {@link bindNodeCallback}\n * instead.\n *\n * `fromEvent` supports following types of event targets:\n *\n * **DOM EventTarget**\n *\n * This is an object with `addEventListener` and `removeEventListener` methods.\n *\n * In the browser, `addEventListener` accepts - apart from event type string and event\n * handler function arguments - optional third parameter, which is either an object or boolean,\n * both used for additional configuration how and when passed function will be called. When\n * `fromEvent` is used with event target of that type, you can provide this values\n * as third parameter as well.\n *\n * **Node.js EventEmitter**\n *\n * An object with `addListener` and `removeListener` methods.\n *\n * **JQuery-style event target**\n *\n * An object with `on` and `off` methods\n *\n * **DOM NodeList**\n *\n * List of DOM Nodes, returned for example by `document.querySelectorAll` or `Node.childNodes`.\n *\n * Although this collection is not event target in itself, `fromEvent` will iterate over all Nodes\n * it contains and install event handler function in every of them. When returned Observable\n * is unsubscribed, function will be removed from all Nodes.\n *\n * **DOM HtmlCollection**\n *\n * Just as in case of NodeList it is a collection of DOM nodes. Here as well event handler function is\n * installed and removed in each of elements.\n *\n *\n * ## Examples\n * ### Emits clicks happening on the DOM document\n * ```ts\n * import { fromEvent } from 'rxjs';\n *\n * const clicks = fromEvent(document, 'click');\n * clicks.subscribe(x => console.log(x));\n *\n * // Results in:\n * // MouseEvent object logged to console every time a click\n * // occurs on the document.\n * ```\n *\n * ### Use addEventListener with capture option\n * ```ts\n * import { fromEvent } from 'rxjs';\n *\n * const clicksInDocument = fromEvent(document, 'click', true); // note optional configuration parameter\n * // which will be passed to addEventListener\n * const clicksInDiv = fromEvent(someDivInDocument, 'click');\n *\n * clicksInDocument.subscribe(() => console.log('document'));\n * clicksInDiv.subscribe(() => console.log('div'));\n *\n * // By default events bubble UP in DOM tree, so normally\n * // when we would click on div in document\n * // \"div\" would be logged first and then \"document\".\n * // Since we specified optional `capture` option, document\n * // will catch event when it goes DOWN DOM tree, so console\n * // will log \"document\" and then \"div\".\n * ```\n *\n * @see {@link bindCallback}\n * @see {@link bindNodeCallback}\n * @see {@link fromEventPattern}\n *\n * @param {FromEventTarget} target The DOM EventTarget, Node.js\n * EventEmitter, JQuery-like event target, NodeList or HTMLCollection to attach the event handler to.\n * @param {string} eventName The event name of interest, being emitted by the\n * `target`.\n * @param {EventListenerOptions} [options] Options to pass through to addEventListener\n * @return {Observable}\n * @name fromEvent\n */\nexport function fromEvent(\n target: FromEventTarget,\n eventName: string,\n options?: EventListenerOptions | ((...args: any[]) => T),\n resultSelector?: ((...args: any[]) => T)\n): Observable {\n\n if (isFunction(options)) {\n // DEPRECATED PATH\n resultSelector = options;\n options = undefined;\n }\n if (resultSelector) {\n // DEPRECATED PATH\n return fromEvent(target, eventName, options).pipe(\n map(args => isArray(args) ? resultSelector(...args) : resultSelector(args))\n );\n }\n\n return new Observable(subscriber => {\n function handler(e: T) {\n if (arguments.length > 1) {\n subscriber.next(Array.prototype.slice.call(arguments));\n } else {\n subscriber.next(e);\n }\n }\n setupSubscription(target, eventName, handler, subscriber, options as EventListenerOptions);\n });\n}\n\nfunction setupSubscription(sourceObj: FromEventTarget, eventName: string,\n handler: (...args: any[]) => void, subscriber: Subscriber,\n options?: EventListenerOptions) {\n let unsubscribe: () => void;\n if (isEventTarget(sourceObj)) {\n const source = sourceObj;\n sourceObj.addEventListener(eventName, handler, options);\n unsubscribe = () => source.removeEventListener(eventName, handler, options);\n } else if (isJQueryStyleEventEmitter(sourceObj)) {\n const source = sourceObj;\n sourceObj.on(eventName, handler);\n unsubscribe = () => source.off(eventName, handler);\n } else if (isNodeStyleEventEmitter(sourceObj)) {\n const source = sourceObj;\n sourceObj.addListener(eventName, handler as NodeEventHandler);\n unsubscribe = () => source.removeListener(eventName, handler as NodeEventHandler);\n } else if (sourceObj && (sourceObj as any).length) {\n for (let i = 0, len = (sourceObj as any).length; i < len; i++) {\n setupSubscription(sourceObj[i], eventName, handler, subscriber, options);\n }\n } else {\n throw new TypeError('Invalid event target');\n }\n\n subscriber.add(unsubscribe);\n}\n\nfunction isNodeStyleEventEmitter(sourceObj: any): sourceObj is NodeStyleEventEmitter {\n return sourceObj && typeof sourceObj.addListener === 'function' && typeof sourceObj.removeListener === 'function';\n}\n\nfunction isJQueryStyleEventEmitter(sourceObj: any): sourceObj is JQueryStyleEventEmitter {\n return sourceObj && typeof sourceObj.on === 'function' && typeof sourceObj.off === 'function';\n}\n\nfunction isEventTarget(sourceObj: any): sourceObj is HasEventTargetAddRemove {\n return sourceObj && typeof sourceObj.addEventListener === 'function' && typeof sourceObj.removeEventListener === 'function';\n}\n","import { el } from 'redom';\n\nexport const getChildren = (icon?: string, text?: string): HTMLElement[] => {\n\tconst children: HTMLElement[] = [];\n\tif (icon) {\n\t\tconst iconEl = el('i');\n\t\ticonEl.className = `icon ${icon}`;\n\t\tchildren.push(iconEl);\n\t}\n\n\tif (text) {\n\t\tconst textEl = el('span');\n\t\ttextEl.className = 'button-label';\n\t\tchildren.push(textEl);\n\t}\n\n\treturn children;\n};\n","import { el, setChildren } from 'redom';\nimport { fromEvent, Observable } from 'rxjs';\n\nimport { StickyButtonOptions } from './button.interface';\nimport { getChildren } from './buttons.util';\nimport { getClassname } from '../../../utils/get-classname.util';\nimport { StickyBaseElement } from '../../base-element';\nimport { ReactiveClickableElement } from '../../../interfaces/reactive-clickable-element.interface';\n\nconst DEFAULT_CLASSLIST = ['video-player-sticky-custom-btn'];\n\nexport class StickyButton\n\textends StickyBaseElement\n\timplements ReactiveClickableElement\n{\n\tel: HTMLButtonElement;\n\tclicked$: Observable;\n\n\tconstructor(settings: StickyButtonOptions) {\n\t\tconst { icon, text, customClass } = settings;\n\n\t\tsuper(el('button'), getClassname(DEFAULT_CLASSLIST, customClass));\n\t\tsetChildren(this.el, getChildren(icon, text));\n\t\tthis.clicked$ = fromEvent(this.el, 'click');\n\t}\n}\n","import { setChildren, el } from 'redom';\nimport { merge, Observable, Subject } from 'rxjs';\nimport { mapTo } from 'rxjs/operators';\nimport { StickyButtonsEvents } from 'src/plugins/sticky/enums/buttons-events.enum';\nimport { Visibility } from 'src/plugins/sticky/enums/visibility.enum';\nimport { StickyButtonVisibilityEvent } from 'src/plugins/sticky/interfaces/sticky-button-visibility-event.interface';\nimport { getClassname } from 'src/plugins/sticky/utils/get-classname.util';\nimport { StickyBaseElement } from '../../base-element';\nimport { StickyButton } from '../../global/buttons/button.component';\nimport { StickyButtonsBarOptions } from './buttons-bar.interface';\n\nexport class StickyButtonsBar extends StickyBaseElement {\n\tgoBackButton: StickyButton;\n\tcloseButton: StickyButton;\n\tevents$: Observable;\n\n\tswitchVisibility$ = new Subject();\n\n\tconstructor(settings: StickyButtonsBarOptions) {\n\t\tconst { customClass } = settings;\n\t\tsuper(el('buttons-bar'), getClassname(['sticky-buttons-bar'], customClass));\n\n\t\tthis.goBackButton = new StickyButton({\n\t\t\ticon: 'icon-arrow-up',\n\t\t\tcustomClass: ['af-btn-v2', 'af-btn-v2-center', 'gotoplayer']\n\t\t});\n\t\tthis.closeButton = new StickyButton({\n\t\t\tcustomClass: 'close'\n\t\t});\n\n\t\tthis.events$ = merge(\n\t\t\tthis.goBackButton.clicked$.pipe(mapTo(StickyButtonsEvents.GO_TO_PLAYER)),\n\t\t\tthis.closeButton.clicked$.pipe(mapTo(StickyButtonsEvents.CLOSE))\n\t\t);\n\n\t\tthis.switchVisibility$.subscribe((event: StickyButtonVisibilityEvent) => {\n\t\t\tconst doSwitchVisibilty = (target: StickyButton, state: Visibility) => {\n\t\t\t\tif (state === Visibility.HIDDEN) {\n\t\t\t\t\ttarget.el.classList.add('hidden');\n\t\t\t\t} else if (state === Visibility.VISIBLE) {\n\t\t\t\t\ttarget.el.classList.remove('hidden');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tswitch (event.btn) {\n\t\t\t\tcase StickyButtonsEvents.CLOSE: {\n\t\t\t\t\tdoSwitchVisibilty(this.closeButton, event.state);\n\t\t\t\t} break;\n\n\t\t\t\tcase StickyButtonsEvents.GO_TO_PLAYER: {\n\t\t\t\t\tdoSwitchVisibilty(this.goBackButton, event.state);\n\t\t\t\t} break;\n\n\t\t\t\tdefault: {\n\t\t\t\t\tconsole.error('This button visibility switch is not yet implemented');\n\t\t\t\t} break;\n\t\t\t}\n\t\t});\n\n\t\tsetChildren(this.el, [this.goBackButton, this.closeButton]);\n\t}\n}\n","import { Observable } from '../Observable';\nimport { ObservableInput, SchedulerLike} from '../types';\nimport { isScheduler } from '../util/isScheduler';\nimport { mergeAll } from '../operators/mergeAll';\nimport { fromArray } from './fromArray';\n\n/* tslint:disable:max-line-length */\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, concurrent: number, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, v2: ObservableInput, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, v2: ObservableInput, concurrent: number, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, concurrent: number, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, concurrent: number, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, v5: ObservableInput, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, v5: ObservableInput, concurrent: number, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, v5: ObservableInput, v6: ObservableInput, scheduler: SchedulerLike): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, v5: ObservableInput, v6: ObservableInput, concurrent: number, scheduler: SchedulerLike): Observable;\n\nexport function merge(v1: ObservableInput): Observable;\nexport function merge(v1: ObservableInput, concurrent?: number): Observable;\nexport function merge(v1: ObservableInput, v2: ObservableInput): Observable;\nexport function merge(v1: ObservableInput, v2: ObservableInput, concurrent?: number): Observable;\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput): Observable;\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, concurrent?: number): Observable;\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput): Observable;\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, concurrent?: number): Observable;\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, v5: ObservableInput): Observable;\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, v5: ObservableInput, concurrent?: number): Observable;\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, v5: ObservableInput, v6: ObservableInput): Observable;\nexport function merge(v1: ObservableInput, v2: ObservableInput, v3: ObservableInput, v4: ObservableInput, v5: ObservableInput, v6: ObservableInput, concurrent?: number): Observable;\nexport function merge(...observables: (ObservableInput | number)[]): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(...observables: (ObservableInput | SchedulerLike | number)[]): Observable;\nexport function merge(...observables: (ObservableInput | number)[]): Observable;\n/** @deprecated use {@link scheduled} and {@link mergeAll} (e.g. `scheduled([ob1, ob2, ob3], scheduled).pipe(mergeAll())*/\nexport function merge(...observables: (ObservableInput | SchedulerLike | number)[]): Observable;\n/* tslint:enable:max-line-length */\n/**\n * Creates an output Observable which concurrently emits all values from every\n * given input Observable.\n *\n * Flattens multiple Observables together by blending\n * their values into one Observable.\n *\n * ![](merge.png)\n *\n * `merge` subscribes to each given input Observable (as arguments), and simply\n * forwards (without doing any transformation) all the values from all the input\n * Observables to the output Observable. The output Observable only completes\n * once all input Observables have completed. Any error delivered by an input\n * Observable will be immediately emitted on the output Observable.\n *\n * ## Examples\n * ### Merge together two Observables: 1s interval and clicks\n * ```ts\n * import { merge, fromEvent, interval } from 'rxjs';\n *\n * const clicks = fromEvent(document, 'click');\n * const timer = interval(1000);\n * const clicksOrTimer = merge(clicks, timer);\n * clicksOrTimer.subscribe(x => console.log(x));\n *\n * // Results in the following:\n * // timer will emit ascending values, one every second(1000ms) to console\n * // clicks logs MouseEvents to console everytime the \"document\" is clicked\n * // Since the two streams are merged you see these happening\n * // as they occur.\n * ```\n *\n * ### Merge together 3 Observables, but only 2 run concurrently\n * ```ts\n * import { merge, interval } from 'rxjs';\n * import { take } from 'rxjs/operators';\n *\n * const timer1 = interval(1000).pipe(take(10));\n * const timer2 = interval(2000).pipe(take(6));\n * const timer3 = interval(500).pipe(take(10));\n * const concurrent = 2; // the argument\n * const merged = merge(timer1, timer2, timer3, concurrent);\n * merged.subscribe(x => console.log(x));\n *\n * // Results in the following:\n * // - First timer1 and timer2 will run concurrently\n * // - timer1 will emit a value every 1000ms for 10 iterations\n * // - timer2 will emit a value every 2000ms for 6 iterations\n * // - after timer1 hits its max iteration, timer2 will\n * // continue, and timer3 will start to run concurrently with timer2\n * // - when timer2 hits its max iteration it terminates, and\n * // timer3 will continue to emit a value every 500ms until it is complete\n * ```\n *\n * @see {@link mergeAll}\n * @see {@link mergeMap}\n * @see {@link mergeMapTo}\n * @see {@link mergeScan}\n *\n * @param {...ObservableInput} observables Input Observables to merge together.\n * @param {number} [concurrent=Number.POSITIVE_INFINITY] Maximum number of input\n * Observables being subscribed to concurrently.\n * @param {SchedulerLike} [scheduler=null] The {@link SchedulerLike} to use for managing\n * concurrency of input Observables.\n * @return {Observable} an Observable that emits items that are the result of\n * every input Observable.\n * @static true\n * @name merge\n * @owner Observable\n */\nexport function merge(...observables: Array | SchedulerLike | number>): Observable {\n let concurrent = Number.POSITIVE_INFINITY;\n let scheduler: SchedulerLike = null;\n let last: any = observables[observables.length - 1];\n if (isScheduler(last)) {\n scheduler = observables.pop();\n if (observables.length > 1 && typeof observables[observables.length - 1] === 'number') {\n concurrent = observables.pop();\n }\n } else if (typeof last === 'number') {\n concurrent = observables.pop();\n }\n\n if (scheduler === null && observables.length === 1 && observables[0] instanceof Observable) {\n return >observables[0];\n }\n\n return mergeAll(concurrent)(fromArray(observables, scheduler));\n}\n","import { el } from 'redom';\nimport { Observable, Subject, BehaviorSubject } from 'rxjs';\nimport { distinctUntilChanged } from 'rxjs/operators';\nimport { VideoConsoleLogger } from 'src/utils/video-logger';\nimport { Visibility } from '../../enums/visibility.enum';\nimport { StickyLayoutEvents } from '../../types/sticky-events.type';\n\nimport { getClassname } from '../../utils/get-classname.util';\nimport { mergeFunctions } from '../../utils/merge-functions.util';\nimport { StickyBaseElement } from '../base-element';\nimport { StickyLayoutOptions } from './base-layout.interface';\n\nconst DEFAULT_CLASSLIST = ['video-player-sticky-container'];\nconst logger = new VideoConsoleLogger();\n\nexport class StickyBaseLayout extends StickyBaseElement {\n\tel: HTMLDivElement;\n\tplayerWrapper: HTMLElement;\n\tparentNode: ParentNode;\n\tplayerElement: HTMLElement;\n\ttoggleableElements: StickyBaseElement[] = [];\n\n\tsticked$ = new Subject();\n\tstickedClasses: string[];\n\n\tcloseBtnVisibility$: BehaviorSubject;\n\n\tevents$: Observable;\n\n\tconstructor(settings: StickyLayoutOptions) {\n\t\tconst { customClass, playerContainerId, playerId, stickedClasses } =\n\t\t\tsettings;\n\t\tsuper(el('div'), getClassname(DEFAULT_CLASSLIST, customClass));\n\n\t\tthis.stickedClasses = stickedClasses;\n\n\t\ttry {\n\t\t\tthis.playerWrapper = this._getPlayerWrapper(playerContainerId);\n\t\t\tthis.parentNode = this._getParentNode(this.playerWrapper);\n\t\t\tthis.playerElement = this._getPlayer(playerId);\n\t\t} catch (error) {\n\t\t\tlogger.error(error)();\n\t\t\tthrow new Error(error);\n\t\t}\n\n\t\tthis.sticked$\n\t\t\t.pipe(distinctUntilChanged())\n\t\t\t.subscribe(mergeFunctions(this.toggleElements, this.toggleStickedClass));\n\n\t\tconst defaultCloseBtnVisibility = settings.closeBtnSwitchFeatureEnabled ? Visibility.HIDDEN : Visibility.VISIBLE;\n\t\tthis.closeBtnVisibility$ = new BehaviorSubject(defaultCloseBtnVisibility);\n\t}\n\n\tprotected toggleElements = (sticked: boolean) =>\n\t\tthis.toggleableElements.forEach((el) => (sticked ? el.show() : el.hide()));\n\tprotected toggleStickedClass = (sticked: boolean) =>\n\t\tthis.playerWrapper.classList[sticked ? 'add' : 'remove'].apply(\n\t\t\tthis.playerWrapper.classList,\n\t\t\tthis.stickedClasses\n\t\t);\n\n\tprivate _getPlayer = (playerId: string) => {\n\t\tconst playerContainer = document.getElementById(playerId);\n\n\t\tif (!playerContainer) {\n\t\t\tthrow new Error(`Cannot find player with id \"${playerId}\"`);\n\t\t}\n\n\t\treturn playerContainer;\n\t};\n\n\tprivate _getPlayerWrapper = (playerContainerId: string) => {\n\t\tconst playerContainer = document.getElementById(playerContainerId);\n\n\t\tif (!playerContainer) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot find player container with id \"${playerContainerId}\"`\n\t\t\t);\n\t\t}\n\n\t\treturn playerContainer;\n\t};\n\n\tprivate _getParentNode = (playerContainer: HTMLElement) => {\n\t\tconst parentNode = playerContainer?.parentNode;\n\n\t\tif (!parentNode) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot find parent node of player with id \"${playerContainer.id}\"`\n\t\t\t);\n\t\t}\n\n\t\treturn parentNode;\n\t};\n}\n","import { distinctUntilChanged } from 'rxjs/operators';\nimport {\n\tPublishableVideoAdEvents,\n\tPublishableVideoContentEvents,\n\tPublishableVideoPlayerEvents,\n\tPublishableVideoStickyEvents,\n\tPublishableVideoStoreEvents\n} from 'src/enums/publishable-events.enum';\nimport { StickyFormats } from 'src/enums/sticky-formats.enum';\nimport { ListenerAction } from 'src/interfaces/listener-action';\nimport {\n\tBannerStickyOptions,\n\tFlyingStickyOptions\n} from 'src/interfaces/sticky-formats-options.interface';\nimport { PlayerInstance } from 'src/types/player-instance.type';\nimport { StickyFormatOptions } from 'src/types/stickyFormatOptions.type';\nimport { Store, StoreInstance } from '../../store';\nimport { FlyingStickyLayout } from './components/layouts/flying/flying.layout.component';\nimport { StickyButtonsEvents } from './enums/buttons-events.enum';\nimport { StickyLayoutEvents } from './types/sticky-events.type';\nimport { VideoConsoleLogger } from 'src/utils/video-logger';\nimport { BannerStickyLayout } from './components/layouts/banner/banner-layout.component';\nimport { formatSecondsToMinutes } from 'src/utils/time-utils.service';\nimport { fromEvent } from 'rxjs';\nimport {\n\tisStickySessionDisabled,\n\tsetDisabledStickyForSessionState\n} from './utils/session-storage.util';\nimport { getElementPosition, getWindowPosition } from './utils/dom.util';\nimport { applyCssTranslate } from './utils/translate.util';\nimport PubSub from 'pubsub-js';\nimport { Visibility } from './enums/visibility.enum';\n\nconst l = new VideoConsoleLogger();\nexport interface StickyPluginOptions {\n\tstore: Store;\n}\n\nenum VP_TOP {\n\tIS_BELOW_CONTAINER_TOP = 'vp-top-below-top',\n\tIS_BELOW_CONTAINER_MIDDLE = 'vp-top-below-middle'\n}\n\nenum VP_BOTTOM {\n\tIS_ABOVE_CONTAINER_BOTTOM = 'vp-bottom-above-bottom',\n\tIS_ABOVE_CONTAINER_MIDDLE = 'vp-bottom-above-middle',\n\tIS_BELOW_CONTAINER_MIDDLE = 'vp-bottom-below-middle'\n}\n\nenum CONTAINER_POSITION {\n\tIS_PARTIALLY_WITHIN_VP = 'partially-within-vp',\n\tIS_WITHIN_VP = 'within-vp'\n}\n\nenum DEFAULT_SETTINGS {\n\tONCOMPLETE_TIMEOUT = 11000,\n\tSCROLL_OFFSET = 200\n}\n\ntype StickyLayout = FlyingStickyLayout | BannerStickyLayout;\n\nexport class StickyPlugin {\n\tpublic name: 'sticky';\n\tpublic scrollEvent: (...args: []) => any =\n\t\tthis.stickMainViewablePlayer.bind(this);\n\n\tprivate _layout: StickyLayout;\n\tprivate _id: string;\n\tprivate _player: PlayerInstance;\n\tprivate _instance: StoreInstance;\n\n\tprivate _stickyFormat: StickyFormats;\n\tprivate _stickyFormatOptions: StickyFormatOptions;\n\tprivate _stickTo: string;\n\tprivate _disabledForPage = false;\n\n\tprivate _container: HTMLElement | Element;\n\tprivate _stickyRect: DOMRect | null;\n\n\tpublic enabled = false;\n\tprivate _closedByUser = false;\n\tprivate _onCompleteTimeout: ReturnType | null;\n\tprivate _isSticked = false;\n\tprivate _stickyReady = false;\n\tprivate _disabledByElementOnScreen = false;\n\tprivate _scrollUp: boolean;\n\n\t// Handle collisions of sticky player over floating elements (popup, ads)\n\tprivate _xPos: number | string = 0;\n\tprivate _yPos: number | string = 0;\n\tprivate _xPosExtra = 0;\n\tprivate _yPosExtra = 0;\n\n\tprivate _waitForAdLoaded = false;\n\tprivate _adLoaded = false;\n\tprivate _stickBothSide = false;\n\n\tprivate _store: Store;\n\n\tprivate screenOrientationChanged$ = fromEvent(screen.orientation, 'change');\n\n\tprivate _listenersActions: ListenerAction[] = [\n\t\t{\n\t\t\t// Once an instance is added to the store, register it\n\t\t\tmessage: PublishableVideoStoreEvents.ADD_INSTANCE,\n\t\t\tactionFn: (msg, instanceData) => {\n\t\t\t\tconst instance = instanceData.instance;\n\n\t\t\t\tif (instance.id !== this._id) {\n\t\t\t\t\tl.debug('Message is not for this sticky plugin, skipping ...')();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Do not register instance if sticky not enabled or an instance is already initialized\n\t\t\t\tif (!instance.sticky.stickTo || this._instance) {\n\t\t\t\t\tif (!instance.sticky.stickTo) {\n\t\t\t\t\t\tthis.enabled = false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._registerInstance(instance);\n\t\t\t\tthis._initLayout(this._stickyFormat, this._stickyFormatOptions);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t// Once a player is ready, init plugin\n\t\t\tmessage: PublishableVideoStickyEvents.STICKY_READY,\n\t\t\tactionFn: (msg, readyData: { id: string }) => {\n\t\t\t\tthis._onPlayerReady.call(this, readyData.id);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_LOADED,\n\t\t\tactionFn: () => {\n\t\t\t\tif (!this._waitForAdLoaded) return;\n\n\t\t\t\tthis._adLoaded = true;\n\t\t\t\tthis._onPlayerReady.call(this, this._id);\n\t\t\t\tthis.stickMainViewablePlayer.call(this);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoAdEvents.AD_START,\n\t\t\tactionFn: () => {\n\t\t\t\t// Hide close button if layout is compatible and needed\n\t\t\t\tif (!this._stickyFormatOptions.closeBtnSwitchFeatureEnabled) return;\n\t\t\t\tthis._layout.closeBtnVisibility$.next(Visibility.HIDDEN);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoContentEvents.VIDEO_START,\n\t\t\tactionFn: () => {\n\t\t\t\t// Hide close button if layout is compatible and needed\n\t\t\t\tif (!this._stickyFormatOptions.closeBtnSwitchFeatureEnabled) return;\n\t\t\t\tthis._layout.closeBtnVisibility$.next(Visibility.VISIBLE);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoStickyEvents.STICKY_CONTENT_START,\n\t\t\tactionFn: () => {\n\t\t\t\tif (\n\t\t\t\t\t!this._stickyReady &&\n\t\t\t\t\t(!this._waitForAdLoaded || (this._waitForAdLoaded && !this._adLoaded))\n\t\t\t\t) {\n\t\t\t\t\tthis._adLoaded = true;\n\t\t\t\t\tthis._onPlayerReady(this._id, true);\n\t\t\t\t\tthis.stickMainViewablePlayer();\n\t\t\t\t}\n\n\t\t\t\tif (!this._stickyReady || this._closedByUser) return;\n\n\t\t\t\t// If sticky already ready, re-enable sticky if not blocked permanently\n\t\t\t\t// to permit to relaunch the video player and get the sticky feature again\n\t\t\t\tthis.enabled = !isStickySessionDisabled() && !this._disabledForPage;\n\t\t\t\tthis._cancelDisablingTimeout();\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoContentEvents.VIDEO_END,\n\t\t\tactionFn: () => {\n\t\t\t\tconst _disableWithDelay = (timeout: number) => {\n\t\t\t\t\t// Set only one \"unstick\" timer (lock for concurrent calls)\n\t\t\t\t\tif (this._onCompleteTimeout) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._onCompleteTimeout = setTimeout(\n\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\ttypeof this._player.playlist === 'undefined'\n\t\t\t\t\t\t\t\t? this._disable(false, false, 'disableWithDelay')\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\ttimeout\n\t\t\t\t\t);\n\t\t\t\t};\n\n\t\t\t\t_disableWithDelay(DEFAULT_SETTINGS.ONCOMPLETE_TIMEOUT);\n\t\t\t\t// Unstick player after a few seconds when video is finished\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.SEEKING,\n\t\t\tactionFn: this._cancelDisablingTimeout\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.PAUSE,\n\t\t\tactionFn: this._cancelDisablingTimeout\n\t\t},\n\t\t{\n\t\t\tmessage: 'mrtn-selection-box:open',\n\t\t\tactionFn: () => {\n\t\t\t\tconst that = this;\n\t\t\t\tif (!this._stickyReady) return;\n\n\t\t\t\tonPopupShow(0, 110); // TODO: retrieve value from mrtnSelectionBox, with data.height\n\n\t\t\t\tfunction onPopupShow(xPos, yPos) {\n\t\t\t\t\tif (!that._isSticked) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthat._xPosExtra = xPos;\n\t\t\t\t\tthat._yPosExtra = yPos;\n\t\t\t\t\tthat._moveStickyToCollisionPosition.call(this);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: 'mrtn-selection-box:close',\n\t\t\tactionFn: () => {\n\t\t\t\tif (!this._stickyReady) return;\n\t\t\t\tthis._resetStickyPosition.call(this);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.CRITICAL_PATH_READY,\n\t\t\tactionFn: () => this.stickMainViewablePlayer()\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoStickyEvents.STICK,\n\t\t\tactionFn: () => this.stick()\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoStickyEvents.UNSTICK,\n\t\t\tactionFn: () => this.unstick()\n\t\t}\n\t];\n\n\tconstructor(options: StickyPluginOptions) {\n\t\tthis._init();\n\t\tthis._store = options.store;\n\t}\n\n\t/**\n\t * Stick the player\n\t */\n\tpublic stick() {\n\t\t// Do nothing if player is already sticked\n\t\tif (!this._player || this._isSticked) return;\n\n\t\t// Stick container and check for collisions with other HTML elements of the page behavior displaying it\n\t\tthis._player.isSticked = this._isSticked = true;\n\t\tthis._layout.sticked$.next(true);\n\t\tthis._moveStickyToCollisionPosition();\n\t\tthis._updatePlayerBoundingRect();\n\t\tthis._player.publish(PublishableVideoStickyEvents.STICKED);\n\t}\n\n\t/**\n\t * Unstick the player\n\t */\n\tpublic unstick() {\n\t\t// Do nothing if player is already unsticked\n\t\tif (!this._player || !this._isSticked) return;\n\n\t\t// Unstick container and reset collisions\n\t\tthis._player.isSticked = this._isSticked = false;\n\t\tthis._layout.sticked$.next(false);\n\t\tthis._resetStickyPosition();\n\n\t\tthis._player.publish(PublishableVideoStickyEvents.UNSTICKED);\n\t}\n\n\t/**\n\t * Event that stick / unstick player on scroll\n\t */\n\tpublic stickMainViewablePlayer() {\n\t\tconst that = this;\n\n\t\tif (!this._layout) return;\n\n\t\tconst stickUnstickHandler = (shouldDisable: boolean) => {\n\t\t\t// Do nothing if sticky is disabled\n\t\t\tif (!this.enabled && !that._disabledByElementOnScreen) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (shouldDisable) {\n\t\t\t\tthis._disable(false, false, 'handler');\n\t\t\t\tthis._disabledByElementOnScreen = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet action;\n\n\t\t\tif (this._stickBothSide) {\n\t\t\t\tconst topBelowMiddle = isViewportPositionned(\n\t\t\t\t\tVP_TOP.IS_BELOW_CONTAINER_MIDDLE\n\t\t\t\t);\n\t\t\t\tconst bottomAboveMiddle = isViewportPositionned(\n\t\t\t\t\tVP_BOTTOM.IS_ABOVE_CONTAINER_MIDDLE\n\t\t\t\t);\n\t\t\t\taction = topBelowMiddle || bottomAboveMiddle ? 'stick' : 'unstick';\n\t\t\t} else if (!this._scrollUp) {\n\t\t\t\t// Scroll down (default behavior): stick when viewport is below the original container\n\t\t\t\taction = isViewportPositionned(VP_TOP.IS_BELOW_CONTAINER_MIDDLE)\n\t\t\t\t\t? 'stick'\n\t\t\t\t\t: 'unstick';\n\t\t\t} else {\n\t\t\t\t// Scroll up (specific case): stick when viewport is above the original container\n\t\t\t\t// ⚠️ Original player container must have be seen at least once before firing any \"scroll-up\" sticky\n\t\t\t\tif (!this._isSticked) {\n\t\t\t\t\taction =\n\t\t\t\t\t\tisViewportPositionned(CONTAINER_POSITION.IS_PARTIALLY_WITHIN_VP) &&\n\t\t\t\t\t\tisViewportPositionned(VP_BOTTOM.IS_ABOVE_CONTAINER_MIDDLE)\n\t\t\t\t\t\t\t? 'stick'\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t} else {\n\t\t\t\t\taction = isViewportPositionned(VP_BOTTOM.IS_BELOW_CONTAINER_MIDDLE)\n\t\t\t\t\t\t? 'unstick'\n\t\t\t\t\t\t: undefined;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!action) return;\n\t\t\tl.debug(`Sticky will ${action}`);\n\t\t\tconst actionFn = this[action].bind(this);\n\n\t\t\tif (this._waitForAdLoaded && !this._adLoaded) {\n\t\t\t\tif (action === 'stick' && !this._store.isViewable(this._instance)) {\n\t\t\t\t\tthis._instance.player.play();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttypeof actionFn === 'function' && actionFn();\n\n\t\t\tif (action === 'stick' && this._disabledByElementOnScreen) {\n\t\t\t\tthis.enabled = true;\n\t\t\t\tthis._instance.player.play();\n\t\t\t\tthis._disabledByElementOnScreen = !this._disabledByElementOnScreen;\n\t\t\t}\n\n\t\t\tfunction isViewportPositionned(condition) {\n\t\t\t\tlet res;\n\t\t\t\tconst containerSize = getElementPosition(that._layout.el);\n\t\t\t\tconst windowSize = getWindowPosition();\n\n\t\t\t\tswitch (condition) {\n\t\t\t\t\tcase VP_TOP.IS_BELOW_CONTAINER_TOP:\n\t\t\t\t\t\tres = windowSize.top >= containerSize.top;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase VP_TOP.IS_BELOW_CONTAINER_MIDDLE:\n\t\t\t\t\t\tres =\n\t\t\t\t\t\t\twindowSize.top >= containerSize.top + containerSize.height / 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase VP_BOTTOM.IS_ABOVE_CONTAINER_BOTTOM:\n\t\t\t\t\t\tres = windowSize.bottom <= containerSize.bottom;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase VP_BOTTOM.IS_ABOVE_CONTAINER_MIDDLE:\n\t\t\t\t\t\tres =\n\t\t\t\t\t\t\twindowSize.bottom <= containerSize.top + containerSize.height / 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase VP_BOTTOM.IS_BELOW_CONTAINER_MIDDLE:\n\t\t\t\t\t\tres =\n\t\t\t\t\t\t\twindowSize.bottom >= containerSize.top + containerSize.height / 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CONTAINER_POSITION.IS_PARTIALLY_WITHIN_VP:\n\t\t\t\t\t\tres =\n\t\t\t\t\t\t\twindowSize.bottom >= containerSize.top &&\n\t\t\t\t\t\t\twindowSize.top <= containerSize.bottom;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CONTAINER_POSITION.IS_WITHIN_VP:\n\t\t\t\t\t\tres =\n\t\t\t\t\t\t\twindowSize.top <= containerSize.top &&\n\t\t\t\t\t\t\twindowSize.bottom >= containerSize.bottom;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t'This position from viewport (' +\n\t\t\t\t\t\t\t\tcondition +\n\t\t\t\t\t\t\t\t') is not yet implemented'\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\treturn res;\n\t\t\t}\n\t\t};\n\n\t\tconst shouldDisable = stickyIsOnElement(\n\t\t\t'#taboola-below-article-thumbnails, #taboola-mobile-below-article-thumbnails',\n\t\t\tthis._stickyRect as DOMRect\n\t\t);\n\t\tstickUnstickHandler(shouldDisable);\n\n\t\tfunction stickyIsOnElement(selector: string, stickyRect: DOMRect) {\n\t\t\tlet targetEl: Element | null = null;\n\t\t\tlet targetRect: DOMRect | null = null;\n\n\t\t\tif (!selector) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t'[Sticky Player Plugin::_stickyIsOnElement] Missing mandatory `selector` parameter'\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttargetEl = document.querySelector(selector);\n\t\t\ttargetRect = targetEl\n\t\t\t\t? (targetEl as HTMLElement).getBoundingClientRect()\n\t\t\t\t: null;\n\n\t\t\treturn stickyIsOnTarget(targetRect, stickyRect);\n\n\t\t\t/**\n\t\t\t * Check if the sticky is inside the target\n\t\t\t * @param {DOMRect} targetRect The target DOMRect\n\t\t\t * @param {DOMRect} stickyRect The sticky DOMRect\n\t\t\t * @returns Wether the sticky is entered on target element. False if there is no sticky or no target\n\t\t\t */\n\t\t\tfunction stickyIsOnTarget(\n\t\t\t\ttargetRect: DOMRect | null,\n\t\t\t\tstickyRect: DOMRect | null\n\t\t\t) {\n\t\t\t\treturn !targetRect || !stickyRect\n\t\t\t\t\t? false\n\t\t\t\t\t: // TODO: Implement resize function and uncomment the following lines to be able to check horizontally\n\t\t\t\t\t // targetRect.left < stickyRect.right &&\n\t\t\t\t\t // targetRect.right > stickyRect.left &&\n\t\t\t\t\t targetRect.top <= stickyRect.bottom &&\n\t\t\t\t\t\t\ttargetRect.bottom >= stickyRect.top;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Initialize the feature\n\t */\n\tprivate _init() {\n\t\tthis.enabled = !isStickySessionDisabled();\n\t\tif (!this.enabled) return;\n\n\t\tthis._initListeners(this._listenersActions);\n\n\t\tthis.screenOrientationChanged$.subscribe(this._updatePlayerBoundingRect);\n\t}\n\n\tprivate _updatePlayerBoundingRect() {\n\t\tl.debug('Updating Layout Bounding Rect')();\n\t\tthis._stickyRect = this._layout.playerWrapper.getBoundingClientRect();\n\t}\n\n\tprivate _initListeners = (listenersActions: ListenerAction[]) =>\n\t\tlistenersActions.forEach((listenAction) =>\n\t\t\tPubSub.subscribe(listenAction.message, listenAction.actionFn.bind(this))\n\t\t);\n\n\tprivate _initLayout = (\n\t\tlayout: StickyFormats,\n\t\toptions: StickyFormatOptions\n\t) => {\n\t\t/**\n\t\t * Select and Spawn the layout\n\t\t */\n\t\tconst getLayout = (\n\t\t\tformat: StickyFormats,\n\t\t\toptions: StickyFormatOptions\n\t\t): StickyLayout => {\n\t\t\tlet layout: StickyLayout;\n\t\t\tconst closeBtnSwitchFeatureEnabled = typeof this._stickyFormatOptions\n\t\t\t\t.closeBtnSwitchFeatureEnabled\n\t\t\t\t? Boolean(this._stickyFormatOptions.closeBtnSwitchFeatureEnabled)\n\t\t\t\t: true;\n\t\t\tconst defaultSettings = {\n\t\t\t\tplayerId: this._instance.player.id,\n\t\t\t\tplayerContainerId: this._instance.player.id + '-container',\n\t\t\t\tcloseBtnSwitchFeatureEnabled\n\t\t\t};\n\t\t\tconst defaultStickyClass = 'sticky-player';\n\n\t\t\tswitch (format) {\n\t\t\t\tcase StickyFormats.BANNER:\n\t\t\t\t\t{\n\t\t\t\t\t\tconst stickedClasses = [defaultStickyClass];\n\t\t\t\t\t\tconst formatOptions = options as BannerStickyOptions;\n\n\t\t\t\t\t\tlayout = new BannerStickyLayout({\n\t\t\t\t\t\t\t...defaultSettings,\n\t\t\t\t\t\t\tstickedClasses,\n\t\t\t\t\t\t\tdisplayVideosInfos: formatOptions.displayDetails,\n\t\t\t\t\t\t\tposition: formatOptions.position\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault: {\n\t\t\t\t\tconst stickedClasses = [\n\t\t\t\t\t\tdefaultStickyClass,\n\t\t\t\t\t\t`sticky-${this._stickTo}`\n\t\t\t\t\t];\n\n\t\t\t\t\tconst formatOptions = options as FlyingStickyOptions;\n\n\t\t\t\t\tif (formatOptions && formatOptions.size === 'large') {\n\t\t\t\t\t\tstickedClasses.push('flying-sticky-large');\n\t\t\t\t\t}\n\n\t\t\t\t\tlayout = new FlyingStickyLayout({\n\t\t\t\t\t\t...defaultSettings,\n\t\t\t\t\t\tstickedClasses\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn layout;\n\t\t};\n\n\t\tconst handleLayoutEvents = (event: StickyLayoutEvents) => {\n\t\t\tconst handlers = {\n\t\t\t\t[StickyButtonsEvents.CLOSE]: this._disable.bind(\n\t\t\t\t\tthis,\n\t\t\t\t\tfalse,\n\t\t\t\t\ttrue,\n\t\t\t\t\t'user closing'\n\t\t\t\t),\n\t\t\t\t[StickyButtonsEvents.GO_TO_PLAYER]: this._scrollToPlayer,\n\t\t\t\tnotYetImplemented: () =>\n\t\t\t\t\tconsole.error(`This event is not yet implemented: ${event}`)\n\t\t\t};\n\n\t\t\tconst actionFn = handlers[event] || handlers.notYetImplemented;\n\t\t\tactionFn.apply(this);\n\t\t};\n\n\t\tthis._layout = getLayout(layout, options);\n\t\tthis._layout.events$.subscribe(handleLayoutEvents);\n\n\t\tconst shouldUpdateDetails =\n\t\t\tlayout === StickyFormats.BANNER &&\n\t\t\t(options as BannerStickyOptions).displayDetails;\n\n\t\tif (!shouldUpdateDetails) return;\n\n\t\t// Update video infos if needed\n\t\tconst subject$ = (this._layout as BannerStickyLayout)\n\t\t\t.stickyBannerVideosInfos$;\n\n\t\tthis._instance.player.videoInfos$\n\t\t\t.pipe(distinctUntilChanged())\n\t\t\t.subscribe((videoInfos) => {\n\t\t\t\tconst duration = videoInfos.durationSeconds\n\t\t\t\t\t? formatSecondsToMinutes(videoInfos.durationSeconds)\n\t\t\t\t\t: undefined;\n\n\t\t\t\tsubject$.next({\n\t\t\t\t\ttitle: videoInfos.title,\n\t\t\t\t\tduration\n\t\t\t\t});\n\t\t\t});\n\t};\n\n\tprivate _onPlayerReady(id: string, contentStarted?: boolean) {\n\t\tif (\n\t\t\t!this.enabled ||\n\t\t\tid !== this._id ||\n\t\t\t(!contentStarted && this._waitForAdLoaded && !this._adLoaded)\n\t\t) {\n\t\t\tif (this._waitForAdLoaded && !this._adLoaded) {\n\t\t\t\tif (this._scrollUp) return; // Do not force play if video cannot stick right now\n\n\t\t\t\t// Force play as the player could not be visible and we are waiting for ad loaded to activate sticky\n\t\t\t\tthis._instance.player.play();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis._player = this._instance.player;\n\n\t\tconst playerContainer = this._player.getContainer();\n\t\tif (!playerContainer) return;\n\n\t\tthis._container = playerContainer;\n\t\tthis._stickyReady = true;\n\t}\n\n\t/**\n\t * Register the first player instance and generate\n\t * @param {StoreInstance} storeInstance\n\t */\n\tprivate _registerInstance(storeInstance: StoreInstance) {\n\t\tconst getDefaultFormatOptions = (\n\t\t\tformat: StickyFormats\n\t\t): StickyFormatOptions => {\n\t\t\tlet res: any;\n\n\t\t\tswitch (format) {\n\t\t\t\tcase StickyFormats.FLYING:\n\t\t\t\t\t{\n\t\t\t\t\t\t(res as FlyingStickyOptions) = {\n\t\t\t\t\t\t\tsize: 'normal'\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase StickyFormats.BANNER:\n\t\t\t\t\t{\n\t\t\t\t\t\t(res as BannerStickyOptions) = {\n\t\t\t\t\t\t\tdisplayDetails: false,\n\t\t\t\t\t\t\tposition: 'bottom'\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow new Error(`Sticky format '${format}' is not yet implemented`);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tres.closeBtnSwitchFeatureEnabled = true;\n\t\t\treturn res;\n\t\t};\n\n\t\tconst player = storeInstance.player;\n\t\tconst stickyOptions = storeInstance.sticky;\n\n\t\tthis._instance = storeInstance;\n\t\tthis._id = player.id;\n\t\tthis._stickTo = stickyOptions.stickTo;\n\t\tthis._waitForAdLoaded = stickyOptions.waitForAdLoaded;\n\t\tthis._scrollUp = stickyOptions.scrollUp;\n\t\tthis._stickBothSide = stickyOptions.stickBothSide;\n\t\tthis._stickyFormat = stickyOptions.format || StickyFormats.FLYING;\n\t\tthis._stickyFormatOptions =\n\t\t\tstickyOptions.formatOptions ||\n\t\t\tgetDefaultFormatOptions(this._stickyFormat);\n\t}\n\t66;\n\tprivate _scrollToPlayer() {\n\t\tconst topPosition =\n\t\t\tthis._layout.el.getBoundingClientRect().top +\n\t\t\tdocument.documentElement.scrollTop -\n\t\t\tDEFAULT_SETTINGS.SCROLL_OFFSET;\n\n\t\twindow.scrollTo({\n\t\t\ttop: topPosition,\n\t\t\tbehavior: 'smooth'\n\t\t});\n\n\t\tthis._updatePlayerBoundingRect();\n\t}\n\n\t/**\n\t * Cancel the disabling timeout\n\t */\n\tprivate _cancelDisablingTimeout() {\n\t\tclearTimeout(this._onCompleteTimeout as any);\n\t\tthis._onCompleteTimeout = null;\n\t}\n\n\t/**\n\t * Disable the sticky feature\n\t * @param {boolean} persistant\n\t */\n\tprivate _disable(\n\t\tdisabledForSession?: boolean,\n\t\tdisabledForPage?: boolean,\n\t\treason?: string\n\t) {\n\t\tl.info(`Sticky disabled. Reason: ${reason}`);\n\n\t\tthis.enabled = false;\n\t\tthis.unstick();\n\n\t\tif (disabledForPage || disabledForSession) {\n\t\t\tif (disabledForPage) {\n\t\t\t\tthis._disabledForPage = true;\n\t\t\t}\n\n\t\t\tif (disabledForSession) {\n\t\t\t\tsetDisabledStickyForSessionState();\n\t\t\t}\n\n\t\t\tthis._player.publish(PublishableVideoStickyEvents.CLOSE);\n\t\t}\n\t}\n\n\t/**\n\t * Move the player to avoid collisions\n\t */\n\tprivate _moveStickyToCollisionPosition() {\n\t\tthis._movePlayer(\n\t\t\t'-' + this._xPosExtra + 'px',\n\t\t\t'-' + this._yPosExtra + 'px'\n\t\t);\n\t}\n\n\t/**\n\t * Reset sticky to initial position\n\t */\n\tprivate _resetStickyPosition() {\n\t\tthis._movePlayer(0, 0);\n\t}\n\n\t/**\n\t * Move the player to the give x y position\n\t * @param {number} xPos Horizontal position\n\t * @param {number} yPos Vertical position\n\t */\n\tprivate _movePlayer(xPos: number | string, yPos: number | string) {\n\t\t// Do nothing if new position is the same\n\t\tif (xPos === this._xPos && yPos === this._yPos) return;\n\n\t\t// Save new position\n\t\tthis._xPos = xPos;\n\t\tthis._yPos = yPos;\n\n\t\tapplyCssTranslate(\n\t\t\tthis._container.parentNode as HTMLElement,\n\t\t\t+this._xPos,\n\t\t\t+this._yPos\n\t\t);\n\t}\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.Sticky = (options: StickyPluginOptions) =>\n\tnew StickyPlugin(options);\n","export function mergeFunctions(...funcs: Function[]) {\n\treturn function (...args: any[]) {\n\t\tfuncs.filter((fn) => !!fn).forEach((fn) => fn?.(...args));\n\t};\n}\n","import { setChildren, mount } from 'redom';\nimport { getClassname } from 'src/plugins/sticky/utils/get-classname.util';\nimport { StickyPlaceholder } from '../../global/placeholder/placeholder.component';\nimport { StickyButtonsBar } from '../../global/buttons-bar/buttons-bar.component';\nimport { StickyBaseLayout } from '../base-layout';\nimport { FlyingLayoutSettings } from './flying-layout.interface';\nimport { from } from 'rxjs';\nimport { distinctUntilChanged } from 'rxjs/operators';\nimport { StickyButtonsEvents } from 'src/plugins/sticky/enums/buttons-events.enum';\nimport { Visibility } from 'src/plugins/sticky/enums/visibility.enum';\n\nexport class FlyingStickyLayout extends StickyBaseLayout {\n\tbackground: StickyPlaceholder;\n\tbuttonsBar: StickyButtonsBar;\n\n\tconstructor(settings: FlyingLayoutSettings) {\n\t\tconst { customClass } = settings;\n\t\tsuper({\n\t\t\t...settings,\n\t\t\tcustomClass: getClassname(['sticky-flying-layout'], customClass)\n\t\t});\n\n\t\tthis.background = new StickyPlaceholder({\n\t\t\tcustomClass: 'flying-layout-background'\n\t\t});\n\t\tthis.buttonsBar = new StickyButtonsBar({\n\t\t\tcustomClass: 'flying-layout-buttons'\n\t\t});\n\n\t\tsetChildren(this.playerWrapper, [this.buttonsBar, this.playerElement]);\n\t\tsetChildren(this.el, [this.background, this.playerWrapper]);\n\n\t\tthis.toggleableElements = [this.background, this.buttonsBar];\n\n\t\tthis.events$ = from(this.buttonsBar.events$);\n\t\tthis.sticked$.next(false);\n\n\t\tthis.closeBtnVisibility$.pipe(distinctUntilChanged()).subscribe((state: Visibility) => {\n\t\t\tthis.buttonsBar.switchVisibility$.next({\n\t\t\t\tbtn: StickyButtonsEvents.CLOSE,\n\t\t\t\tstate\n\t\t\t})\n\t\t});\n\n\t\tthis.mount();\n\t}\n\n\tmount = () => mount(this.parentNode, this);\n}\n","import { setChildren, mount, el } from 'redom';\nimport { getClassname } from 'src/plugins/sticky/utils/get-classname.util';\nimport { StickyPlaceholder } from '../../global/placeholder/placeholder.component';\nimport { StickyButtonsBar } from '../../global/buttons-bar/buttons-bar.component';\nimport { StickyBaseLayout } from '../base-layout';\nimport { from, Subject, Subscription } from 'rxjs';\nimport { distinctUntilChanged } from 'rxjs/operators';\nimport { BannerLayoutSettings } from './banner-layout.interface';\nimport { StickyBaseElement } from '../../base-element';\nimport { Visibility } from 'src/plugins/sticky/enums/visibility.enum';\nimport { StickyButtonsEvents } from 'src/plugins/sticky/enums/buttons-events.enum';\n\nexport interface StickyBannerVideoInfo {\n\ttitle: string;\n\tduration?: string;\n}\n\nexport class BannerStickyLayout extends StickyBaseLayout {\n\tbackground: StickyPlaceholder;\n\tbuttonsBar: StickyButtonsBar;\n\tcontentWrapper: StickyBaseElement;\n\tvideoInfosElement: StickyBaseElement;\n\tstickyBannerVideosInfos$ = new Subject();\n\n\tprivate _subscriptions: Subscription[] = [];\n\tprivate _videoTitleElement: StickyBaseElement;\n\tprivate _videoDurationElement: StickyBaseElement;\n\n\tconstructor(settings: BannerLayoutSettings) {\n\t\tlet { customClass, displayVideosInfos, position = 'bottom' } = settings;\n\t\tcustomClass = customClass ?? [];\n\n\t\tconst customClassList =\n\t\t\ttypeof customClass === 'string' ? [customClass] : customClass;\n\n\t\tsuper({\n\t\t\t...settings,\n\t\t\tcustomClass: getClassname(['sticky-banner-layout'], customClassList)\n\t\t});\n\n\t\tthis.background = new StickyPlaceholder({\n\t\t\tcustomClass: 'banner-layout-background'\n\t\t});\n\n\t\tthis.buttonsBar = new StickyButtonsBar({\n\t\t\tcustomClass: 'banner-layout-buttons'\n\t\t});\n\n\t\tthis.contentWrapper = new StickyBaseElement(\n\t\t\tel('sticky-content-wrapper'),\n\t\t\t'sticky-content-wrapper'\n\t\t);\n\n\t\tthis.videoInfosElement = new StickyBaseElement(\n\t\t\tel('sticky-video-infos'),\n\t\t\t'sticky-video-infos'\n\t\t);\n\n\t\tthis._videoTitleElement = new StickyBaseElement(el('p'), 'video-title');\n\t\tthis._videoDurationElement = new StickyBaseElement(\n\t\t\tel('p'),\n\t\t\t'video-duration'\n\t\t);\n\t\tsetChildren(this.videoInfosElement, [\n\t\t\tthis._videoTitleElement,\n\t\t\tthis._videoDurationElement\n\t\t]);\n\n\t\tsetChildren(this.contentWrapper, [\n\t\t\tthis.playerElement,\n\t\t\tthis.videoInfosElement\n\t\t]);\n\t\tsetChildren(this.playerWrapper, [this.buttonsBar, this.contentWrapper]);\n\t\tsetChildren(this.el, [this.background, this.playerWrapper]);\n\n\t\tthis.toggleableElements = [\n\t\t\tthis.background,\n\t\t\tthis.buttonsBar,\n\t\t\tthis.videoInfosElement\n\t\t];\n\n\t\tthis.events$ = from(this.buttonsBar.events$);\n\n\t\tthis.setPosition(position);\n\t\tthis.toggleVideosInfo(displayVideosInfos ? true : false);\n\t\tthis.sticked$.next(false);\n\n\t\tthis.closeBtnVisibility$.pipe(distinctUntilChanged()).subscribe((state: Visibility) => {\n\t\t\tthis.buttonsBar.switchVisibility$.next({\n\t\t\t\tbtn: StickyButtonsEvents.CLOSE,\n\t\t\t\tstate\n\t\t\t})\n\t\t});\n\n\t\tthis.mount();\n\t}\n\n\tonmount() {\n\t\tconst subscription = this.stickyBannerVideosInfos$.subscribe(\n\t\t\t(videoInfo) => {\n\t\t\t\tthis._videoTitleElement.el.textContent = videoInfo.title;\n\t\t\t\tthis._videoDurationElement.el.textContent = '' + videoInfo.duration;\n\t\t\t}\n\t\t);\n\n\t\tthis._subscriptions.push(subscription);\n\t}\n\n\tonunmount() {\n\t\tthis._subscriptions.forEach((sub) => sub.unsubscribe());\n\t}\n\n\ttoggleVideosInfo(force: boolean) {\n\t\tthis.el.classList.toggle('video-infos-displayed', force);\n\t}\n\n\tsetPosition(position: 'top' | 'bottom') {\n\t\tconst addedClass = position === 'top' ? 'position-top' : 'position-bottom';\n\t\tconst removedClass =\n\t\t\tposition === 'top' ? 'position-bottom' : 'position-top';\n\n\t\tthis.el.classList.remove(removedClass);\n\t\tthis.el.classList.add(addedClass);\n\t}\n\n\tmount = () => mount(this.parentNode, this);\n}\n","const disabledStickySessionVarName = 'stickySessionDisabled';\n\nconst isStickySessionDisabled = () =>\n\ttypeof sessionStorage.getItem(disabledStickySessionVarName) !== 'undefined' &&\n\tBoolean(sessionStorage.getItem(disabledStickySessionVarName));\n\nconst setDisabledStickyForSessionState = () =>\n\tsessionStorage.setItem(disabledStickySessionVarName, 'true');\n\nexport { isStickySessionDisabled, setDisabledStickyForSessionState };\n","//get element size+position\ninterface ElementPosition {\n\tleft: number;\n\ttop: number;\n\tright: number;\n\tbottom: number;\n\twidth: number;\n\theight: number;\n}\n\nconst getElementPosition = (o: HTMLElement): ElementPosition => {\n\tlet left = 0;\n\tlet top = 0;\n\tlet right = 0;\n\tlet bottom = 0;\n\n\tlet body = document.body;\n\tlet width = o.offsetWidth;\n\tlet height = o.offsetHeight;\n\n\tlet offSetParent = o.offsetParent;\n\n\tif (offSetParent) {\n\t\tlet p: any = o;\n\t\tleft = o.offsetLeft - o.scrollLeft;\n\t\ttop = o.offsetTop - o.scrollTop;\n\t\twhile ((p = p.offsetParent)) {\n\t\t\tif (!p) break;\n\t\t\tleft += p.offsetLeft - (p != body ? p.scrollLeft : 0);\n\t\t\ttop += p.offsetTop - (p != body ? p.scrollTop : 0);\n\t\t}\n\t}\n\n\tright = left + width;\n\tbottom = top + height;\n\n\treturn { left, top, right, bottom, width, height };\n};\n\n// Get window size + position\nconst getWindowPosition = (): ElementPosition => {\n\tconst w = window,\n\t\te = document.documentElement,\n\t\tb = document.body;\n\n\tconst width = w.innerWidth\n\t\t? w.innerWidth\n\t\t: e && e.clientWidth\n\t\t? e.clientWidth\n\t\t: b && b.clientWidth\n\t\t? b.clientWidth\n\t\t: 0;\n\n\tconst height = w.innerHeight\n\t\t? w.innerHeight\n\t\t: e && e.clientHeight\n\t\t? e.clientHeight\n\t\t: b && b.clientHeight\n\t\t? b.clientHeight\n\t\t: 0;\n\n\tconst left = w.pageXOffset\n\t\t? w.pageXOffset\n\t\t: e && e.scrollLeft\n\t\t? e.scrollLeft\n\t\t: b && b.scrollLeft\n\t\t? b.scrollLeft\n\t\t: 0;\n\n\tconst top = w.pageYOffset\n\t\t? w.pageYOffset\n\t\t: e && e.scrollTop\n\t\t? e.scrollTop\n\t\t: b && b.scrollTop\n\t\t? b.scrollTop\n\t\t: 0;\n\n\tconst right = left + width;\n\tconst bottom = top + height;\n\n\treturn { left, top, right, bottom, width, height };\n};\n\n/**\n * Get visibility percent of element in viewport\n */\nconst percentInViewport = (el: Element | null, topOffset?: number): number => {\n\tif (!el) {\n\t\treturn 0;\n\t}\n\n\tvar rect = el.getBoundingClientRect();\n\tvar wSize = getWindowPosition();\n\tvar visibleHeight = rect.height - (topOffset || 0);\n\tvar visibleWidth = rect.width;\n\tvar totalSize = visibleHeight * visibleWidth;\n\n\t// A part of element is above viewport\n\tif (rect.top < 0 && rect.bottom > 0) {\n\t\tvisibleHeight += rect.top;\n\t}\n\n\t// A part of element is below viewport\n\tif (rect.bottom > wSize.height && rect.top < wSize.height) {\n\t\tvisibleHeight += wSize.height - rect.bottom;\n\t}\n\n\t// Element is totally above or below viewport\n\tif (\n\t\tMath.max(rect.top, rect.bottom) < 0 ||\n\t\tMath.min(rect.bottom, rect.top) > wSize.height\n\t) {\n\t\tvisibleHeight = 0;\n\t}\n\n\t// A part of element is on the left of viewport\n\tif (rect.left < 0 && rect.right > 0) {\n\t\tvisibleWidth += rect.left;\n\t}\n\n\t// A part of element is on the right of viewport\n\tif (rect.right > wSize.width && rect.left < wSize.width) {\n\t\tvisibleWidth += wSize.width - rect.right;\n\t}\n\n\t// Element is totally on the right/left of viewport\n\tif (\n\t\tMath.max(rect.left, rect.right) < 0 ||\n\t\tMath.min(rect.left, rect.right) > wSize.width\n\t) {\n\t\tvisibleWidth = 0;\n\t}\n\n\treturn (visibleHeight * visibleWidth) / totalSize;\n};\n\n/**\n * Detect if element is in viewport\n */\nconst isInViewport = (\n\tel: HTMLElement | null,\n\tpercent = 1,\n\ttopOffset?: number\n): boolean => percentInViewport(el, topOffset) >= percent;\n\nexport { getElementPosition, getWindowPosition, isInViewport };\n","export const formatSecondsToMinutes = (s: number): string => {\n\tconst minutes = Math.floor(s / 60);\n\tconst seconds = Math.floor(s % 60);\n\tconst mn = minutes < 10 ? '0' + minutes : minutes;\n\tconst sec = seconds < 10 ? '0' + seconds : seconds;\n\n\treturn `${mn}:${sec}`;\n};\n","export const applyCssTranslate = (elt: HTMLElement, x: number, y: number) => {\n\twindow.requestAnimationFrame(() =>\n\t\t'transform webkitTransform mozTransform oTransform msTransform'\n\t\t\t.split(' ')\n\t\t\t.forEach(\n\t\t\t\t(prefix) =>\n\t\t\t\t\t(elt.style[prefix] = `translate(' + ${x} + ', ' + ${y} + ')`)\n\t\t\t)\n\t);\n};\n","// This file's responsability is to centralize all data about all specific videoplayers instances\n\nimport { StickySettings } from './interfaces/sticky-settings.interface';\nimport { DailymotionEmbedPlayer } from './players/dailymotion-embed';\nimport { JwPlayer } from './players/jwplayer';\nimport { VJsPlayer } from './players/video-js';\nimport { isInViewport } from './plugins/sticky/utils/dom.util';\nimport PubSub from 'pubsub-js';\n\nexport interface StoreInstance {\n\tplayer: JwPlayer | VJsPlayer | DailymotionEmbedPlayer;\n\tadPlayer: any;\n\tlogger: any;\n\tsticky: StickySettings & { enabled?: boolean };\n\tautoplay: any;\n\tcontext: any;\n\tposition: any;\n}\n\nexport class Store {\n\tprivate viewableTreshold = 0.5;\n\tprivate static instance: Store;\n\tprivate constructor() {}\n\tinstances: Map = new Map();\n\tcurrentPlayableInstanceId: string;\n\n\tpublic addInstance(id: string, instance: StoreInstance): void {\n\t\tif (!instance.player) {\n\t\t\tinstance.logger.logError(\n\t\t\t\t'Invalid player instance: a mandatory information is missing'\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconsole.log('id', id);\n\t\tconst thisInstance = this.instances.get(id);\n\t\tif (thisInstance) {\n\t\t\tinstance.logger.logError(\n\t\t\t\t'A player has already been initialized with this id: ' + id\n\t\t\t);\n\n\t\t\tconsole.error('found instance', thisInstance);\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Block autoplay by default until player is ready\n\t\tinstance.autoplay.enabled = instance.autoplay.enabled || false;\n\n\t\t// Add everything to the store\n\t\tthis.instances.set(id, instance);\n\n\t\tPubSub.publish('video.store.addInstance', {\n\t\t\tid: id,\n\t\t\tinstance: this.instances.get(id)\n\t\t});\n\t}\n\n\tpublic getInstance(id: string) {\n\t\treturn this.instances.get(id);\n\t}\n\n\tpublic getCurrentPlayableInstance(): StoreInstance | undefined {\n\t\treturn this.getInstance(this.currentPlayableInstanceId);\n\t}\n\n\tpublic setCurrentPlayableInstanceId(id: string): void {\n\t\tthis.currentPlayableInstanceId = id;\n\t}\n\n\tpublic isPlaying = async (instance: StoreInstance): Promise =>\n\t\tinstance &&\n\t\t((instance.adPlayer && instance.adPlayer.isPlaying()) ||\n\t\t\tawait instance.player?.isPlaying());\n\n\tpublic getActivePlayer = (instance) =>\n\t\tinstance.adPlayer && instance.adPlayer.isActive()\n\t\t\t? instance.adPlayer\n\t\t\t: instance.player;\n\n\tpublic isViewable = (instance: StoreInstance): boolean =>\n\t\tinstance &&\n\t\tisInViewport(\n\t\t\tinstance.player?.getContainer() as HTMLElement,\n\t\t\tthis.viewableTreshold\n\t\t);\n\n\tpublic static get(): Store {\n\t\tif (!Store.instance) {\n\t\t\tStore.instance = new Store();\n\t\t}\n\n\t\treturn Store.instance;\n\t}\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.Store = window.AufVideo.Store || Store;\n","/**\n * This file's responsability is to initialize objects previously created by the spawner\n */\n\nimport DailymotionEmbedAdPlayer from './adPlayers/dailymotion-embed';\nimport { PublishableVideoStickyEvents } from './enums/publishable-events.enum';\nimport { VideoPlugins } from './enums/video-plugins.enum';\nimport { AdsParams } from './interfaces';\nimport { DailymotionEmbedPlayer } from './players/dailymotion-embed';\nimport { AnalyticsPlugin } from './plugins/analytics/analytics';\nimport { AutoplayPlugin } from './plugins/autoplay/autoplay';\nimport { DebugPlugin } from './plugins/debug/debug';\nimport { StickyPlugin } from './plugins/sticky/sticky-core';\n\nimport { Store, StoreInstance } from './store';\nimport { PlayerInstance } from './types/player-instance.type';\nimport { AufVideoUtils } from './utils/utils';\nimport { VideoConsoleLogger } from './utils/video-logger';\nimport AfLogger from '@vendor/auf/afLogger';\nimport PubSub from 'pubsub-js';\nimport { PegasusResponseBids } from './interfaces/pegasus-response-bids.interface';\n\nconst logger = new VideoConsoleLogger();\nconst afLogger = new AfLogger({ disableSessionData: true });\n\nexport interface ManagerOptions {\n\tlabels?: any;\n}\n\nconst PEGASUS_TIMEOUT = 7000;\n\nexport class Manager {\n\tprivate labels;\n\tprivate store: Store;\n\tprivate storeInstance: StoreInstance;\n\tpublic plugins: Map = new Map();\n\tprivate static instance: Manager;\n\n\tconstructor(options: ManagerOptions = {}) {\n\t\tthis.labels = options.labels;\n\t\tthis._init();\n\t}\n\n\t// TODO @4lador: Check if that still deserve a purpose\n\tpublic logConsole = (logs: string, service?: string) =>\n\t\tafLogger.logConsole(logs, 'log', service);\n\n\tprivate _init(): void {\n\t\t// Mandatory initializations\n\t\tthis.store = Store.get();\n\n\t\tthis._initListeners();\n\n\t\tconst plugins = [\n\t\t\tVideoPlugins.ANALYTICS,\n\t\t\tVideoPlugins.STICKY,\n\t\t\tVideoPlugins.AUTOPLAY\n\t\t];\n\n\t\tconst isLocal = location.host.indexOf('local') === 0;\n\n\t\tif (isLocal) {\n\t\t\tplugins.push(VideoPlugins.DEBUG);\n\t\t}\n\n\t\tthis._initPlugins(plugins);\n\t\tthis._initScrollListener();\n\t}\n\n\tprivate _initListeners(): void {\n\t\tconst that = this;\n\n\t\t// Init instance once it has been registered to the store\n\t\tPubSub.subscribe(\n\t\t\t'video.store.addInstance',\n\t\t\tasync (msg, data) => {\n\t\t\t\tlogger.debug(`AddInstance msg received from ${data?.instance?.player?.id}`)();\n\t\t\t\tawait this._initInstance(data.instance);\n\t\t\t}\n\t\t);\n\n\t\tinitAutopause();\n\n\t\tfunction initAutopause() {\n\t\t\t// Automatically pause the previous playing instance when a player starts / resumes\n\t\t\tPubSub.subscribe('video.store.playingInstance.update', (msg, data) =>\n\t\t\t\tthat._pausePreviousPlayingInstance(data.id)\n\t\t\t);\n\t\t\tPubSub.subscribe('video.ad.start', (msg, data) =>\n\t\t\t\tthat._pausePreviousPlayingInstance(data.id)\n\t\t\t);\n\t\t\tPubSub.subscribe('video.ad.resume', (msg, data) =>\n\t\t\t\tthat._pausePreviousPlayingInstance(data.id)\n\t\t\t);\n\t\t\tPubSub.subscribe('video.player.start', (msg, data) =>\n\t\t\t\tthat._pausePreviousPlayingInstance(data.id)\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async _initInstance(instance: StoreInstance): Promise {\n\t\tthis.storeInstance = instance;\n\n\t\tif (!(window as any).gdprAppliesGlobally) {\n\t\t\tawait this._initPlayers(instance);\n\t\t}\n\n\t\t// TODO: Type Didomi\n\t\tconst didomiOnReady = ((window as any).didomiOnReady =\n\t\t\t(window as any).didomiOnReady || []);\n\n\t\tdidomiOnReady.push(async () => {\n\t\t\tconst didomi = (window as any).Didomi;\n\t\t\tconst consentShouldBeCollected = didomi.shouldConsentBeCollected();\n\t\t\tconst didomiEventListeners: { event: string; listener: Function }[] = (\n\t\t\t\twindow as any\n\t\t\t).didomiEventListeners;\n\n\t\t\tif (consentShouldBeCollected) {\n\t\t\t\t// If CMP consent notice popup is shown, defer players init until popup has been closed\n\t\t\t\tdidomiEventListeners.push({\n\t\t\t\t\tevent: 'notice.hidden',\n\t\t\t\t\tlistener: async () => await this._initPlayers(instance)\n\t\t\t\t});\n\n\t\t\t\tlogger.debug(`Init player ${instance.player.id} pushed to Didomi listener`)();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Otherwise init players directly because it means user has already given his consent\n\t\t\tawait this._initPlayers(instance);\n\t\t});\n\t}\n\n\tprivate async _initPlayers(\n\t\tinstance: StoreInstance = this.storeInstance\n\t): Promise {\n\t\tconst player = instance.player;\n\t\tconst adPlayer = instance.adPlayer;\n\t\tconst npaActivated = adPlayer && adPlayer._getNpaFromCmp() === '0';\n\t\tconst usePegasus = adPlayer && npaActivated && adPlayer.needPegasus;\n\t\tconst pegasus = (window as any).top.pegasus || { cmd: [] };\n\t\tconst lazyLoadDailymotion =\n\t\t\tusePegasus && instance.player.name === 'dailymotion-embed';\n\t\tconst that = this;\n\n\t\tconst pushToPegasus = () => {\n\t\t\tconst pegasusHandler = async (responseBids: PegasusResponseBids) =>\n\t\t\t\tawait playerInitWithPegasus(player, adPlayer, responseBids);\n\n\t\t\tconst cbName = adPlayer._hbVideoActive\n\t\t\t\t? 'onHbVideoReady'\n\t\t\t\t: 'globalTargeted';\n\n\t\t\tpegasus.cmd.push({ disabledPreroll: pegasusHandler });\n\t\t\tpegasus.cmd.push({\n\t\t\t\t[cbName]: pegasusHandler\n\t\t\t});\n\n\t\t\tlogger.info(`init pushed to pegasus on ${cbName}`)();\n\t\t};\n\n\t\tif (usePegasus) {\n\t\t\tif (lazyLoadDailymotion) {\n\t\t\t\t(instance.player as DailymotionEmbedPlayer)\n\t\t\t\t\t.createLazyPlayer()\n\t\t\t\t\t.then(pushToPegasus);\n\t\t\t} else {\n\t\t\t\tpushToPegasus();\n\t\t\t}\n\n\t\t\tsetTimeout(async () => {\n\t\t\t\tconst isPegasusInitialized = (pegasus && pegasus.version) || (pegasus && pegasus.VERSION);\n\n\t\t\t\tif (!isPegasusInitialized) {\n\t\t\t\t\tlogger.error('Pegasus is not responding')();\n\n\t\t\t\t\t(instance.adPlayer as DailymotionEmbedAdPlayer).needPegasus = false;\n\t\t\t\t\tawait initPlayerWithoutPegasus();\n\t\t\t\t}\n\t\t\t}, PEGASUS_TIMEOUT);\n\t\t} else {\n\t\t\tawait initPlayerWithoutPegasus();\n\t\t}\n\n\t\tasync function initPlayerWithoutPegasus() {\n\t\t\tlogger.debug('initPlayerWithoutPegasus()')();\n\n\t\t\tawait player.init(await getAdParams(adPlayer), _playerInitCb);\n\n\t\t\tlogger.debug('Player initialized')();\n\n\t\t\tasync function _playerInitCb(): Promise {\n\t\t\t\tplayer.publish(PublishableVideoStickyEvents.STICKY_READY);\n\n\t\t\t\tif (!adPlayer) return Promise.resolve();\n\n\t\t\t\tawait initAdPlayer(that.store, player);\n\n\t\t\t\treturn Promise.resolve();\n\t\t\t}\n\t\t}\n\n\t\t// TODO: Type this function && type adPlayer && type responseBids\n\t\tasync function playerInitWithPegasus(\n\t\t\tplayer: PlayerInstance,\n\t\t\tadPlayer: any,\n\t\t\tresponseBids?: any\n\t\t) {\n\t\t\tlogger.debug('Player Init With Pegasus')();\n\t\t\tconst isPrerollDisabled = ((\n\t\t\t\tplayer as DailymotionEmbedPlayer\n\t\t\t).isAdDisabled = (window as any).pegasus.getData(\n\t\t\t\t'adops.disableAdPreroll'\n\t\t\t));\n\n\t\t\tconst isResponseBids = typeof responseBids !== 'undefined';\n\t\t\tif (isResponseBids) {\n\t\t\t\tadPlayer.setHbResponses(responseBids);\n\t\t\t}\n\n\t\t\t// TODO: Type Pegasus\n\t\t\tconst pegasusAccount = (window as any).pegasus.getData(\n\t\t\t\t'adserver.dfp.account'\n\t\t\t);\n\n\t\t\tconst pegasusAdUnit = (window as any).pegasus.getData(\n\t\t\t\t'slots.instream.adUnitPath'\n\t\t\t);\n\n\t\t\tadPlayer.adUnit = '/' + pegasusAccount + '/' + pegasusAdUnit;\n\n\t\t\tlet adParams: AdsParams | undefined;\n\t\t\tif (isPrerollDisabled) {\n\t\t\t\t_disablePreroll(player);\n\t\t\t} else {\n\t\t\t\tadParams = await getAdParams(adPlayer);\n\t\t\t}\n\n\t\t\tlogger.info('Player init with Pegasus using adParams', adParams)();\n\n\t\t\tawait player.init(adParams, () =>\n\t\t\t\t_onPlayerInit(isPrerollDisabled, player)\n\t\t\t);\n\n\t\t\tfunction _disablePreroll(player: PlayerInstance): void {\n\t\t\t\tlogger.debug('_disablePreroll(player)', player)();\n\t\t\t\tplayer.cancelAdvertising();\n\t\t\t}\n\n\t\t\tasync function _onPlayerInit(\n\t\t\t\tdisablePreroll: boolean,\n\t\t\t\tplayer: PlayerInstance\n\t\t\t): Promise {\n\t\t\t\tif (!adPlayer || disablePreroll) return;\n\n\t\t\t\treplaceVariable();\n\t\t\t\tawait initAdPlayer(that.store, player);\n\n\t\t\t\t// Check if that deserve a real purpose\n\t\t\t\tplayer.publish(PublishableVideoStickyEvents.STICKY_READY);\n\n\t\t\t\tfunction replaceVariable() {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!adPlayer.replaceVariable ||\n\t\t\t\t\t\ttypeof adPlayer.replaceVariable !== 'function'\n\t\t\t\t\t)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tadPlayer.replaceVariable();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// TODO: Move that to Dailymotion adPlayer\n\t\tasync function getAdParams(adPlayerInstance) {\n\t\t\treturn adPlayerInstance\n\t\t\t\t? {\n\t\t\t\t\t\tui: adPlayerInstance.adUnit, // TODO cast to right class (not abstract)\n\t\t\t\t\t\tcustom: await adPlayerInstance.getAdTagCustomParameters()\n\t\t\t\t }\n\t\t\t\t: undefined;\n\t\t}\n\n\t\tasync function initAdPlayer(store: Store, player?: any): Promise {\n\t\t\tawait adPlayer.init(store, player);\n\t\t\tadPlayer.onApiLoaded();\n\t\t\treturn Promise.resolve();\n\t\t}\n\t}\n\n\tprivate _logError = (message: string, category?: string) =>\n\t\tafLogger.logError(message, category);\n\n\tprivate _pausePreviousPlayingInstance(id: string) {\n\t\tconst previousInstance = this.store.getCurrentPlayableInstance();\n\t\tif (previousInstance && id !== previousInstance.player.id) {\n\t\t\tif (previousInstance.adPlayer) {\n\t\t\t\tpreviousInstance.adPlayer.pause();\n\t\t\t}\n\n\t\t\tpreviousInstance.player.pause();\n\t\t}\n\n\t\t// Set current instance as the new playing instance\n\t\tthis.store.setCurrentPlayableInstanceId(id);\n\t}\n\n\t// Create a global listener on user scroll\n\tprivate _initScrollListener() {\n\t\tconst pluginsWithScrollHandlers = [\n\t\t\tthis.plugins.get('sticky'),\n\t\t\tthis.plugins.get('autoplay')\n\t\t];\n\n\t\tfunction globalScrollHandler() {\n\t\t\t// Handlers are called in the correct order and are not debounced functions as we need to control the execution order\n\t\t\t// As this global handler is already using debounce we don't need to chain debounced handlers\n\t\t\tpluginsWithScrollHandlers.forEach(function (plugin = {}) {\n\t\t\t\tconst handler = plugin.scrollEvent;\n\t\t\t\tif (handler && typeof handler === 'function') {\n\t\t\t\t\thandler.apply();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tdocument.addEventListener(\n\t\t\t'scroll',\n\t\t\tAufVideoUtils.throttle(globalScrollHandler, 50, {\n\t\t\t\tleading: true\n\t\t\t}),\n\t\t\t{ passive: true }\n\t\t);\n\t}\n\n\tprivate _initPlugins(plugins: string[]) {\n\t\tplugins.forEach((plugin) => {\n\t\t\tswitch (plugin) {\n\t\t\t\tcase VideoPlugins.STICKY:\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.plugins.set(\n\t\t\t\t\t\t\tplugin.toLocaleLowerCase(),\n\t\t\t\t\t\t\tnew StickyPlugin({\n\t\t\t\t\t\t\t\tstore: this.store\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\t\t\t\t\t\tlogger.debug('Sticky plugin loaded')();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase VideoPlugins.AUTOPLAY:\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.plugins.set(\n\t\t\t\t\t\t\tplugin.toLocaleLowerCase(),\n\t\t\t\t\t\t\tnew AutoplayPlugin({\n\t\t\t\t\t\t\t\tstore: this.store\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\t\t\t\t\t\tlogger.debug('Autoplay plugin loaded')();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase VideoPlugins.ANALYTICS:\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.plugins.set(\n\t\t\t\t\t\t\tplugin.toLocaleLowerCase(),\n\t\t\t\t\t\t\tnew AnalyticsPlugin({\n\t\t\t\t\t\t\t\tstore: this.store\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\t\t\t\t\t\tlogger.debug('Analytics plugin loaded')();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase VideoPlugins.DEBUG:\n\t\t\t\t\t{\n\t\t\t\t\t\tthis.plugins.set(\n\t\t\t\t\t\t\tplugin.toLocaleLowerCase(),\n\t\t\t\t\t\t\tnew DebugPlugin({\n\t\t\t\t\t\t\t\tstore: this.store\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\t\t\t\t\t\tlogger.debug('Debug plugin loaded')();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t});\n\t}\n\n\t// Related contents\n\t// TODO @yohanauf: move init to a separate plugin\n\t// TODO @damien: Check if that still deserve a purpose\n\tpublic initRelatedContents(player) {\n\t\tconst RelatedContents = (window as any).AufVideo.RelatedContents;\n\t\tif (!RelatedContents) return;\n\n\t\tconst afRelatedContent = new RelatedContents();\n\t\tafRelatedContent.init({\n\t\t\tid: player.id,\n\t\t\tplayer,\n\t\t\tlabels: this.labels,\n\t\t\trevolver: false\n\t\t});\n\t}\n\n\t// TODO @damien: Check if that still deserve a purpose\n\tprivate _getInstancesAdsInfo() {\n\t\tconst infos: { playerId: string; placement: string }[] = [];\n\t\tconst instances = this.store.instances;\n\n\t\tinstances.forEach((instance: StoreInstance, key: string) => {\n\t\t\tif (instance.adPlayer) {\n\t\t\t\tinfos.push({\n\t\t\t\t\tplayerId: instance.adPlayer.id,\n\t\t\t\t\tplacement: instance.adPlayer.adUnit.split('/').pop()\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic static get(options?: ManagerOptions): Manager {\n\t\tif (!Manager.instance) {\n\t\t\tManager.instance = new Manager(options);\n\t\t}\n\n\t\treturn Manager.instance;\n\t}\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.Manager = window.AufVideo.Manager || Manager;\n","import {\n\tPublishableVideoAdEvents,\n\tPublishableVideoLogEvents\n} from 'src/enums/publishable-events.enum';\nimport { Manager } from 'src/manager';\nimport { Store } from 'src/store';\nimport { AufVideoUtils } from 'src/utils/utils';\nimport { VideoConsoleLogger } from 'src/utils/video-logger';\nimport { PlayerPosition } from '../enums/player-position.enum';\nimport { PlayerInstance } from '../types/player-instance.type';\nimport PubSub from 'pubsub-js';\nimport {\n\tAdUnitCode,\n\tPegasusAmazonItem,\n\tPegasusPreBidItem,\n\tPegasusResponseBids\n} from 'src/interfaces/pegasus-response-bids.interface';\n\nconst logger = new VideoConsoleLogger();\n\nlet SETTINGS: any = {\n\tDEFAULTplayer_WIDTH: 640,\n\tDEFAULTplayer_HEIGHT: 480,\n\tHB_VIDEO_TIMEOUT: 3000,\n\tDEFAULT_AD_TAG_URL:\n\t\t'https://securepubads.g.doubleclick.net/gampad/ads' +\n\t\t'?sz=640x480' + // Size of master video ad slot, use pipe for multiple sizes\n\t\t'&impl=s' + // The request mode. Here, s for sync\n\t\t'&gdfp_req=1' + // Indicates that the user is on the DFP schema\n\t\t'&env=vp' + // Indicates that the request is from a video player\n\t\t'&output=vast' + // Output format of ad, vast => network's default setting\n\t\t'&unviewed_position_start=1', // Setting this to 1 turns on delayed impressions,\n\tCMP_AD_SERVER_KEY: 'google'\n};\n\nSETTINGS.DEBUG_AD_TAG_URL =\n\tSETTINGS.DEFAULT_AD_TAG_URL +\n\t'&iu=/124319096/external/single_ad_samples' +\n\t'&ciu_szs=300x250' +\n\t'&cust_params=deployment%3Ddevsite%26sample_ct%3Dskippablelinear';\n\nexport interface AdPlayerOptions {\n\tid: string;\n\tname: string;\n\tplayer: PlayerInstance;\n\tadUnit: string;\n\tadTargeting: any; // TODO: Type that\n\tallowMultipleTinyAds: boolean;\n\tsiteId: number;\n\tposition: PlayerPosition;\n\tadScheduleId: string;\n\tplayPreroll: boolean;\n\tneedPegasus: boolean;\n\thbVideoActive?: boolean;\n\tjwpAdvertisingParameters?: boolean;\n\tisCM?: boolean;\n\tadRule?: boolean;\n\tviewableVideo?: boolean;\n}\n\nexport interface AdData {}\n\nexport interface AdState {\n\tplaying: boolean;\n\tstarted: boolean;\n\tended: boolean;\n\tpaused: boolean;\n\tpods: number;\n\teventsLists: string[];\n}\n\ndeclare global {\n\tinterface Window {\n\t\tDidomi: any;\n\t\tunify_dataSlayer: any;\n\t\tafAdblock: any;\n\t\tpegasusConf: any;\n\t\tsas_target: any;\n\t\tpegasus: any;\n\t}\n}\n\nexport default abstract class AdPlayer {\n\tpublic adsState: AdState = {\n\t\tplaying: false,\n\t\tstarted: false,\n\t\tended: false,\n\t\tpaused: false,\n\t\tpods: 0,\n\t\teventsLists: []\n\t};\n\tprivate _hbResponses: PegasusResponseBids; // TODO: Type that (if hb still needed)\n\tprivate _adTagUrl: string;\n\tprivate _debug = false;\n\tprivate _allowMultipleTinyAds = false;\n\tprivate _adTargeting: any; // TODO: Type that\n\tprivate _adRule: boolean;\n\tprivate _isCM: boolean;\n\tprotected _jwpAdvertisingParameters: boolean;\n\tprotected _playPreroll: boolean;\n\tprotected _viewableVideo: boolean;\n\tprotected _id: string;\n\tprotected _ready = false;\n\tprotected _player: PlayerInstance;\n\tprotected _hbVideoActive: boolean;\n\tprotected _adScheduleId: string;\n\tpublic adUnit: string;\n\tpublic position: PlayerPosition;\n\tpublic needPegasus: boolean;\n\tpublic name: string;\n\tpublic siteId: number;\n\n\tconstructor(options: AdPlayerOptions) {\n\t\tthis._id = options.id;\n\n\t\tif (!options.id || !options.player || !options.adUnit) {\n\t\t\tthis.logError('Unable to init ad player (missing options)');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.name = options.name;\n\t\tthis.siteId = options.siteId;\n\t\tthis._player = options.player;\n\t\tthis.adUnit = options.adUnit;\n\t\tthis._adTargeting = options.adTargeting;\n\t\tthis._allowMultipleTinyAds = options.allowMultipleTinyAds;\n\t\tthis.position = options.position;\n\t\tthis._adScheduleId = options.adScheduleId;\n\t\tthis._hbVideoActive = options.hbVideoActive || false;\n\t\tthis._jwpAdvertisingParameters = options.jwpAdvertisingParameters || false;\n\t\tthis.needPegasus = options.needPegasus || false;\n\t\tthis._isCM = options.isCM || false;\n\t\tthis._playPreroll = options.playPreroll;\n\t\tthis._adRule = options.adRule || false;\n\t\tthis._viewableVideo = false;\n\t}\n\n\tpublic async init(store?: Store, player?: any): Promise {\n\t\tthis._player = player;\n\n\t\t// If user got an adBlocker or if website uses a CMP and user doesn't consent to ad server, do not init ad player\n\t\tconst adsDisabled =\n\t\t\tthis._userHasAdBlock() ||\n\t\t\t(window.Didomi &&\n\t\t\t\t!window.Didomi.getUserConsentStatusForVendor(\n\t\t\t\t\tSETTINGS.CMP_AD_SERVER_KEY\n\t\t\t\t));\n\n\t\tif (adsDisabled) return Promise.resolve();\n\n\t\tPubSub.subscribe(\n\t\t\tPublishableVideoAdEvents.AD_TAG_READY,\n\t\t\t(\n\t\t\t\tevent,\n\t\t\t\tparams: { adTagUrl: string; typeAd: string; position: string }\n\t\t\t) => {\n\t\t\t\tif (params.position !== this.position) return;\n\n\t\t\t\tthis._playAdInstant(params.adTagUrl);\n\t\t\t}\n\t\t);\n\n\t\tawait this._postInit(store, player);\n\t\treturn Promise.resolve();\n\t}\n\n\t// (Ima & Jwplayer) Ad tag: regenerate URL on each request because some key/values are updated on the fly for some 3rd party\n\t// RECO Damien: Déplacer vers un service plutot que dans l'adplayer\n\tprotected async getAdTagUrl(typeAd: string = 'preroll') {\n\t\tif (this._debug) {\n\t\t\treturn SETTINGS.DEBUG_AD_TAG_URL + '&correlator=' + Date.now(); // A random positive number;\n\t\t}\n\n\t\tconst isVposSet =\n\t\t\tthis._adTagUrl &&\n\t\t\tthis._adTagUrl.split('&vpos=') &&\n\t\t\tthis._adTagUrl.split('&vpos=')[1] === typeAd;\n\n\t\t// If ad tag URL is available, return it directly\n\t\tif (isVposSet) return this._adTagUrl;\n\n\t\tconst customParameters = await this.getAdTagCustomParameters();\n\t\tconst nonPersonalizedAds = this._getNpaFromCmp();\n\n\t\tfunction buildAdTagUrl(\n\t\t\tiu: string,\n\t\t\turl: string,\n\t\t\tcustomParams: string,\n\t\t\tnpa: string,\n\t\t\tvpos: string,\n\t\t\tadRule?: number\n\t\t) {\n\t\t\tlet params: any = {\n\t\t\t\tiu,\n\t\t\t\turl: encodeURIComponent(url),\n\t\t\t\tdescription_url: encodeURIComponent(url),\n\t\t\t\tcust_params: encodeURIComponent(customParams),\n\t\t\t\tnpa,\n\t\t\t\tcorrelator: Date.now(),\n\t\t\t\tvpos\n\t\t\t};\n\n\t\t\tif (adRule) {\n\t\t\t\tparams = {\n\t\t\t\t\t...params,\n\t\t\t\t\tad_rule: adRule\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn `${SETTINGS.DEFAULT_AD_TAG_URL}&${Object.keys(params)\n\t\t\t\t.map((k) => `${k}=${params[k]}`)\n\t\t\t\t.join('&')}`;\n\t\t}\n\n\t\treturn buildAdTagUrl(\n\t\t\tthis.adUnit,\n\t\t\tlocation.href,\n\t\t\tcustomParameters,\n\t\t\tnonPersonalizedAds,\n\t\t\ttypeAd,\n\t\t\tthis._allowMultipleTinyAds ? 1 : undefined\n\t\t);\n\t}\n\n\tprotected logError(message: string) {\n\t\tthis.publish(PublishableVideoLogEvents.ERROR, {\n\t\t\tmessage: message,\n\t\t\tcategory: this.name\n\t\t});\n\t}\n\n\tprotected _playAdInstant(adTagUrl: string): boolean {\n\t\tif (!adTagUrl) return false;\n\n\t\tthis._adTagUrl = adTagUrl;\n\t\tthis._postPlayAdInstant();\n\t\treturn true;\n\t}\n\n\tpublic publish(event: string, data: any = {}) {\n\t\tdata.id = this._id; // To retrieve current instance\n\t\tPubSub.publish(event, data);\n\n\t\tconst blacklistedFromConsoleLogs = ['video.ad.time_update'];\n\t\tif (blacklistedFromConsoleLogs.includes(event)) return;\n\n\t\tlogger.debug(`Publishing ${event}`, data)();\n\t}\n\n\tpublic publishApiEvent(event: string, ad?: AdData) {\n\t\tconst data = {\n\t\t\tad: this._getAdData(ad), // Add extra data about ads\n\t\t\tvideoBreak: this._getVideoBreak(ad), // Instream video ad break (preroll, postroll, ..)\n\t\t\tvideo: this._player ? this._player.videoId : undefined,\n\t\t\turl: document.URL\n\t\t};\n\n\t\tthis.publish(event, data);\n\t}\n\n\tpublic onApiLoaded() {\n\t\tif (this._ready) return;\n\n\t\tthis._initApiListeners();\n\t\tthis._initErrorsListeners();\n\n\t\tif (this._player.muted && this.mute) {\n\t\t\tthis.mute();\n\t\t}\n\n\t\tthis.publishApiEvent(PublishableVideoAdEvents.AD_READY);\n\t\tthis._ready = true;\n\t}\n\n\tpublic async getAdTagCustomParameters() {\n\t\t// Keywords targeting\n\t\tlet customParameters = await this._getAdTargetingFormated(this.position);\n\t\tconst playerWidth =\n\t\t\tthis._player && this._player.ready\n\t\t\t\t? this._player.getWidth()\n\t\t\t\t: SETTINGS.DEFAULTplayer_WIDTH;\n\t\tconst playerHeight =\n\t\t\tthis._player && this._player.ready\n\t\t\t\t? this._player.getHeight()\n\t\t\t\t: SETTINGS.DEFAULTplayer_HEIGHT;\n\n\t\tcustomParameters +=\n\t\t\t'&playerwidth=' + playerWidth + '&playerheight=' + playerHeight;\n\n\t\treturn customParameters;\n\t}\n\n\tpublic setHbResponses = (hbResponses) => (this._hbResponses = hbResponses);\n\tpublic isPlaying = () => this.adsState.playing;\n\tpublic isPaused = () => !this.adsState.playing;\n\tpublic isActive = () => this.adsState.started && !this.adsState.ended;\n\n\tprivate _logConsole = (logs: string, format?: string) =>\n\t\tManager.get().logConsole(logs, format);\n\n\tprivate _userHasAdBlock = () =>\n\t\twindow.afAdblock && window.afAdblock.status === 0;\n\n\tprotected _getNpaFromCmp() {\n\t\tif (!window.Didomi) {\n\t\t\treturn '0'; // NPA allowed by default if no CMP\n\t\t}\n\n\t\t// If website uses Didomi CMP, check for user content to non-personalized ads\n\t\tconst userConsentToPersonalizedAds =\n\t\t\twindow.Didomi.getUserConsentStatusForPurpose('cookies') &&\n\t\t\twindow.Didomi.getUserConsentStatusForPurpose('select_basic_ads') &&\n\t\t\twindow.Didomi.getUserConsentStatusForPurpose('create_ads_profile') &&\n\t\t\twindow.Didomi.getUserConsentStatusForPurpose('select_personalized_ads') &&\n\t\t\twindow.Didomi.getUserConsentStatusForPurpose('measure_ad_performance') &&\n\t\t\twindow.Didomi.getUserConsentStatusForPurpose('market_research') &&\n\t\t\twindow.Didomi.getUserConsentStatusForPurpose('improve_products');\n\n\t\treturn userConsentToPersonalizedAds ? '0' : '1';\n\t}\n\n\tprivate _getPegasusBids(hbResponse: PegasusResponseBids): string {\n\t\tconst amazon = hbResponse.amazon;\n\t\tconst prebid = hbResponse.prebid;\n\n\t\tfunction getBids(\n\t\t\titem:\n\t\t\t\t| { [adUnitCode in AdUnitCode]: PegasusPreBidItem | PegasusAmazonItem }\n\t\t\t\t| undefined\n\t\t) {\n\t\t\titem = item ? item[Object.keys(item)[0]] : undefined;\n\t\t\tconst prebidItem = item as unknown as PegasusPreBidItem;\n\t\t\tconst amazonItem = item as unknown as PegasusAmazonItem;\n\t\t\tconst isPrebid =\n\t\t\t\tprebidItem &&\n\t\t\t\tprebidItem.bids &&\n\t\t\t\tArray.isArray(prebidItem.bids) &&\n\t\t\t\tprebidItem.bids.length;\n\t\t\tconst isAmazon =\n\t\t\t\tamazonItem && amazonItem.bids && amazonItem.bids?.targeting;\n\n\t\t\treturn isPrebid\n\t\t\t\t? prebidItem.targeting\n\t\t\t\t: isAmazon\n\t\t\t\t? amazonItem.targeting\n\t\t\t\t: {};\n\t\t}\n\n\t\tconst targetings = {\n\t\t\t...getBids(amazon),\n\t\t\t...getBids(prebid)\n\t\t};\n\n\t\treturn Object.keys(targetings)\n\t\t\t.map((k) => `${k}=${targetings[k]}`)\n\t\t\t.join(';');\n\t}\n\n\tprivate async _getAdTargetingFormated(position: PlayerPosition) {\n\t\tlogger.debug('_getAdTargetingFormated()')();\n\n\t\tlet adTargeting = `video_pos=${\n\t\t\tposition.toLowerCase().startsWith('mtf') ? 'mtf' : position.toLowerCase()\n\t\t};`;\n\n\t\t// Add GoFeminin targeting if needed\n\t\tadTargeting +=\n\t\t\tthis.siteId === 4\n\t\t\t\t? getGoFemininTargeting(window.unify_dataSlayer, this._player.isMobile)\n\t\t\t\t: '';\n\n\t\t// Add pegasus hb responses\n\t\tconst hasHbResponses = this._hasHbResponses(this._hbResponses);\n\t\tif (hasHbResponses) {\n\t\t\tconst pegasusBids = this._getPegasusBids(this._hbResponses);\n\n\t\t\tif (pegasusBids)\n\t\t\t\tthis.publishApiEvent(PublishableVideoAdEvents.AD_BID_FOUND);\n\n\t\t\tadTargeting += pegasusBids;\n\t\t}\n\n\t\t// Add debug targeting\n\t\tconst debugPrerollAdTargeting = localStorage.getItem('video_force_preroll')\n\t\t\t? 'adtest=preroll'\n\t\t\t: '';\n\t\tadTargeting += `${window.sas_target};${this._adTargeting};${debugPrerollAdTargeting}`;\n\n\t\t// Add Pegasus Conf Keywords\n\t\tconst pegasusConfKeywords = window.pegasusConf?.params?.keywords;\n\t\tconst pegasusDotConfKeywords = window.pegasus?.conf?.params?.keywords;\n\t\tadTargeting += pegasusConfKeywords ? `;${pegasusConfKeywords}` : '';\n\t\tadTargeting += pegasusDotConfKeywords ? `;${pegasusDotConfKeywords}` : '';\n\n\t\t// Add Global targeting from Pegasus\n\t\tif (this.needPegasus) {\n\t\t\tlogger.debug('_getAdTargetingFormated() : Need Pegasus')();\n\t\t\tconst pegasusReady = async (): Promise => {\n\t\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t\tlet pegasusReady = false;\n\n\t\t\t\t\tconst pegasusReadyInterval = window.setInterval(() => {\n\t\t\t\t\t\tconst pegasus = window.pegasus;\n\t\t\t\t\t\tconst googletag = window.googletag;\n\t\t\t\t\t\tif (pegasus.getGlobalTargeting && googletag.pubads) {\n\t\t\t\t\t\t\tpegasusReady = true;\n\t\t\t\t\t\t\twindow.clearInterval(pegasusReadyInterval);\n\t\t\t\t\t\t\treturn resolve(pegasusReady);\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 150);\n\n\t\t\t\t\twindow.setTimeout(() => {\n\t\t\t\t\t\tif (!pegasusReady) {\n\t\t\t\t\t\t\tconst err = 'Pegasus timed out';\n\t\t\t\t\t\t\tlogger.error(err + ', clearing interval')();\n\t\t\t\t\t\t\twindow.clearInterval(pegasusReadyInterval);\n\t\t\t\t\t\t\treject(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t}, 10000);\n\t\t\t\t});\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\tawait pegasusReady();\n\t\t\t} catch (error) {\n\t\t\t\treturn Promise.reject(error);\n\t\t\t}\n\n\t\t\tconst globalTargeting = window.pegasus.getGlobalTargeting() || {};\n\t\t\tconst pegasusTargetting = Object.keys(globalTargeting)\n\t\t\t\t.map(function (k) {\n\t\t\t\t\treturn k + '=' + window.pegasus.getGlobalTargeting()[k].join(',');\n\t\t\t\t})\n\t\t\t\t.join(';');\n\n\t\t\tadTargeting += `;${pegasusTargetting}`;\n\t\t}\n\n\t\tfunction getGoFemininTargeting(\n\t\t\tdatalayer: any[],\n\t\t\tisMobile?: boolean\n\t\t): string {\n\t\t\tdatalayer = datalayer && Array.isArray(datalayer) ? datalayer : [];\n\t\t\tconst pageItem = datalayer.find((elem) => elem.page);\n\t\t\tconst lockVerz = pageItem\n\t\t\t\t? `lokverz1=${pageItem.page.section};lokverz2=${pageItem.page.subSection};`\n\t\t\t\t: '';\n\n\t\t\treturn `pos=preroll;loktitel=gofeminin;${\n\t\t\t\tisMobile ? 'environment=mob;' : 'environment=sta;'\n\t\t\t}${lockVerz}`;\n\t\t}\n\n\t\treturn Promise.resolve(AufVideoUtils.getDFPFormattedKeywords(adTargeting));\n\t}\n\n\tprotected _getAdRule = () => (this._adRule ? 1 : 0);\n\n\tprotected _setAdsState(state) {\n\t\tswitch (state) {\n\t\t\tcase PublishableVideoAdEvents.AD_START:\n\t\t\t\tthis.adsState.started = true;\n\t\t\t\tthis.adsState.ended = false;\n\t\t\t\tthis.adsState.pods++;\n\t\t\t\tbreak;\n\n\t\t\tcase PublishableVideoAdEvents.AD_END:\n\t\t\t\tthis.adsState.started = false;\n\t\t\t\tthis.adsState.playing = false;\n\t\t\t\tthis.adsState.ended = true;\n\t\t\t\tbreak;\n\n\t\t\tcase PublishableVideoAdEvents.AD_PAUSE:\n\t\t\t\tthis.adsState.playing = false;\n\t\t\t\tthis.adsState.paused = true;\n\t\t\t\tbreak;\n\n\t\t\tcase PublishableVideoAdEvents.AD_PLAY:\n\t\t\tcase PublishableVideoAdEvents.AD_RESUME:\n\t\t\t\tthis.adsState.paused = false;\n\t\t\t\tthis.adsState.started = true;\n\t\t\t\tthis.adsState.playing = true;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tthis._pushToEventsList(state);\n\t}\n\n\tprivate _pushToEventsList(eventName) {\n\t\tthis.adsState.eventsLists.push(this.name + ': ' + eventName);\n\t}\n\n\tprivate _hasHbResponses(hbResponses: PegasusResponseBids) {\n\t\tconst prebid = hbResponses && hbResponses.prebid;\n\t\tconst amazon = hbResponses && hbResponses.amazon;\n\n\t\tconst hasPrebidProps = prebid\n\t\t\t? Object.getOwnPropertyNames(hbResponses.prebid).length\n\t\t\t: undefined;\n\t\tconst hasAmazonProps = amazon\n\t\t\t? Object.getOwnPropertyNames(hbResponses.amazon).length\n\t\t\t: undefined;\n\n\t\treturn hasPrebidProps || hasAmazonProps;\n\t}\n\n\tprotected abstract _getAdData(ad?: any): any;\n\tprotected abstract _getVideoBreak(ad: any): any;\n\tprotected abstract _postInit(store?: Store, player?: any): Promise;\n\tprotected abstract _postPlayAdInstant(): any;\n\tprotected abstract _initApiListeners(): void;\n\tprotected abstract _initErrorsListeners(): void;\n\tpublic abstract mute(): void;\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.AdPlayer = AdPlayer;\n","import { AufVideoUtils } from 'src/utils/utils';\nimport { VideoConsoleLogger } from 'src/utils/video-logger';\nimport { PublishableVideoAdEvents } from '../enums/publishable-events.enum';\nimport { ImaApi } from '../interfaces/ima-api.inteface';\nimport { ListenerAction } from '../interfaces/listener-action';\nimport { Store } from '../store';\nimport AdPlayer, { AdPlayerOptions } from './_adapter';\n\nconst logger = new VideoConsoleLogger();\n\nconst API_DEFAULT_SETUP = {\n\tadsRenderingSettings: {\n\t\tenablePreloading: true,\n\t\tloadVideoTimeout: 10000\n\t},\n\tdisableCustomPlaybackForIOS10Plus: true, // IMPORTANT: IOS inline autoplay issues without this\n\tdisableFlashAds: true,\n\tprerollTimeout: 5000,\n\tshowCountdown: true, // Whether or not to show the ad countdown timer\n\tvastLoadTimeout: 5000, // As we do prefetch we can try a higher value here,\n\tlocale: undefined,\n\tnumRedirects: undefined\n};\n\nconst IMA_UNFILLED_ERROR_CODES = {\n\t1009: 'Empty VAST response.'\n};\n\nexport interface ImaAdPlayerOptions extends AdPlayerOptions {\n\tadLabel: string;\n\tlanguage: string;\n}\n\nexport class ImaAdPlayer extends AdPlayer {\n\tpublic ready = false;\n\tpublic api: ImaApi;\n\tpublic imaOptions: any;\n\tprivate _adLabel: string;\n\tprivate _language: string;\n\tprivate _store: Store;\n\tprivate _alreadyRequested = false;\n\tprivate _loadVideoTimeout: number;\n\tprivate _prerollTimeout: number;\n\tprivate _showCountdown: boolean;\n\tprivate _vastLoadTimeout: number;\n\tprivate _numRedirects: number;\n\n\tprivate _apiListenersActions: ListenerAction[] = [\n\t\t{\n\t\t\tmessage: (window as any).google.ima.AdEvent.Type.STARTED,\n\t\t\tactionFn: (ad) => {\n\t\t\t\t// HACK: reforce mute when ad starts to prevent some bugs with 2nd preroll\n\t\t\t\tif (this._player.muted) {\n\t\t\t\t\tthis.mute();\n\t\t\t\t}\n\n\t\t\t\tthis._emitEventHandler(PublishableVideoAdEvents.AD_START);\n\t\t\t\tthis.publishApiEvent(PublishableVideoAdEvents.AD_PLAY, ad);\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tmessage: (window as any).google.ima.AdEvent.Type.PAUSED,\n\t\t\tactionFn: (ad) =>\n\t\t\t\tthis._emitEventHandler(PublishableVideoAdEvents.AD_PAUSE, ad)\n\t\t},\n\t\t{\n\t\t\tmessage: (window as any).google.ima.AdEvent.Type.RESUMED,\n\t\t\tactionFn: (ad) =>\n\t\t\t\tthis._emitEventHandler(PublishableVideoAdEvents.AD_RESUME, ad)\n\t\t},\n\t\t{\n\t\t\tmessage: (window as any).google.ima.AdEvent.Type.COMPLETE,\n\t\t\tactionFn: (ad) =>\n\t\t\t\tthis._emitEventHandler(PublishableVideoAdEvents.AD_RESUME, ad)\n\t\t},\n\t\t{\n\t\t\tmessage: (window as any).google.ima.AdEvent.Type.CLICK,\n\t\t\tactionFn: (ad) =>\n\t\t\t\tthis._emitEventHandler(PublishableVideoAdEvents.AD_CLICK, ad)\n\t\t},\n\t\t{\n\t\t\tmessage: (window as any).google.ima.AdEvent.Type.IMPRESSION,\n\t\t\tactionFn: (ad) =>\n\t\t\t\tthis._emitEventHandler(PublishableVideoAdEvents.AD_IMPRESSION, ad)\n\t\t},\n\t\t{\n\t\t\tmessage: (window as any).google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED,\n\t\t\tactionFn: (ad) => {\n\t\t\t\tthis._setAdsState(PublishableVideoAdEvents.AD_END);\n\t\t\t\tthis.publishApiEvent(PublishableVideoAdEvents.AD_CONTENT_RESUME);\n\t\t\t}\n\t\t}\n\t];\n\n\tconstructor(options: ImaAdPlayerOptions) {\n\t\tsuper({ ...options, name: 'ima' });\n\n\t\tthis.name = 'ima';\n\t\tthis._adLabel = options.adLabel;\n\t\tthis._language = options.language;\n\n\t\tthis.imaOptions = {\n\t\t\t...API_DEFAULT_SETUP,\n\t\t\tid: this._id,\n\t\t\tadLabel: this._adLabel,\n\t\t\tadWillPlayMuted: this._player.muted,\n\t\t\tadsManagerLoadedCallback: this.onApiLoaded.bind(this),\n\t\t\tadsRenderingSettings: this._loadVideoTimeout\n\t\t\t\t? {\n\t\t\t\t\t\tloadVideoTimeout: this._loadVideoTimeout\n\t\t\t\t }\n\t\t\t\t: API_DEFAULT_SETUP.adsRenderingSettings,\n\t\t\tprerollTimeout: this._prerollTimeout || API_DEFAULT_SETUP.prerollTimeout,\n\t\t\tshowCountdown: this._showCountdown || API_DEFAULT_SETUP.showCountdown,\n\t\t\tvastLoadTimeout:\n\t\t\t\tthis._vastLoadTimeout || API_DEFAULT_SETUP.vastLoadTimeout,\n\t\t\tlocale:\n\t\t\t\t(this._language && this._language.toLowerCase()) ||\n\t\t\t\tAPI_DEFAULT_SETUP.locale,\n\t\t\tnumRedirects: this._numRedirects || API_DEFAULT_SETUP.numRedirects\n\t\t};\n\t}\n\n\tpublic mute(): void {\n\t\tconst adManager = this.api.getAdsManager;\n\t\tif (!(adManager && adManager.setVolume)) return;\n\n\t\tadManager.setVolume(0);\n\t}\n\n\tpublic play = () => (this.ready ? this.api.resumeAd() : undefined);\n\tpublic pause = () => (this.ready ? this.api.pauseAd() : undefined);\n\n\tprotected async _postInit(store: Store): Promise {\n\t\tconst getGoogle = async (): Promise => {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tconst googleReadyInterval = window.setInterval(() => {\n\t\t\t\t\tconst google = (window as any).google;\n\t\t\t\t\tif (google) {\n\t\t\t\t\t\t(window as any).clearInterval(googleReadyInterval);\n\t\t\t\t\t\treturn resolve(google);\n\t\t\t\t\t}\n\t\t\t\t}, 50);\n\n\t\t\t\t//window.setTimeout(() => window.clearInterval(googleReadyInterval), 2000);\n\t\t\t});\n\t\t};\n\n\t\tconst google = await getGoogle();\n\n\t\tif (!google || !(this._player.api as any).ima) {\n\t\t\tconst err = 'Unable to initialize ad player';\n\t\t\tthis.logError(err);\n\t\t\tthrow err;\n\t\t}\n\n\t\tthis._store = store;\n\t\tawait this._initApi();\n\n\t\tif (!this._hbVideoActive) {\n\t\t\tthis._initAdRequest();\n\t\t}\n\n\t\treturn Promise.resolve();\n\t}\n\n\tprotected _postPlayAdInstant = () => this._initAdRequest();\n\n\tprotected _initApiListeners() {\n\t\tthis._apiListenersActions.forEach((listener) =>\n\t\t\tthis.api.addEventListener(listener.message, listener.actionFn)\n\t\t);\n\n\t\t// Listen click / touch events on playback buttons to catch user interaction with player\n\t\tAufVideoUtils.addClickListener(\n\t\t\tthis._id,\n\t\t\t['ima-play-pause-div', this._id + '_ima-ad-container'],\n\t\t\t() => this.publish('video.player.user.togglePlayPause'),\n\t\t\t{ stopPropagation: true }\n\t\t);\n\t}\n\n\tprotected _initErrorsListeners() {\n\t\t(this._player.api as any).on('adserror', (error) => {\n\t\t\tvar errorCode = error.data.AdError.getErrorCode();\n\t\t\tif (IMA_UNFILLED_ERROR_CODES[errorCode]) {\n\t\t\t\tthis.adsState.eventsLists.push('IMA: AD_UNFILLED');\n\t\t\t\tthis.publish('video.ad.unfilled');\n\t\t\t} else {\n\t\t\t\tthis.adsState.eventsLists.push('IMA: AD_ERROR');\n\t\t\t\tthis.logError(error.data.AdError.getMessage() + ' [' + errorCode + ']');\n\t\t\t}\n\t\t});\n\t}\n\n\t// Documentation: https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdPodInfo.getPodIndex\n\tprotected _getAdData(data: any) {\n\t\ttry {\n\t\t\tconst ad = data.getAd();\n\n\t\t\t// Sometimes default infos are not filled, but wrappers are filled instead\n\t\t\t// TODO @money: improve to log more ad data\n\t\t\treturn {\n\t\t\t\tadId: ad.getAdId() || ad.getWrapperAdIds().toString(),\n\t\t\t\tadSystem: ad.getAdSystem() || ad.getWrapperAdSystems().toString(),\n\t\t\t\tcreativeId: ad.getCreativeId() || ad.getWrapperCreativeIds().toString()\n\t\t\t};\n\t\t} catch (e) {\n\t\t\tthis.logError('Unable to retrieve some ad data: ' + e.message);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tpublic async _initApi(): Promise {\n\t\tconst that = this;\n\t\tconst ima = (this._player.api as any).ima;\n\n\t\tif (!this.api && ima && typeof ima === 'function') {\n\t\t\tima(this.imaOptions);\n\t\t\tthis.api = ima;\n\t\t}\n\t\tlogger.info('ima::initApi()', this.api)();\n\n\t\treturn Promise.resolve();\n\t}\n\n\tpublic setApi(api: ImaApi) {\n\t\tif (!api) return;\n\n\t\tthis.api = api;\n\t}\n\n\tprivate _initAdRequest() {\n\t\t// Autostart on: prefetch ads as soon as possible\n\t\tconst instance = this._store.getInstance(this._id);\n\t\tif (instance && instance.autoplay.startOnSight) {\n\t\t\tthis._requestAds();\n\t\t\treturn;\n\t\t}\n\n\t\t// Autostart off: only load ads when the video player is clicked\n\t\tconst handler = () => {\n\t\t\t// IMPORTANT: must be done via a user action if autoplay is not allowed\n\t\t\tthis.api.initializeAdDisplayContainer(); // Create an ad display container\n\t\t\tthis._requestAds();\n\t\t};\n\n\t\t(this._player.api as any).on('click', handler);\n\t}\n\n\t// TODO @money: use static constants from IMA SDK\n\tprotected _getVideoBreak(ad: any) {\n\t\tlet res = '';\n\n\t\tif (!ad || !ad.getAd) {\n\t\t\tlogger.debug('ad or ad.getAd not found')();\n\t\t\treturn res;\n\t\t}\n\n\t\tswitch (ad.getAd().getAdPodInfo().getPodIndex()) {\n\t\t\tcase 0:\n\t\t\t\tres = 'preroll';\n\t\t\tcase -1:\n\t\t\t\tres = 'postroll';\n\t\t\tdefault:\n\t\t\t\tres = '';\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tprivate async _requestAds(): Promise {\n\t\tif (this._alreadyRequested) return;\n\n\t\tconst adTagUrl = await this.getAdTagUrl();\n\t\tthis.api.setContentWithAdTag(null, adTagUrl, false);\n\t\tthis.api.requestAds();\n\n\t\tthis._alreadyRequested = true;\n\n\t\treturn Promise.resolve();\n\t}\n\n\tprivate _emitEventHandler(evt: PublishableVideoAdEvents, adData?: any): void {\n\t\tthis._setAdsState(evt);\n\t\tthis.publishApiEvent(evt, adData);\n\t}\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.IMA = ImaAdPlayer;\n","// NOTE: this list must be up-to-date with browsers listed in\n// test/acceptance/useragentstrings.yml\nexport const BROWSER_ALIASES_MAP = {\n 'Amazon Silk': 'amazon_silk',\n 'Android Browser': 'android',\n Bada: 'bada',\n BlackBerry: 'blackberry',\n Chrome: 'chrome',\n Chromium: 'chromium',\n Electron: 'electron',\n Epiphany: 'epiphany',\n Firefox: 'firefox',\n Focus: 'focus',\n Generic: 'generic',\n 'Google Search': 'google_search',\n Googlebot: 'googlebot',\n 'Internet Explorer': 'ie',\n 'K-Meleon': 'k_meleon',\n Maxthon: 'maxthon',\n 'Microsoft Edge': 'edge',\n 'MZ Browser': 'mz',\n 'NAVER Whale Browser': 'naver',\n Opera: 'opera',\n 'Opera Coast': 'opera_coast',\n PhantomJS: 'phantomjs',\n Puffin: 'puffin',\n QupZilla: 'qupzilla',\n QQ: 'qq',\n QQLite: 'qqlite',\n Safari: 'safari',\n Sailfish: 'sailfish',\n 'Samsung Internet for Android': 'samsung_internet',\n SeaMonkey: 'seamonkey',\n Sleipnir: 'sleipnir',\n Swing: 'swing',\n Tizen: 'tizen',\n 'UC Browser': 'uc',\n Vivaldi: 'vivaldi',\n 'WebOS Browser': 'webos',\n WeChat: 'wechat',\n 'Yandex Browser': 'yandex',\n Roku: 'roku',\n};\n\nexport const BROWSER_MAP = {\n amazon_silk: 'Amazon Silk',\n android: 'Android Browser',\n bada: 'Bada',\n blackberry: 'BlackBerry',\n chrome: 'Chrome',\n chromium: 'Chromium',\n electron: 'Electron',\n epiphany: 'Epiphany',\n firefox: 'Firefox',\n focus: 'Focus',\n generic: 'Generic',\n googlebot: 'Googlebot',\n google_search: 'Google Search',\n ie: 'Internet Explorer',\n k_meleon: 'K-Meleon',\n maxthon: 'Maxthon',\n edge: 'Microsoft Edge',\n mz: 'MZ Browser',\n naver: 'NAVER Whale Browser',\n opera: 'Opera',\n opera_coast: 'Opera Coast',\n phantomjs: 'PhantomJS',\n puffin: 'Puffin',\n qupzilla: 'QupZilla',\n qq: 'QQ Browser',\n qqlite: 'QQ Browser Lite',\n safari: 'Safari',\n sailfish: 'Sailfish',\n samsung_internet: 'Samsung Internet for Android',\n seamonkey: 'SeaMonkey',\n sleipnir: 'Sleipnir',\n swing: 'Swing',\n tizen: 'Tizen',\n uc: 'UC Browser',\n vivaldi: 'Vivaldi',\n webos: 'WebOS Browser',\n wechat: 'WeChat',\n yandex: 'Yandex Browser',\n};\n\nexport const PLATFORMS_MAP = {\n tablet: 'tablet',\n mobile: 'mobile',\n desktop: 'desktop',\n tv: 'tv',\n};\n\nexport const OS_MAP = {\n WindowsPhone: 'Windows Phone',\n Windows: 'Windows',\n MacOS: 'macOS',\n iOS: 'iOS',\n Android: 'Android',\n WebOS: 'WebOS',\n BlackBerry: 'BlackBerry',\n Bada: 'Bada',\n Tizen: 'Tizen',\n Linux: 'Linux',\n ChromeOS: 'Chrome OS',\n PlayStation4: 'PlayStation 4',\n Roku: 'Roku',\n};\n\nexport const ENGINE_MAP = {\n EdgeHTML: 'EdgeHTML',\n Blink: 'Blink',\n Trident: 'Trident',\n Presto: 'Presto',\n Gecko: 'Gecko',\n WebKit: 'WebKit',\n};\n","import { BROWSER_MAP, BROWSER_ALIASES_MAP } from './constants.js';\n\nexport default class Utils {\n /**\n * Get first matched item for a string\n * @param {RegExp} regexp\n * @param {String} ua\n * @return {Array|{index: number, input: string}|*|boolean|string}\n */\n static getFirstMatch(regexp, ua) {\n const match = ua.match(regexp);\n return (match && match.length > 0 && match[1]) || '';\n }\n\n /**\n * Get second matched item for a string\n * @param regexp\n * @param {String} ua\n * @return {Array|{index: number, input: string}|*|boolean|string}\n */\n static getSecondMatch(regexp, ua) {\n const match = ua.match(regexp);\n return (match && match.length > 1 && match[2]) || '';\n }\n\n /**\n * Match a regexp and return a constant or undefined\n * @param {RegExp} regexp\n * @param {String} ua\n * @param {*} _const Any const that will be returned if regexp matches the string\n * @return {*}\n */\n static matchAndReturnConst(regexp, ua, _const) {\n if (regexp.test(ua)) {\n return _const;\n }\n return void (0);\n }\n\n static getWindowsVersionName(version) {\n switch (version) {\n case 'NT': return 'NT';\n case 'XP': return 'XP';\n case 'NT 5.0': return '2000';\n case 'NT 5.1': return 'XP';\n case 'NT 5.2': return '2003';\n case 'NT 6.0': return 'Vista';\n case 'NT 6.1': return '7';\n case 'NT 6.2': return '8';\n case 'NT 6.3': return '8.1';\n case 'NT 10.0': return '10';\n default: return undefined;\n }\n }\n\n /**\n * Get macOS version name\n * 10.5 - Leopard\n * 10.6 - Snow Leopard\n * 10.7 - Lion\n * 10.8 - Mountain Lion\n * 10.9 - Mavericks\n * 10.10 - Yosemite\n * 10.11 - El Capitan\n * 10.12 - Sierra\n * 10.13 - High Sierra\n * 10.14 - Mojave\n * 10.15 - Catalina\n *\n * @example\n * getMacOSVersionName(\"10.14\") // 'Mojave'\n *\n * @param {string} version\n * @return {string} versionName\n */\n static getMacOSVersionName(version) {\n const v = version.split('.').splice(0, 2).map(s => parseInt(s, 10) || 0);\n v.push(0);\n if (v[0] !== 10) return undefined;\n switch (v[1]) {\n case 5: return 'Leopard';\n case 6: return 'Snow Leopard';\n case 7: return 'Lion';\n case 8: return 'Mountain Lion';\n case 9: return 'Mavericks';\n case 10: return 'Yosemite';\n case 11: return 'El Capitan';\n case 12: return 'Sierra';\n case 13: return 'High Sierra';\n case 14: return 'Mojave';\n case 15: return 'Catalina';\n default: return undefined;\n }\n }\n\n /**\n * Get Android version name\n * 1.5 - Cupcake\n * 1.6 - Donut\n * 2.0 - Eclair\n * 2.1 - Eclair\n * 2.2 - Froyo\n * 2.x - Gingerbread\n * 3.x - Honeycomb\n * 4.0 - Ice Cream Sandwich\n * 4.1 - Jelly Bean\n * 4.4 - KitKat\n * 5.x - Lollipop\n * 6.x - Marshmallow\n * 7.x - Nougat\n * 8.x - Oreo\n * 9.x - Pie\n *\n * @example\n * getAndroidVersionName(\"7.0\") // 'Nougat'\n *\n * @param {string} version\n * @return {string} versionName\n */\n static getAndroidVersionName(version) {\n const v = version.split('.').splice(0, 2).map(s => parseInt(s, 10) || 0);\n v.push(0);\n if (v[0] === 1 && v[1] < 5) return undefined;\n if (v[0] === 1 && v[1] < 6) return 'Cupcake';\n if (v[0] === 1 && v[1] >= 6) return 'Donut';\n if (v[0] === 2 && v[1] < 2) return 'Eclair';\n if (v[0] === 2 && v[1] === 2) return 'Froyo';\n if (v[0] === 2 && v[1] > 2) return 'Gingerbread';\n if (v[0] === 3) return 'Honeycomb';\n if (v[0] === 4 && v[1] < 1) return 'Ice Cream Sandwich';\n if (v[0] === 4 && v[1] < 4) return 'Jelly Bean';\n if (v[0] === 4 && v[1] >= 4) return 'KitKat';\n if (v[0] === 5) return 'Lollipop';\n if (v[0] === 6) return 'Marshmallow';\n if (v[0] === 7) return 'Nougat';\n if (v[0] === 8) return 'Oreo';\n if (v[0] === 9) return 'Pie';\n return undefined;\n }\n\n /**\n * Get version precisions count\n *\n * @example\n * getVersionPrecision(\"1.10.3\") // 3\n *\n * @param {string} version\n * @return {number}\n */\n static getVersionPrecision(version) {\n return version.split('.').length;\n }\n\n /**\n * Calculate browser version weight\n *\n * @example\n * compareVersions('1.10.2.1', '1.8.2.1.90') // 1\n * compareVersions('1.010.2.1', '1.09.2.1.90'); // 1\n * compareVersions('1.10.2.1', '1.10.2.1'); // 0\n * compareVersions('1.10.2.1', '1.0800.2'); // -1\n * compareVersions('1.10.2.1', '1.10', true); // 0\n *\n * @param {String} versionA versions versions to compare\n * @param {String} versionB versions versions to compare\n * @param {boolean} [isLoose] enable loose comparison\n * @return {Number} comparison result: -1 when versionA is lower,\n * 1 when versionA is bigger, 0 when both equal\n */\n /* eslint consistent-return: 1 */\n static compareVersions(versionA, versionB, isLoose = false) {\n // 1) get common precision for both versions, for example for \"10.0\" and \"9\" it should be 2\n const versionAPrecision = Utils.getVersionPrecision(versionA);\n const versionBPrecision = Utils.getVersionPrecision(versionB);\n\n let precision = Math.max(versionAPrecision, versionBPrecision);\n let lastPrecision = 0;\n\n const chunks = Utils.map([versionA, versionB], (version) => {\n const delta = precision - Utils.getVersionPrecision(version);\n\n // 2) \"9\" -> \"9.0\" (for precision = 2)\n const _version = version + new Array(delta + 1).join('.0');\n\n // 3) \"9.0\" -> [\"000000000\"\", \"000000009\"]\n return Utils.map(_version.split('.'), chunk => new Array(20 - chunk.length).join('0') + chunk).reverse();\n });\n\n // adjust precision for loose comparison\n if (isLoose) {\n lastPrecision = precision - Math.min(versionAPrecision, versionBPrecision);\n }\n\n // iterate in reverse order by reversed chunks array\n precision -= 1;\n while (precision >= lastPrecision) {\n // 4) compare: \"000000009\" > \"000000010\" = false (but \"9\" > \"10\" = true)\n if (chunks[0][precision] > chunks[1][precision]) {\n return 1;\n }\n\n if (chunks[0][precision] === chunks[1][precision]) {\n if (precision === lastPrecision) {\n // all version chunks are same\n return 0;\n }\n\n precision -= 1;\n } else if (chunks[0][precision] < chunks[1][precision]) {\n return -1;\n }\n }\n\n return undefined;\n }\n\n /**\n * Array::map polyfill\n *\n * @param {Array} arr\n * @param {Function} iterator\n * @return {Array}\n */\n static map(arr, iterator) {\n const result = [];\n let i;\n if (Array.prototype.map) {\n return Array.prototype.map.call(arr, iterator);\n }\n for (i = 0; i < arr.length; i += 1) {\n result.push(iterator(arr[i]));\n }\n return result;\n }\n\n /**\n * Array::find polyfill\n *\n * @param {Array} arr\n * @param {Function} predicate\n * @return {Array}\n */\n static find(arr, predicate) {\n let i;\n let l;\n if (Array.prototype.find) {\n return Array.prototype.find.call(arr, predicate);\n }\n for (i = 0, l = arr.length; i < l; i += 1) {\n const value = arr[i];\n if (predicate(value, i)) {\n return value;\n }\n }\n return undefined;\n }\n\n /**\n * Object::assign polyfill\n *\n * @param {Object} obj\n * @param {Object} ...objs\n * @return {Object}\n */\n static assign(obj, ...assigners) {\n const result = obj;\n let i;\n let l;\n if (Object.assign) {\n return Object.assign(obj, ...assigners);\n }\n for (i = 0, l = assigners.length; i < l; i += 1) {\n const assigner = assigners[i];\n if (typeof assigner === 'object' && assigner !== null) {\n const keys = Object.keys(assigner);\n keys.forEach((key) => {\n result[key] = assigner[key];\n });\n }\n }\n return obj;\n }\n\n /**\n * Get short version/alias for a browser name\n *\n * @example\n * getBrowserAlias('Microsoft Edge') // edge\n *\n * @param {string} browserName\n * @return {string}\n */\n static getBrowserAlias(browserName) {\n return BROWSER_ALIASES_MAP[browserName];\n }\n\n /**\n * Get short version/alias for a browser name\n *\n * @example\n * getBrowserAlias('edge') // Microsoft Edge\n *\n * @param {string} browserAlias\n * @return {string}\n */\n static getBrowserTypeByAlias(browserAlias) {\n return BROWSER_MAP[browserAlias] || '';\n }\n}\n","/**\n * Browsers' descriptors\n *\n * The idea of descriptors is simple. You should know about them two simple things:\n * 1. Every descriptor has a method or property called `test` and a `describe` method.\n * 2. Order of descriptors is important.\n *\n * More details:\n * 1. Method or property `test` serves as a way to detect whether the UA string\n * matches some certain browser or not. The `describe` method helps to make a result\n * object with params that show some browser-specific things: name, version, etc.\n * 2. Order of descriptors is important because a Parser goes through them one by one\n * in course. For example, if you insert Chrome's descriptor as the first one,\n * more then a half of browsers will be described as Chrome, because they will pass\n * the Chrome descriptor's test.\n *\n * Descriptor's `test` could be a property with an array of RegExps, where every RegExp\n * will be applied to a UA string to test it whether it matches or not.\n * If a descriptor has two or more regexps in the `test` array it tests them one by one\n * with a logical sum operation. Parser stops if it has found any RegExp that matches the UA.\n *\n * Or `test` could be a method. In that case it gets a Parser instance and should\n * return true/false to get the Parser know if this browser descriptor matches the UA or not.\n */\n\nimport Utils from './utils.js';\n\nconst commonVersionIdentifier = /version\\/(\\d+(\\.?_?\\d+)+)/i;\n\nconst browsersList = [\n /* Googlebot */\n {\n test: [/googlebot/i],\n describe(ua) {\n const browser = {\n name: 'Googlebot',\n };\n const version = Utils.getFirstMatch(/googlebot\\/(\\d+(\\.\\d+))/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n\n /* Opera < 13.0 */\n {\n test: [/opera/i],\n describe(ua) {\n const browser = {\n name: 'Opera',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:opera)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n\n /* Opera > 13.0 */\n {\n test: [/opr\\/|opios/i],\n describe(ua) {\n const browser = {\n name: 'Opera',\n };\n const version = Utils.getFirstMatch(/(?:opr|opios)[\\s/](\\S+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/SamsungBrowser/i],\n describe(ua) {\n const browser = {\n name: 'Samsung Internet for Android',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:SamsungBrowser)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/Whale/i],\n describe(ua) {\n const browser = {\n name: 'NAVER Whale Browser',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:whale)[\\s/](\\d+(?:\\.\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/MZBrowser/i],\n describe(ua) {\n const browser = {\n name: 'MZ Browser',\n };\n const version = Utils.getFirstMatch(/(?:MZBrowser)[\\s/](\\d+(?:\\.\\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/focus/i],\n describe(ua) {\n const browser = {\n name: 'Focus',\n };\n const version = Utils.getFirstMatch(/(?:focus)[\\s/](\\d+(?:\\.\\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/swing/i],\n describe(ua) {\n const browser = {\n name: 'Swing',\n };\n const version = Utils.getFirstMatch(/(?:swing)[\\s/](\\d+(?:\\.\\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/coast/i],\n describe(ua) {\n const browser = {\n name: 'Opera Coast',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:coast)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/opt\\/\\d+(?:.?_?\\d+)+/i],\n describe(ua) {\n const browser = {\n name: 'Opera Touch',\n };\n const version = Utils.getFirstMatch(/(?:opt)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/yabrowser/i],\n describe(ua) {\n const browser = {\n name: 'Yandex Browser',\n };\n const version = Utils.getFirstMatch(/(?:yabrowser)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/ucbrowser/i],\n describe(ua) {\n const browser = {\n name: 'UC Browser',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:ucbrowser)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/Maxthon|mxios/i],\n describe(ua) {\n const browser = {\n name: 'Maxthon',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:Maxthon|mxios)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/epiphany/i],\n describe(ua) {\n const browser = {\n name: 'Epiphany',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:epiphany)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/puffin/i],\n describe(ua) {\n const browser = {\n name: 'Puffin',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:puffin)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/sleipnir/i],\n describe(ua) {\n const browser = {\n name: 'Sleipnir',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:sleipnir)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/k-meleon/i],\n describe(ua) {\n const browser = {\n name: 'K-Meleon',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:k-meleon)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/micromessenger/i],\n describe(ua) {\n const browser = {\n name: 'WeChat',\n };\n const version = Utils.getFirstMatch(/(?:micromessenger)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/qqbrowser/i],\n describe(ua) {\n const browser = {\n name: (/qqbrowserlite/i).test(ua) ? 'QQ Browser Lite' : 'QQ Browser',\n };\n const version = Utils.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\\d+(\\.?_?\\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/msie|trident/i],\n describe(ua) {\n const browser = {\n name: 'Internet Explorer',\n };\n const version = Utils.getFirstMatch(/(?:msie |rv:)(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/\\sedg\\//i],\n describe(ua) {\n const browser = {\n name: 'Microsoft Edge',\n };\n\n const version = Utils.getFirstMatch(/\\sedg\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/edg([ea]|ios)/i],\n describe(ua) {\n const browser = {\n name: 'Microsoft Edge',\n };\n\n const version = Utils.getSecondMatch(/edg([ea]|ios)\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/vivaldi/i],\n describe(ua) {\n const browser = {\n name: 'Vivaldi',\n };\n const version = Utils.getFirstMatch(/vivaldi\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/seamonkey/i],\n describe(ua) {\n const browser = {\n name: 'SeaMonkey',\n };\n const version = Utils.getFirstMatch(/seamonkey\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/sailfish/i],\n describe(ua) {\n const browser = {\n name: 'Sailfish',\n };\n\n const version = Utils.getFirstMatch(/sailfish\\s?browser\\/(\\d+(\\.\\d+)?)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/silk/i],\n describe(ua) {\n const browser = {\n name: 'Amazon Silk',\n };\n const version = Utils.getFirstMatch(/silk\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/phantom/i],\n describe(ua) {\n const browser = {\n name: 'PhantomJS',\n };\n const version = Utils.getFirstMatch(/phantomjs\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/slimerjs/i],\n describe(ua) {\n const browser = {\n name: 'SlimerJS',\n };\n const version = Utils.getFirstMatch(/slimerjs\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/blackberry|\\bbb\\d+/i, /rim\\stablet/i],\n describe(ua) {\n const browser = {\n name: 'BlackBerry',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/blackberry[\\d]+\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/(web|hpw)[o0]s/i],\n describe(ua) {\n const browser = {\n name: 'WebOS Browser',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/w(?:eb)?[o0]sbrowser\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/bada/i],\n describe(ua) {\n const browser = {\n name: 'Bada',\n };\n const version = Utils.getFirstMatch(/dolfin\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/tizen/i],\n describe(ua) {\n const browser = {\n name: 'Tizen',\n };\n const version = Utils.getFirstMatch(/(?:tizen\\s?)?browser\\/(\\d+(\\.?_?\\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/qupzilla/i],\n describe(ua) {\n const browser = {\n name: 'QupZilla',\n };\n const version = Utils.getFirstMatch(/(?:qupzilla)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/firefox|iceweasel|fxios/i],\n describe(ua) {\n const browser = {\n name: 'Firefox',\n };\n const version = Utils.getFirstMatch(/(?:firefox|iceweasel|fxios)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/electron/i],\n describe(ua) {\n const browser = {\n name: 'Electron',\n };\n const version = Utils.getFirstMatch(/(?:electron)\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/MiuiBrowser/i],\n describe(ua) {\n const browser = {\n name: 'Miui',\n };\n const version = Utils.getFirstMatch(/(?:MiuiBrowser)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/chromium/i],\n describe(ua) {\n const browser = {\n name: 'Chromium',\n };\n const version = Utils.getFirstMatch(/(?:chromium)[\\s/](\\d+(\\.?_?\\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/chrome|crios|crmo/i],\n describe(ua) {\n const browser = {\n name: 'Chrome',\n };\n const version = Utils.getFirstMatch(/(?:chrome|crios|crmo)\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n {\n test: [/GSA/i],\n describe(ua) {\n const browser = {\n name: 'Google Search',\n };\n const version = Utils.getFirstMatch(/(?:GSA)\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n\n /* Android Browser */\n {\n test(parser) {\n const notLikeAndroid = !parser.test(/like android/i);\n const butAndroid = parser.test(/android/i);\n return notLikeAndroid && butAndroid;\n },\n describe(ua) {\n const browser = {\n name: 'Android Browser',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n\n /* PlayStation 4 */\n {\n test: [/playstation 4/i],\n describe(ua) {\n const browser = {\n name: 'PlayStation 4',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n\n /* Safari */\n {\n test: [/safari|applewebkit/i],\n describe(ua) {\n const browser = {\n name: 'Safari',\n };\n const version = Utils.getFirstMatch(commonVersionIdentifier, ua);\n\n if (version) {\n browser.version = version;\n }\n\n return browser;\n },\n },\n\n /* Something else */\n {\n test: [/.*/i],\n describe(ua) {\n /* Here we try to make sure that there are explicit details about the device\n * in order to decide what regexp exactly we want to apply\n * (as there is a specific decision based on that conclusion)\n */\n const regexpWithoutDeviceSpec = /^(.*)\\/(.*) /;\n const regexpWithDeviceSpec = /^(.*)\\/(.*)[ \\t]\\((.*)/;\n const hasDeviceSpec = ua.search('\\\\(') !== -1;\n const regexp = hasDeviceSpec ? regexpWithDeviceSpec : regexpWithoutDeviceSpec;\n return {\n name: Utils.getFirstMatch(regexp, ua),\n version: Utils.getSecondMatch(regexp, ua),\n };\n },\n },\n];\n\nexport default browsersList;\n","import Utils from './utils.js';\nimport { OS_MAP } from './constants.js';\n\nexport default [\n /* Roku */\n {\n test: [/Roku\\/DVP/],\n describe(ua) {\n const version = Utils.getFirstMatch(/Roku\\/DVP-(\\d+\\.\\d+)/i, ua);\n return {\n name: OS_MAP.Roku,\n version,\n };\n },\n },\n\n /* Windows Phone */\n {\n test: [/windows phone/i],\n describe(ua) {\n const version = Utils.getFirstMatch(/windows phone (?:os)?\\s?(\\d+(\\.\\d+)*)/i, ua);\n return {\n name: OS_MAP.WindowsPhone,\n version,\n };\n },\n },\n\n /* Windows */\n {\n test: [/windows /i],\n describe(ua) {\n const version = Utils.getFirstMatch(/Windows ((NT|XP)( \\d\\d?.\\d)?)/i, ua);\n const versionName = Utils.getWindowsVersionName(version);\n\n return {\n name: OS_MAP.Windows,\n version,\n versionName,\n };\n },\n },\n\n /* Firefox on iPad */\n {\n test: [/Macintosh(.*?) FxiOS(.*?)\\//],\n describe(ua) {\n const result = {\n name: OS_MAP.iOS,\n };\n const version = Utils.getSecondMatch(/(Version\\/)(\\d[\\d.]+)/, ua);\n if (version) {\n result.version = version;\n }\n return result;\n },\n },\n\n /* macOS */\n {\n test: [/macintosh/i],\n describe(ua) {\n const version = Utils.getFirstMatch(/mac os x (\\d+(\\.?_?\\d+)+)/i, ua).replace(/[_\\s]/g, '.');\n const versionName = Utils.getMacOSVersionName(version);\n\n const os = {\n name: OS_MAP.MacOS,\n version,\n };\n if (versionName) {\n os.versionName = versionName;\n }\n return os;\n },\n },\n\n /* iOS */\n {\n test: [/(ipod|iphone|ipad)/i],\n describe(ua) {\n const version = Utils.getFirstMatch(/os (\\d+([_\\s]\\d+)*) like mac os x/i, ua).replace(/[_\\s]/g, '.');\n\n return {\n name: OS_MAP.iOS,\n version,\n };\n },\n },\n\n /* Android */\n {\n test(parser) {\n const notLikeAndroid = !parser.test(/like android/i);\n const butAndroid = parser.test(/android/i);\n return notLikeAndroid && butAndroid;\n },\n describe(ua) {\n const version = Utils.getFirstMatch(/android[\\s/-](\\d+(\\.\\d+)*)/i, ua);\n const versionName = Utils.getAndroidVersionName(version);\n const os = {\n name: OS_MAP.Android,\n version,\n };\n if (versionName) {\n os.versionName = versionName;\n }\n return os;\n },\n },\n\n /* WebOS */\n {\n test: [/(web|hpw)[o0]s/i],\n describe(ua) {\n const version = Utils.getFirstMatch(/(?:web|hpw)[o0]s\\/(\\d+(\\.\\d+)*)/i, ua);\n const os = {\n name: OS_MAP.WebOS,\n };\n\n if (version && version.length) {\n os.version = version;\n }\n return os;\n },\n },\n\n /* BlackBerry */\n {\n test: [/blackberry|\\bbb\\d+/i, /rim\\stablet/i],\n describe(ua) {\n const version = Utils.getFirstMatch(/rim\\stablet\\sos\\s(\\d+(\\.\\d+)*)/i, ua)\n || Utils.getFirstMatch(/blackberry\\d+\\/(\\d+([_\\s]\\d+)*)/i, ua)\n || Utils.getFirstMatch(/\\bbb(\\d+)/i, ua);\n\n return {\n name: OS_MAP.BlackBerry,\n version,\n };\n },\n },\n\n /* Bada */\n {\n test: [/bada/i],\n describe(ua) {\n const version = Utils.getFirstMatch(/bada\\/(\\d+(\\.\\d+)*)/i, ua);\n\n return {\n name: OS_MAP.Bada,\n version,\n };\n },\n },\n\n /* Tizen */\n {\n test: [/tizen/i],\n describe(ua) {\n const version = Utils.getFirstMatch(/tizen[/\\s](\\d+(\\.\\d+)*)/i, ua);\n\n return {\n name: OS_MAP.Tizen,\n version,\n };\n },\n },\n\n /* Linux */\n {\n test: [/linux/i],\n describe() {\n return {\n name: OS_MAP.Linux,\n };\n },\n },\n\n /* Chrome OS */\n {\n test: [/CrOS/],\n describe() {\n return {\n name: OS_MAP.ChromeOS,\n };\n },\n },\n\n /* Playstation 4 */\n {\n test: [/PlayStation 4/],\n describe(ua) {\n const version = Utils.getFirstMatch(/PlayStation 4[/\\s](\\d+(\\.\\d+)*)/i, ua);\n return {\n name: OS_MAP.PlayStation4,\n version,\n };\n },\n },\n];\n","import Utils from './utils.js';\nimport { PLATFORMS_MAP } from './constants.js';\n\n/*\n * Tablets go first since usually they have more specific\n * signs to detect.\n */\n\nexport default [\n /* Googlebot */\n {\n test: [/googlebot/i],\n describe() {\n return {\n type: 'bot',\n vendor: 'Google',\n };\n },\n },\n\n /* Huawei */\n {\n test: [/huawei/i],\n describe(ua) {\n const model = Utils.getFirstMatch(/(can-l01)/i, ua) && 'Nova';\n const platform = {\n type: PLATFORMS_MAP.mobile,\n vendor: 'Huawei',\n };\n if (model) {\n platform.model = model;\n }\n return platform;\n },\n },\n\n /* Nexus Tablet */\n {\n test: [/nexus\\s*(?:7|8|9|10).*/i],\n describe() {\n return {\n type: PLATFORMS_MAP.tablet,\n vendor: 'Nexus',\n };\n },\n },\n\n /* iPad */\n {\n test: [/ipad/i],\n describe() {\n return {\n type: PLATFORMS_MAP.tablet,\n vendor: 'Apple',\n model: 'iPad',\n };\n },\n },\n\n /* Firefox on iPad */\n {\n test: [/Macintosh(.*?) FxiOS(.*?)\\//],\n describe() {\n return {\n type: PLATFORMS_MAP.tablet,\n vendor: 'Apple',\n model: 'iPad',\n };\n },\n },\n\n /* Amazon Kindle Fire */\n {\n test: [/kftt build/i],\n describe() {\n return {\n type: PLATFORMS_MAP.tablet,\n vendor: 'Amazon',\n model: 'Kindle Fire HD 7',\n };\n },\n },\n\n /* Another Amazon Tablet with Silk */\n {\n test: [/silk/i],\n describe() {\n return {\n type: PLATFORMS_MAP.tablet,\n vendor: 'Amazon',\n };\n },\n },\n\n /* Tablet */\n {\n test: [/tablet(?! pc)/i],\n describe() {\n return {\n type: PLATFORMS_MAP.tablet,\n };\n },\n },\n\n /* iPod/iPhone */\n {\n test(parser) {\n const iDevice = parser.test(/ipod|iphone/i);\n const likeIDevice = parser.test(/like (ipod|iphone)/i);\n return iDevice && !likeIDevice;\n },\n describe(ua) {\n const model = Utils.getFirstMatch(/(ipod|iphone)/i, ua);\n return {\n type: PLATFORMS_MAP.mobile,\n vendor: 'Apple',\n model,\n };\n },\n },\n\n /* Nexus Mobile */\n {\n test: [/nexus\\s*[0-6].*/i, /galaxy nexus/i],\n describe() {\n return {\n type: PLATFORMS_MAP.mobile,\n vendor: 'Nexus',\n };\n },\n },\n\n /* Mobile */\n {\n test: [/[^-]mobi/i],\n describe() {\n return {\n type: PLATFORMS_MAP.mobile,\n };\n },\n },\n\n /* BlackBerry */\n {\n test(parser) {\n return parser.getBrowserName(true) === 'blackberry';\n },\n describe() {\n return {\n type: PLATFORMS_MAP.mobile,\n vendor: 'BlackBerry',\n };\n },\n },\n\n /* Bada */\n {\n test(parser) {\n return parser.getBrowserName(true) === 'bada';\n },\n describe() {\n return {\n type: PLATFORMS_MAP.mobile,\n };\n },\n },\n\n /* Windows Phone */\n {\n test(parser) {\n return parser.getBrowserName() === 'windows phone';\n },\n describe() {\n return {\n type: PLATFORMS_MAP.mobile,\n vendor: 'Microsoft',\n };\n },\n },\n\n /* Android Tablet */\n {\n test(parser) {\n const osMajorVersion = Number(String(parser.getOSVersion()).split('.')[0]);\n return parser.getOSName(true) === 'android' && (osMajorVersion >= 3);\n },\n describe() {\n return {\n type: PLATFORMS_MAP.tablet,\n };\n },\n },\n\n /* Android Mobile */\n {\n test(parser) {\n return parser.getOSName(true) === 'android';\n },\n describe() {\n return {\n type: PLATFORMS_MAP.mobile,\n };\n },\n },\n\n /* desktop */\n {\n test(parser) {\n return parser.getOSName(true) === 'macos';\n },\n describe() {\n return {\n type: PLATFORMS_MAP.desktop,\n vendor: 'Apple',\n };\n },\n },\n\n /* Windows */\n {\n test(parser) {\n return parser.getOSName(true) === 'windows';\n },\n describe() {\n return {\n type: PLATFORMS_MAP.desktop,\n };\n },\n },\n\n /* Linux */\n {\n test(parser) {\n return parser.getOSName(true) === 'linux';\n },\n describe() {\n return {\n type: PLATFORMS_MAP.desktop,\n };\n },\n },\n\n /* PlayStation 4 */\n {\n test(parser) {\n return parser.getOSName(true) === 'playstation 4';\n },\n describe() {\n return {\n type: PLATFORMS_MAP.tv,\n };\n },\n },\n\n /* Roku */\n {\n test(parser) {\n return parser.getOSName(true) === 'roku';\n },\n describe() {\n return {\n type: PLATFORMS_MAP.tv,\n };\n },\n },\n];\n","import Utils from './utils.js';\nimport { ENGINE_MAP } from './constants.js';\n\n/*\n * More specific goes first\n */\nexport default [\n /* EdgeHTML */\n {\n test(parser) {\n return parser.getBrowserName(true) === 'microsoft edge';\n },\n describe(ua) {\n const isBlinkBased = /\\sedg\\//i.test(ua);\n\n // return blink if it's blink-based one\n if (isBlinkBased) {\n return {\n name: ENGINE_MAP.Blink,\n };\n }\n\n // otherwise match the version and return EdgeHTML\n const version = Utils.getFirstMatch(/edge\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n return {\n name: ENGINE_MAP.EdgeHTML,\n version,\n };\n },\n },\n\n /* Trident */\n {\n test: [/trident/i],\n describe(ua) {\n const engine = {\n name: ENGINE_MAP.Trident,\n };\n\n const version = Utils.getFirstMatch(/trident\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n engine.version = version;\n }\n\n return engine;\n },\n },\n\n /* Presto */\n {\n test(parser) {\n return parser.test(/presto/i);\n },\n describe(ua) {\n const engine = {\n name: ENGINE_MAP.Presto,\n };\n\n const version = Utils.getFirstMatch(/presto\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n engine.version = version;\n }\n\n return engine;\n },\n },\n\n /* Gecko */\n {\n test(parser) {\n const isGecko = parser.test(/gecko/i);\n const likeGecko = parser.test(/like gecko/i);\n return isGecko && !likeGecko;\n },\n describe(ua) {\n const engine = {\n name: ENGINE_MAP.Gecko,\n };\n\n const version = Utils.getFirstMatch(/gecko\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n engine.version = version;\n }\n\n return engine;\n },\n },\n\n /* Blink */\n {\n test: [/(apple)?webkit\\/537\\.36/i],\n describe() {\n return {\n name: ENGINE_MAP.Blink,\n };\n },\n },\n\n /* WebKit */\n {\n test: [/(apple)?webkit/i],\n describe(ua) {\n const engine = {\n name: ENGINE_MAP.WebKit,\n };\n\n const version = Utils.getFirstMatch(/webkit\\/(\\d+(\\.?_?\\d+)+)/i, ua);\n\n if (version) {\n engine.version = version;\n }\n\n return engine;\n },\n },\n];\n","import browserParsersList from './parser-browsers.js';\nimport osParsersList from './parser-os.js';\nimport platformParsersList from './parser-platforms.js';\nimport enginesParsersList from './parser-engines.js';\nimport Utils from './utils.js';\n\n/**\n * The main class that arranges the whole parsing process.\n */\nclass Parser {\n /**\n * Create instance of Parser\n *\n * @param {String} UA User-Agent string\n * @param {Boolean} [skipParsing=false] parser can skip parsing in purpose of performance\n * improvements if you need to make a more particular parsing\n * like {@link Parser#parseBrowser} or {@link Parser#parsePlatform}\n *\n * @throw {Error} in case of empty UA String\n *\n * @constructor\n */\n constructor(UA, skipParsing = false) {\n if (UA === void (0) || UA === null || UA === '') {\n throw new Error(\"UserAgent parameter can't be empty\");\n }\n\n this._ua = UA;\n\n /**\n * @typedef ParsedResult\n * @property {Object} browser\n * @property {String|undefined} [browser.name]\n * Browser name, like `\"Chrome\"` or `\"Internet Explorer\"`\n * @property {String|undefined} [browser.version] Browser version as a String `\"12.01.45334.10\"`\n * @property {Object} os\n * @property {String|undefined} [os.name] OS name, like `\"Windows\"` or `\"macOS\"`\n * @property {String|undefined} [os.version] OS version, like `\"NT 5.1\"` or `\"10.11.1\"`\n * @property {String|undefined} [os.versionName] OS name, like `\"XP\"` or `\"High Sierra\"`\n * @property {Object} platform\n * @property {String|undefined} [platform.type]\n * platform type, can be either `\"desktop\"`, `\"tablet\"` or `\"mobile\"`\n * @property {String|undefined} [platform.vendor] Vendor of the device,\n * like `\"Apple\"` or `\"Samsung\"`\n * @property {String|undefined} [platform.model] Device model,\n * like `\"iPhone\"` or `\"Kindle Fire HD 7\"`\n * @property {Object} engine\n * @property {String|undefined} [engine.name]\n * Can be any of this: `WebKit`, `Blink`, `Gecko`, `Trident`, `Presto`, `EdgeHTML`\n * @property {String|undefined} [engine.version] String version of the engine\n */\n this.parsedResult = {};\n\n if (skipParsing !== true) {\n this.parse();\n }\n }\n\n /**\n * Get UserAgent string of current Parser instance\n * @return {String} User-Agent String of the current object\n *\n * @public\n */\n getUA() {\n return this._ua;\n }\n\n /**\n * Test a UA string for a regexp\n * @param {RegExp} regex\n * @return {Boolean}\n */\n test(regex) {\n return regex.test(this._ua);\n }\n\n /**\n * Get parsed browser object\n * @return {Object}\n */\n parseBrowser() {\n this.parsedResult.browser = {};\n\n const browserDescriptor = Utils.find(browserParsersList, (_browser) => {\n if (typeof _browser.test === 'function') {\n return _browser.test(this);\n }\n\n if (_browser.test instanceof Array) {\n return _browser.test.some(condition => this.test(condition));\n }\n\n throw new Error(\"Browser's test function is not valid\");\n });\n\n if (browserDescriptor) {\n this.parsedResult.browser = browserDescriptor.describe(this.getUA());\n }\n\n return this.parsedResult.browser;\n }\n\n /**\n * Get parsed browser object\n * @return {Object}\n *\n * @public\n */\n getBrowser() {\n if (this.parsedResult.browser) {\n return this.parsedResult.browser;\n }\n\n return this.parseBrowser();\n }\n\n /**\n * Get browser's name\n * @return {String} Browser's name or an empty string\n *\n * @public\n */\n getBrowserName(toLowerCase) {\n if (toLowerCase) {\n return String(this.getBrowser().name).toLowerCase() || '';\n }\n return this.getBrowser().name || '';\n }\n\n\n /**\n * Get browser's version\n * @return {String} version of browser\n *\n * @public\n */\n getBrowserVersion() {\n return this.getBrowser().version;\n }\n\n /**\n * Get OS\n * @return {Object}\n *\n * @example\n * this.getOS();\n * {\n * name: 'macOS',\n * version: '10.11.12'\n * }\n */\n getOS() {\n if (this.parsedResult.os) {\n return this.parsedResult.os;\n }\n\n return this.parseOS();\n }\n\n /**\n * Parse OS and save it to this.parsedResult.os\n * @return {*|{}}\n */\n parseOS() {\n this.parsedResult.os = {};\n\n const os = Utils.find(osParsersList, (_os) => {\n if (typeof _os.test === 'function') {\n return _os.test(this);\n }\n\n if (_os.test instanceof Array) {\n return _os.test.some(condition => this.test(condition));\n }\n\n throw new Error(\"Browser's test function is not valid\");\n });\n\n if (os) {\n this.parsedResult.os = os.describe(this.getUA());\n }\n\n return this.parsedResult.os;\n }\n\n /**\n * Get OS name\n * @param {Boolean} [toLowerCase] return lower-cased value\n * @return {String} name of the OS — macOS, Windows, Linux, etc.\n */\n getOSName(toLowerCase) {\n const { name } = this.getOS();\n\n if (toLowerCase) {\n return String(name).toLowerCase() || '';\n }\n\n return name || '';\n }\n\n /**\n * Get OS version\n * @return {String} full version with dots ('10.11.12', '5.6', etc)\n */\n getOSVersion() {\n return this.getOS().version;\n }\n\n /**\n * Get parsed platform\n * @return {{}}\n */\n getPlatform() {\n if (this.parsedResult.platform) {\n return this.parsedResult.platform;\n }\n\n return this.parsePlatform();\n }\n\n /**\n * Get platform name\n * @param {Boolean} [toLowerCase=false]\n * @return {*}\n */\n getPlatformType(toLowerCase = false) {\n const { type } = this.getPlatform();\n\n if (toLowerCase) {\n return String(type).toLowerCase() || '';\n }\n\n return type || '';\n }\n\n /**\n * Get parsed platform\n * @return {{}}\n */\n parsePlatform() {\n this.parsedResult.platform = {};\n\n const platform = Utils.find(platformParsersList, (_platform) => {\n if (typeof _platform.test === 'function') {\n return _platform.test(this);\n }\n\n if (_platform.test instanceof Array) {\n return _platform.test.some(condition => this.test(condition));\n }\n\n throw new Error(\"Browser's test function is not valid\");\n });\n\n if (platform) {\n this.parsedResult.platform = platform.describe(this.getUA());\n }\n\n return this.parsedResult.platform;\n }\n\n /**\n * Get parsed engine\n * @return {{}}\n */\n getEngine() {\n if (this.parsedResult.engine) {\n return this.parsedResult.engine;\n }\n\n return this.parseEngine();\n }\n\n /**\n * Get engines's name\n * @return {String} Engines's name or an empty string\n *\n * @public\n */\n getEngineName(toLowerCase) {\n if (toLowerCase) {\n return String(this.getEngine().name).toLowerCase() || '';\n }\n return this.getEngine().name || '';\n }\n\n /**\n * Get parsed platform\n * @return {{}}\n */\n parseEngine() {\n this.parsedResult.engine = {};\n\n const engine = Utils.find(enginesParsersList, (_engine) => {\n if (typeof _engine.test === 'function') {\n return _engine.test(this);\n }\n\n if (_engine.test instanceof Array) {\n return _engine.test.some(condition => this.test(condition));\n }\n\n throw new Error(\"Browser's test function is not valid\");\n });\n\n if (engine) {\n this.parsedResult.engine = engine.describe(this.getUA());\n }\n\n return this.parsedResult.engine;\n }\n\n /**\n * Parse full information about the browser\n * @returns {Parser}\n */\n parse() {\n this.parseBrowser();\n this.parseOS();\n this.parsePlatform();\n this.parseEngine();\n\n return this;\n }\n\n /**\n * Get parsed result\n * @return {ParsedResult}\n */\n getResult() {\n return Utils.assign({}, this.parsedResult);\n }\n\n /**\n * Check if parsed browser matches certain conditions\n *\n * @param {Object} checkTree It's one or two layered object,\n * which can include a platform or an OS on the first layer\n * and should have browsers specs on the bottom-laying layer\n *\n * @returns {Boolean|undefined} Whether the browser satisfies the set conditions or not.\n * Returns `undefined` when the browser is no described in the checkTree object.\n *\n * @example\n * const browser = Bowser.getParser(window.navigator.userAgent);\n * if (browser.satisfies({chrome: '>118.01.1322' }))\n * // or with os\n * if (browser.satisfies({windows: { chrome: '>118.01.1322' } }))\n * // or with platforms\n * if (browser.satisfies({desktop: { chrome: '>118.01.1322' } }))\n */\n satisfies(checkTree) {\n const platformsAndOSes = {};\n let platformsAndOSCounter = 0;\n const browsers = {};\n let browsersCounter = 0;\n\n const allDefinitions = Object.keys(checkTree);\n\n allDefinitions.forEach((key) => {\n const currentDefinition = checkTree[key];\n if (typeof currentDefinition === 'string') {\n browsers[key] = currentDefinition;\n browsersCounter += 1;\n } else if (typeof currentDefinition === 'object') {\n platformsAndOSes[key] = currentDefinition;\n platformsAndOSCounter += 1;\n }\n });\n\n if (platformsAndOSCounter > 0) {\n const platformsAndOSNames = Object.keys(platformsAndOSes);\n const OSMatchingDefinition = Utils.find(platformsAndOSNames, name => (this.isOS(name)));\n\n if (OSMatchingDefinition) {\n const osResult = this.satisfies(platformsAndOSes[OSMatchingDefinition]);\n\n if (osResult !== void 0) {\n return osResult;\n }\n }\n\n const platformMatchingDefinition = Utils.find(\n platformsAndOSNames,\n name => (this.isPlatform(name)),\n );\n if (platformMatchingDefinition) {\n const platformResult = this.satisfies(platformsAndOSes[platformMatchingDefinition]);\n\n if (platformResult !== void 0) {\n return platformResult;\n }\n }\n }\n\n if (browsersCounter > 0) {\n const browserNames = Object.keys(browsers);\n const matchingDefinition = Utils.find(browserNames, name => (this.isBrowser(name, true)));\n\n if (matchingDefinition !== void 0) {\n return this.compareVersion(browsers[matchingDefinition]);\n }\n }\n\n return undefined;\n }\n\n /**\n * Check if the browser name equals the passed string\n * @param browserName The string to compare with the browser name\n * @param [includingAlias=false] The flag showing whether alias will be included into comparison\n * @returns {boolean}\n */\n isBrowser(browserName, includingAlias = false) {\n const defaultBrowserName = this.getBrowserName().toLowerCase();\n let browserNameLower = browserName.toLowerCase();\n const alias = Utils.getBrowserTypeByAlias(browserNameLower);\n\n if (includingAlias && alias) {\n browserNameLower = alias.toLowerCase();\n }\n return browserNameLower === defaultBrowserName;\n }\n\n compareVersion(version) {\n let expectedResults = [0];\n let comparableVersion = version;\n let isLoose = false;\n\n const currentBrowserVersion = this.getBrowserVersion();\n\n if (typeof currentBrowserVersion !== 'string') {\n return void 0;\n }\n\n if (version[0] === '>' || version[0] === '<') {\n comparableVersion = version.substr(1);\n if (version[1] === '=') {\n isLoose = true;\n comparableVersion = version.substr(2);\n } else {\n expectedResults = [];\n }\n if (version[0] === '>') {\n expectedResults.push(1);\n } else {\n expectedResults.push(-1);\n }\n } else if (version[0] === '=') {\n comparableVersion = version.substr(1);\n } else if (version[0] === '~') {\n isLoose = true;\n comparableVersion = version.substr(1);\n }\n\n return expectedResults.indexOf(\n Utils.compareVersions(currentBrowserVersion, comparableVersion, isLoose),\n ) > -1;\n }\n\n isOS(osName) {\n return this.getOSName(true) === String(osName).toLowerCase();\n }\n\n isPlatform(platformType) {\n return this.getPlatformType(true) === String(platformType).toLowerCase();\n }\n\n isEngine(engineName) {\n return this.getEngineName(true) === String(engineName).toLowerCase();\n }\n\n /**\n * Is anything? Check if the browser is called \"anything\",\n * the OS called \"anything\" or the platform called \"anything\"\n * @param {String} anything\n * @param [includingAlias=false] The flag showing whether alias will be included into comparison\n * @returns {Boolean}\n */\n is(anything, includingAlias = false) {\n return this.isBrowser(anything, includingAlias) || this.isOS(anything)\n || this.isPlatform(anything);\n }\n\n /**\n * Check if any of the given values satisfies this.is(anything)\n * @param {String[]} anythings\n * @returns {Boolean}\n */\n some(anythings = []) {\n return anythings.some(anything => this.is(anything));\n }\n}\n\nexport default Parser;\n","declare global {\n\tinterface Window {\n\t\tm_dataLayer: any;\n\t\taf_dataLayer: any;\n\t\tunify_dataSlayer: any;\n\t\t_gaq: any;\n\t\tgdprAppliesGlobally: boolean;\n\t\tdidomiOnReady: Function[];\n\t}\n}\n\ninterface GaEvent {\n\tevent: 'UA - Event' | 'uaevent';\n\teventCategory: string;\n\teventAction: string;\n\teventLabel?: string;\n\teventValue?: any;\n\teventNonInt: boolean;\n\tdata: any;\n}\n\ninterface MobileGAEvent {\n\tevent: 'UA-Event';\n\tuaEventCategory: string;\n\tuaEventAction: string;\n\tuaEventLibelle: string;\n\tuaEventValue: any;\n\tuaEventNonInt: boolean;\n\tdata: any;\n}\n\nexport const trackAnalyticsEvent = (\n\tcategory: string,\n\taction: string,\n\topt_label = '',\n\topt_value: any,\n\topt_noninteraction = false,\n\tprefix = '',\n\tsampling = 100,\n\tcustomData?: any\n) => {\n\t// Block useless events to avoid reaching GA limitations\n\tif (category === 'AF_Album' && action === 'go') return;\n\tif (category === 'AF_Album' && action === 'prev') return;\n\tif (category === 'AF_Album' && action === 'next') return;\n\n\t// Sample events\n\tif (\n\t\t!isNaN(parseInt('' + sampling)) &&\n\t\tMath.floor(Math.random() * 100) > +sampling\n\t) {\n\t\treturn;\n\t}\n\n\tconst eventBase = {\n\t\teventCategory: category,\n\t\teventAction: action,\n\t\teventLabel: opt_label,\n\t\teventValue: opt_value,\n\t\teventNonInt: true\n\t};\n\n\tlet event: GaEvent | MobileGAEvent;\n\n\tif (typeof window.m_dataLayer !== 'undefined') {\n\t\tevent = {\n\t\t\tevent: 'UA-Event',\n\t\t\tuaEventCategory: category,\n\t\t\tuaEventAction: action,\n\t\t\tuaEventLibelle: opt_label,\n\t\t\tuaEventValue: opt_value,\n\t\t\tuaEventNonInt: true,\n\t\t\t...customData\n\t\t};\n\n\t\twindow.m_dataLayer.push(event);\n\t} else if (typeof window.af_dataLayer !== 'undefined') {\n\t\tevent = {\n\t\t\tevent: 'UA - Event',\n\t\t\t...eventBase,\n\t\t\t...customData\n\t\t};\n\n\t\twindow.af_dataLayer.push(event);\n\t} else if (typeof window._gaq !== 'undefined') {\n\t\tif (prefix != '' && prefix.substr(-1) != '.') prefix += '.';\n\t\twindow._gaq.push([\n\t\t\tprefix + '_trackEvent',\n\t\t\tcategory,\n\t\t\taction,\n\t\t\topt_label,\n\t\t\topt_value,\n\t\t\topt_noninteraction\n\t\t]);\n\t}\n\n\tif (typeof window.unify_dataSlayer !== 'undefined') {\n\t\tevent = {\n\t\t\tevent: 'uaevent',\n\t\t\t...eventBase,\n\t\t\t...customData\n\t\t};\n\n\t\tif (window.gdprAppliesGlobally) {\n\t\t\t// Site with GDPR: wait for CMP consent before adding any GA event to the datalayer, otherwise these events are not tracked properly\n\t\t\twindow.didomiOnReady = window.didomiOnReady || [];\n\t\t\twindow.didomiOnReady.push(function () {\n\t\t\t\twindow.unify_dataSlayer.push(event);\n\t\t\t});\n\t\t} else {\n\t\t\t// Site without GDPR: fire events synchronously\n\t\t\twindow.unify_dataSlayer.push(event);\n\t\t}\n\t}\n};\n","import { Players } from 'src/enums/players.enum';\nimport {\n\tPublishableVideoContentEvents,\n\tPublishableVideoPlayerEvents\n} from 'src/enums/publishable-events.enum';\nimport { DailymotionEmbedPlayer } from 'src/players/dailymotion-embed';\nimport { ListenerAction } from '../interfaces/listener-action';\nimport { Store, StoreInstance } from '../store';\nimport { trackAnalyticsEvent } from './utils/ga-tracking.util';\nimport PubSub from 'pubsub-js';\n\nconst EVENT_CATEGORY = 'Video';\n\ninterface ExtraDailymotionVideoData {\n\ttype: string;\n\tdatePublication: string;\n}\n\nexport class GaVideoTracker {\n\tprivate _events: Map> = new Map<\n\t\tstring,\n\t\tMap\n\t>();\n\n\tprivate _store: Store;\n\tprivate static instance: GaVideoTracker;\n\tprivate _extraDailymotionData = new Map();\n\n\tprivate _listenersActions: ListenerAction[] = [\n\t\t{\n\t\t\tmessage: PublishableVideoContentEvents.VIDEO_START,\n\t\t\tactionFn: async (msg, data) =>\n\t\t\t\tawait this._trackEventOnceByVideo(data.id, 'Play', data)\n\t\t},\n\t\t{\n\t\t\tmessage: 'video.player.complete',\n\t\t\tactionFn: async (msg, data) =>\n\t\t\t\tawait this._trackEventOnceByVideo(data.id, 'Completed', data)\n\t\t},\n\t\t{\n\t\t\tmessage: PublishableVideoPlayerEvents.UNMUTE,\n\t\t\tactionFn: async (msg, data) =>\n\t\t\t\tawait this._trackEventOnceByVideo(data.id, 'player unmute', data)\n\t\t}\n\t];\n\n\tconstructor() {\n\t\tthis._init();\n\t}\n\n\tprivate _init() {\n\t\tthis._store = (window as any).AufVideo.Store.get();\n\t\tthis._initEventListeners(this._listenersActions);\n\t}\n\n\tprivate _initEventListeners(listenersActions: ListenerAction[]) {\n\t\tlistenersActions.forEach((listenAction) =>\n\t\t\tPubSub.subscribe(listenAction.message, listenAction.actionFn)\n\t\t);\n\t}\n\n\tprivate async _trackEventOnceByVideo(\n\t\tinstanceId: string,\n\t\taction: string,\n\t\tdata: any\n\t) {\n\t\tconst instance = this._store.getInstance(instanceId);\n\t\tconst player = instance?.player;\n\n\t\tif (!player || !instance)\n\t\t\tthrow new Error('Missing Store Instance or player');\n\n\t\tconst videoId =\n\t\t\tplayer.name === Players.DAILYMOTION_EMBED\n\t\t\t\t? await (player as DailymotionEmbedPlayer).getVideo()\n\t\t\t\t: player.videoId;\n\n\t\tthis._events[instanceId] = this._events[instanceId] || {};\n\n\t\tif (this._events[instanceId][action] === videoId) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._trackEvent(action, await this._getDataToSend(instance, data));\n\t\tthis._events[instanceId][action] = videoId;\n\t}\n\n\tprivate _trackEvent = (action: string, dataToSend: any) =>\n\t\ttrackAnalyticsEvent(\n\t\t\tEVENT_CATEGORY,\n\t\t\taction,\n\t\t\tdataToSend['video.title'],\n\t\t\t'',\n\t\t\tfalse,\n\t\t\t'',\n\t\t\t100,\n\t\t\tdataToSend\n\t\t);\n\n\tprivate async _getDataToSend(instance: StoreInstance, customData: any) {\n\t\tconst player = instance.player;\n\t\tconst videoFileUrl =\n\t\t\t(customData && customData.file) ||\n\t\t\t((player as any).getFile && (player as any).getFile.apply(player)) ||\n\t\t\t'';\n\n\t\tlet extraDailymotionData = this._extraDailymotionData.get(player.videoId);\n\t\tconst shouldFetch =\n\t\t\t!extraDailymotionData &&\n\t\t\tplayer.name === Players.DAILYMOTION_EMBED &&\n\t\t\tplayer.videoId;\n\t\tif (shouldFetch) {\n\t\t\tconst getExtraAnalyticsData = async (\n\t\t\t\tdailymotionId: string\n\t\t\t): Promise => {\n\t\t\t\ttry {\n\t\t\t\t\tconsole.log('window.location', window.location);\n\n\t\t\t\t\tconst routePath = `reloaded/api/videos/extraanalyticsdata/${dailymotionId}`;\n\t\t\t\t\tconst internalDomains =\n\t\t\t\t\t\t/alfemminile|aufeminin|marmiton|enfeminino|taofeminino|gofeminin|wewomen|sofeminin|1001cocktails|petitsplatsenequilibre/;\n\t\t\t\t\tconst routeUrl = window.location.origin.match(internalDomains)\n\t\t\t\t\t\t? `/${routePath}`\n\t\t\t\t\t\t: `https://www.aufeminin.com/${routePath}`;\n\n\t\t\t\t\tconst response = await fetch(routeUrl);\n\t\t\t\t\tconst json = await response.json();\n\n\t\t\t\t\treturn Promise.resolve({\n\t\t\t\t\t\ttype: json.videoType,\n\t\t\t\t\t\tdatePublication: json.datePublication\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst errMsg = 'Cannot retrieve extra Analytics data';\n\n\t\t\t\t\tconsole.error(errMsg, error);\n\n\t\t\t\t\t// Return an object with unknown to let processing continue\n\t\t\t\t\treturn Promise.resolve({\n\t\t\t\t\t\ttype: 'unknown',\n\t\t\t\t\t\tdatePublication: 'unknown'\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\n\t\t\textraDailymotionData = await getExtraAnalyticsData(player.videoId);\n\t\t\tthis._extraDailymotionData.set(player.videoId, extraDailymotionData);\n\t\t}\n\n\t\treturn {\n\t\t\t'video.id': player.videoId,\n\t\t\t'video.context': instance.context,\n\t\t\t'video.place': instance.position,\n\t\t\t'video.url': videoFileUrl,\n\t\t\t'video.tags': '', // Not available\n\t\t\t'video.title': player.videoTitle,\n\t\t\t'video.player': player.name,\n\t\t\t'video.position': player.videosPlayed.length,\n\t\t\t'video.type': extraDailymotionData?.type,\n\t\t\t'video.date_publication': extraDailymotionData?.datePublication\n\t\t};\n\t}\n\n\tpublic static get(): GaVideoTracker {\n\t\tif (!GaVideoTracker.instance) {\n\t\t\tGaVideoTracker.instance = new GaVideoTracker();\n\t\t}\n\n\t\treturn GaVideoTracker.instance;\n\t}\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.Tracker = window.AufVideo.Tracker || {};\nwindow.AufVideo.Tracker.GA = GaVideoTracker;\n","import Bowser from \"bowser\";\n\nimport {\n\tJwPlayerPlaylist,\n\tPlaylistId\n} from './interfaces/player-playlist.interface';\nimport { VideoPlayerSettings } from './interfaces/VideoPlayerSettings.interface';\nimport { Manager } from './manager';\nimport { Store } from './store';\nimport { VideoConsoleLogger } from './utils/video-logger';\nimport { VideoLogger, VideoLoggerOptions } from './trackers/aufVideoLogger';\nimport { Players } from './enums/players.enum';\nimport { GaVideoTracker } from './trackers/GAVideoTracking';\n\nconst l = new VideoConsoleLogger();\nwindow.videoPlayerVersionNumber = '2.3.2';\nwindow.bowser = Bowser.parse(window.navigator.userAgent);\n\ndeclare global {\n\tinterface Window {\n\t\tvideoPhpVars: VideoPlayerSettings[];\n\t\tvideoPlayerVersionNumber: string;\n\t\tbowser: Bowser.Parser.ParsedResult;\n\t}\n}\n\nfunction buildVideoLogger(settings: VideoPlayerSettings) {\n\tconst videoLoggerSettings: VideoLoggerOptions = {\n\t\tcontext: {\n\t\t\tadPlayer:\n\t\t\t\tsettings.adTechno && settings.adTechno.name\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tname: settings.adTechno.name\n\t\t\t\t\t }\n\t\t\t\t\t: undefined,\n\t\t\tplayer: {\n\t\t\t\tversion: window.videoPlayerVersionNumber,\n\t\t\t\tname: settings.techno ? settings.techno.name : 'undefined',\n\t\t\t\tvideoId: settings.videoId,\n\t\t\t\tcontext: settings.context,\n\t\t\t\tposition: settings.position\n\t\t\t}\n\t\t}\n\t};\n\n\treturn new VideoLogger(videoLoggerSettings);\n}\n\nasync function buildVideoPlayer(\n\tplayerConstructor: any,\n\tsettings: VideoPlayerSettings\n) {\n\tconst isJwPlayer = settings.techno.id === Players.JWPLAYER;\n\tconst isDailymotion = settings.techno.id === Players.DAILYMOTION;\n\tconst isDailymotionEmbed = settings.techno.id === Players.DAILYMOTION_EMBED;\n\n\tlet playlist = isJwPlayer\n\t\t? ({\n\t\t\t\tsources: settings.sources,\n\t\t\t\timage: '' + settings.poster\n\t\t } as JwPlayerPlaylist)\n\t\t: isDailymotion || isDailymotionEmbed\n\t\t? (settings.dailymotionPlaylistID as PlaylistId)\n\t\t: undefined;\n\n\tconst playerSettings = {\n\t\tname: settings.techno?.name,\n\t\taspectRatio: settings.aspectRatio,\n\t\tfluid: Boolean(settings.aspectRatio),\n\t\theight: +settings.height,\n\t\tid: settings.playerId,\n\t\tmuted: settings.autoplay.startOnSight && settings.muted,\n\t\tplaylist: playlist ? playlist : undefined,\n\t\ttitle: settings.title,\n\t\ttype: settings.type,\n\t\tdatePublication: settings.datePublication,\n\t\tvideoId:\n\t\t\tisDailymotion || isDailymotionEmbed\n\t\t\t\t? settings.dailymotionId\n\t\t\t\t: settings.videoId,\n\t\tisAdDisabled: settings.isAdDisabled,\n\t\tisLazyLoadedPlayer: settings.isLazyLoadedPlayer,\n\t\tpmad: settings.pmad,\n\t\tpmxd: settings.pmxd\n\t};\n\n\tconst player = playerConstructor\n\t\t? new playerConstructor(playerSettings)\n\t\t: undefined;\n\n\treturn player;\n}\n\n/**\n * Configure ad video player\n */\nfunction buildAdPlayer(\n\tadPlayerConstructor: any,\n\tsettings: VideoPlayerSettings,\n\tadTargeting: any,\n\tplayer: any\n) {\n\tconst adsSettings: any = {\n\t\tid: settings.playerId,\n\t\tname: settings.adTechno?.name,\n\t\tplayer: player,\n\t\tadUnit: settings.adUnit,\n\t\tadTargeting,\n\t\tallowMultipleTinyAds: settings.allowMultipleTinyAds,\n\t\tsiteId: settings.siteId,\n\t\tisCM: settings.isCM,\n\t\tneedPegasus: settings.needPegasus,\n\t\thbVideoActive: settings.hbVideoActive,\n\t\tposition: '' + settings.position,\n\t\tadScheduleId: settings.adScheduleId,\n\t\tadLabel: settings.adLabel,\n\t\tlanguage: settings.adPlayerLanguage,\n\t\tmidrollActive: settings.midrollActive,\n\t\tminTimeMidroll: settings.minTimeMidroll,\n\t\tjwpAdvertisingParameters: settings.jwpAdvertisingParameters,\n\t\tadRule: settings.adRule\n\t};\n\n\treturn adPlayerConstructor ? new adPlayerConstructor(adsSettings) : undefined;\n}\n\nfunction addStoreInstance(\n\tlogger: VideoLogger,\n\tplayer: any,\n\tadPlayer: any,\n\tsettings: VideoPlayerSettings\n) {\n\tconst store: Store = Store.get();\n\tconst instanceProps = {\n\t\tlogger: logger,\n\t\tplayer: player,\n\t\tadPlayer: adPlayer,\n\t\tcontext: settings.context,\n\t\tposition: settings.position,\n\t\tautoplay: settings.autoplay,\n\t\tsticky: settings.sticky\n\t};\n\n\tstore.addInstance(settings.playerId, instanceProps);\n}\n\nexport async function initAll(\n\tplayerConstructor: any,\n\tadConstructor: any,\n\tsettings: VideoPlayerSettings\n) {\n\t/* * * * * * * * * * * * * * * * * *\n\t * Init trackers *\n\t * * * * * * * * * * * * * * * * * */\n\tGaVideoTracker.get(); // Note: gaTracker is not used afterwhile\n\tif (settings.isComScoreTrackingEnabled) {\n\t\t// comScore.init();\n\t}\n\n\t/* * * * * * * * * * * * * * * * * *\n\t * Instantiate Video Objects *\n\t * * * * * * * * * * * * * * * * * */\n\tconst logger = buildVideoLogger(settings);\n\tconst player = await buildVideoPlayer(playerConstructor, settings);\n\n\tconst adPlayer = !settings.isAdDisabled\n\t\t? buildAdPlayer(\n\t\t\t\tadConstructor,\n\t\t\t\tsettings,\n\t\t\t\t_getAdTargetingString(settings),\n\t\t\t\tplayer\n\t\t )\n\t\t: undefined;\n\n\tManager.get({\n\t\tlabels: {\n\t\t\tnextVideo: settings.nextVideoLabel\n\t\t}\n\t});\n\n\tif (!logger || !player || (!settings.isAdDisabled && !adPlayer)) {\n\t\tif (!logger) {\n\t\t\tl.error('VideoLogger is undefined !')();\n\t\t}\n\n\t\tif (!player) {\n\t\t\tl.error('Player is undefined !')();\n\t\t}\n\n\t\tif (!settings.isAdDisabled && !adPlayer) {\n\t\t\tl.error('AdPlayer is undefined !')();\n\t\t}\n\n\t\tthrow new Error('Missing mandatory object to add store instance');\n\t}\n\taddStoreInstance(logger, player, adPlayer, settings);\n\n\tfunction _getAdTargetingString(settings: VideoPlayerSettings) {\n\t\tconst newAdTargeting =\n\t\t\t';' +\n\t\t\t[\n\t\t\t\tsettings.adTarget,\n\t\t\t\t'player=' + settings.techno.id,\n\t\t\t\t'adplayer=' + settings.adTechno.id,\n\t\t\t\t'context=' + settings.context,\n\t\t\t\t'video=' + settings.videoId + 'v'\n\t\t\t].join(';');\n\n\t\treturn newAdTargeting;\n\t}\n}\n","/*!\n * Bowser - a browser detector\n * https://github.com/lancedikson/bowser\n * MIT License | (c) Dustin Diaz 2012-2015\n * MIT License | (c) Denis Demchenko 2015-2019\n */\nimport Parser from './parser.js';\nimport {\n BROWSER_MAP,\n ENGINE_MAP,\n OS_MAP,\n PLATFORMS_MAP,\n} from './constants.js';\n\n/**\n * Bowser class.\n * Keep it simple as much as it can be.\n * It's supposed to work with collections of {@link Parser} instances\n * rather then solve one-instance problems.\n * All the one-instance stuff is located in Parser class.\n *\n * @class\n * @classdesc Bowser is a static object, that provides an API to the Parsers\n * @hideconstructor\n */\nclass Bowser {\n /**\n * Creates a {@link Parser} instance\n *\n * @param {String} UA UserAgent string\n * @param {Boolean} [skipParsing=false] Will make the Parser postpone parsing until you ask it\n * explicitly. Same as `skipParsing` for {@link Parser}.\n * @returns {Parser}\n * @throws {Error} when UA is not a String\n *\n * @example\n * const parser = Bowser.getParser(window.navigator.userAgent);\n * const result = parser.getResult();\n */\n static getParser(UA, skipParsing = false) {\n if (typeof UA !== 'string') {\n throw new Error('UserAgent should be a string');\n }\n return new Parser(UA, skipParsing);\n }\n\n /**\n * Creates a {@link Parser} instance and runs {@link Parser.getResult} immediately\n *\n * @param UA\n * @return {ParsedResult}\n *\n * @example\n * const result = Bowser.parse(window.navigator.userAgent);\n */\n static parse(UA) {\n return (new Parser(UA)).getResult();\n }\n\n static get BROWSER_MAP() {\n return BROWSER_MAP;\n }\n\n static get ENGINE_MAP() {\n return ENGINE_MAP;\n }\n\n static get OS_MAP() {\n return OS_MAP;\n }\n\n static get PLATFORMS_MAP() {\n return PLATFORMS_MAP;\n }\n}\n\nexport default Bowser;\n","/**\n * This file responsability is to pilot the player instantiations modes\n */\n\nimport { Players } from './enums/players.enum';\nimport { VideoPlayerSettings } from './interfaces/VideoPlayerSettings.interface';\nimport { initAll } from './spawner';\nimport { AufVideoUtils } from './utils/utils';\nimport { VideoConsoleLogger } from './utils/video-logger';\n\nconst w = window as any;\nconst logger = new VideoConsoleLogger();\n\nfunction _isNoVideoTestMode() {\n\tconst queryParamsArr = location.search.slice(1).split('&');\n\n\treturn (\n\t\tqueryParamsArr.includes('utm_source=webperf') &&\n\t\tqueryParamsArr.includes('utm_medium=psi') &&\n\t\tqueryParamsArr.includes('utm_campaign=no-dailymotion')\n\t);\n}\n\nexport async function start(\n\tplayerConstructor: any,\n\tadPlayerConstructor: any,\n\tforce?: boolean\n) {\n\tw.videoPlayerUnifyInitDone =\n\t\ttypeof force !== 'undefined' ? false : w.videoPlayerUnifyInitDone;\n\n\tasync function ensureVideoVarsAreSet() {\n\t\tlet t = 0;\n\t\treturn new Promise(waitForVars);\n\n\t\tfunction waitForVars(resolve, reject) {\n\t\t\tif (window.videoPhpVars) {\n\t\t\t\tlogger.info('Player vars available after ' + t * 25 + ' ms')();\n\t\t\t\tresolve(window.videoPhpVars);\n\t\t\t} else {\n\t\t\t\tt++;\n\t\t\t\tsetTimeout(waitForVars.bind(this, resolve, reject), 25);\n\t\t\t}\n\t\t}\n\t}\n\n\t//Protection contre les instancations multiples du fait de plusieurs ESI dans la même page\n\tif (w.videoPlayerUnifyInitDone) {\n\t\treturn;\n\t}\n\tw.videoPlayerUnifyInitDone = true;\n\n\tawait ensureVideoVarsAreSet();\n\n\tlogger.info('Starting video players', w.videoPhpVars)();\n\n\tfor (let playerId in w.videoPhpVars) {\n\t\tconst settings = w.videoPhpVars[playerId] as VideoPlayerSettings;\n\t\tsettings.needPegasus = !AufVideoUtils.isPreview()\n\t\t\t? settings.needPegasus\n\t\t\t: false;\n\n\t\t// TODO: Déplacer ça dans le spawner\n\t\tvar isDailymotionEmbed = settings.techno.id === Players.DAILYMOTION_EMBED;\n\t\tsettings.isLazyLoadedPlayer = isDailymotionEmbed && settings.needPegasus;\n\n\t\t!_isNoVideoTestMode()\n\t\t\t? await initAll(playerConstructor, adPlayerConstructor, settings)\n\t\t\t: undefined;\n\t}\n}\n\nwindow.AufVideo = window.AufVideo || {};\nwindow.AufVideo.start = start;\n","// User-agent module\n// TODO: add OS detection\nexport const afUserAgent = (function () {\n\tvar _isMobile = false;\n\tvar _isTablet = false;\n\tvar _regexMobile =\n\t\t/(ipod|blackberry|phone|mobile|opera mini|pda|symbian|3ds|nokia|ericsson|alcatel)/gi;\n\tvar _regexTabletSmall =\n\t\t/(pad|lenovo|tab|GT-P5210|GT-P5110|Nexus 7|GT-N8010|GT-P3110)/gi;\n\tvar _regexTablet = /(pad|tab|android)/gi;\n\n\tvar _initialized = false;\n\tfunction _init() {\n\t\tif (_initialized) return;\n\n\t\t_initialized = true;\n\t\tif (navigator.userAgent.match(_regexMobile)) {\n\t\t\tif (navigator.userAgent.match(_regexTabletSmall)) {\n\t\t\t\t_isTablet = true;\n\t\t\t} else {\n\t\t\t\t_isMobile = true;\n\t\t\t}\n\t\t} else if (\n\t\t\tnavigator.userAgent.match(_regexTablet) &&\n\t\t\t!navigator.userAgent.match(/(pc)/gi)\n\t\t) {\n\t\t\t// TEMP: quick fix for IE11 detected as tablet\n\t\t\t_isTablet = true;\n\t\t}\n\t}\n\n\tfunction isMobile() {\n\t\t_init();\n\t\treturn _isMobile;\n\t}\n\n\tfunction isTablet() {\n\t\t_init();\n\t\treturn _isTablet;\n\t}\n\n\treturn {\n\t\tisMobile: isMobile,\n\t\tisTablet: isTablet\n\t};\n})();\n","// Event listener handler\nexport function afAddEvent(elt, event, listener, capture) {\n\tif (elt && elt.addEventListener) {\n\t\telt.addEventListener(event, listener, capture);\n\t\treturn true;\n\t} else if (elt && elt.attachEvent) {\n\t\treturn elt.attachEvent('on' + event, listener);\n\t} else if (elt) {\n\t\tvar oldListener = elt['on' + event];\n\t\telt['on' + event] = function (e) {\n\t\t\tif (oldListener) {\n\t\t\t\toldListener(e);\n\t\t\t}\n\t\t\treturn listener(e);\n\t\t};\n\t\treturn oldListener;\n\t}\n}\n","import { Subject } from 'rxjs';\nimport { VideoInfos } from 'src/interfaces/video-infos.interface.js';\nimport { VideoConsoleLogger } from 'src/utils/video-logger.js';\nimport { AspectRatio } from '../enums/aspect-ratio.enum.js';\nimport {\n\tPublishableVideoAdEvents,\n\tPublishableVideoContentEvents,\n\tPublishableVideoLogEvents,\n\tPublishableVideoPlayerEvents,\n\tPublishableVideoStickyEvents,\n\tPublishableVideoStoreEvents,\n\tPublishableVideoUserEvents\n} from '../enums/publishable-events.enum.js';\nimport { AdsParams } from '../interfaces/ads-params.interface.js';\nimport {\n\tPlayerErrorEventData,\n\tPlayerEventData\n} from '../interfaces/player-event-data.interface.js';\nimport { PlayerOptions } from '../interfaces/player-options.interface.js';\nimport PubSub from 'pubsub-js';\nimport { afUserAgent } from 'src/utils/detect-device.util.js';\nimport { afAddEvent } from 'src/utils/events.util.js';\n\nconst logger = new VideoConsoleLogger();\n\ntype PlayerEvent =\n\t| PublishableVideoPlayerEvents\n\t| PublishableVideoContentEvents\n\t| PublishableVideoUserEvents\n\t| PublishableVideoLogEvents\n\t| PublishableVideoAdEvents\n\t| PublishableVideoStoreEvents\n\t| PublishableVideoStickyEvents;\n\nexport default abstract class Player {\n\tpublic id: string;\n\tpublic name: string;\n\tpublic aspectRatio: AspectRatio;\n\tpublic muted: boolean;\n\tpublic videoId: string;\n\tpublic videoTitle: string;\n\tpublic videoDuration: number;\n\tpublic isMobile: boolean;\n\tpublic ready = false;\n\tpublic videoStarted = false;\n\tpublic isAdDisabled = false;\n\tpublic isSticked = false;\n\tpublic videosPlayed: VideoInfos[] = [];\n\tpublic videoInfos$ = new Subject();\n\n\tprotected _readyCb: ((...args: any[]) => any) | null;\n\tprotected _userUnmuted = false;\n\tprivate _aufIsMobile = afUserAgent.isMobile;\n\tprivate _aufAddEvent = afAddEvent;\n\n\tabstract api: HTMLMediaElement | any;\n\n\tconstructor(options: PlayerOptions) {\n\t\tif (\n\t\t\t!options ||\n\t\t\t!options.id ||\n\t\t\t!options.name ||\n\t\t\t!options.aspectRatio ||\n\t\t\ttypeof options.muted === 'undefined' ||\n\t\t\t!options.videoId ||\n\t\t\t!options.title\n\t\t) {\n\t\t\tthrow new Error('Missing mandatory parameter to initialize player');\n\t\t}\n\n\t\tthis.id = options.id;\n\t\tthis.name = options.name;\n\t\tthis.aspectRatio = options.aspectRatio;\n\t\tthis.muted = options.muted;\n\t\tthis.videoId = options.videoId;\n\t\tthis.videoTitle = options.title || 'none';\n\t\tthis.isAdDisabled = options.isAdDisabled || false;\n\t\tthis.isMobile = this._aufIsMobile(); // TODO: Créer un d.ts\n\t\tthis._readyCb = null;\n\n\t\tPubSub.subscribe(PublishableVideoAdEvents.AD_CANCEL, () => {\n\t\t\tthis.disableAds();\n\t\t});\n\t}\n\n\tpublic async init(\n\t\tadsParams?: AdsParams,\n\t\treadyCb?: (...args: any[]) => Promise\n\t): Promise {\n\t\tthis._readyCb = readyCb && typeof readyCb === 'function' ? readyCb : null;\n\n\t\ttry {\n\t\t\tthis.initListeners();\n\t\t\tawait this.initApi(adsParams);\n\t\t\tthis.initApiListeners();\n\t\t\tthis.initErrorsListeners();\n\t\t} catch (error) {\n\t\t\tlogger.error(error)();\n\t\t\treturn Promise.reject(error);\n\t\t}\n\n\t\treturn Promise.resolve();\n\t}\n\n\tpublic publish = (\n\t\tmessage: PlayerEvent | string,\n\t\tdata: PlayerEventData | PlayerErrorEventData = {}\n\t) => {\n\t\tPubSub.publish(message, { ...data, id: this.id });\n\n\t\tconst blacklistedFromConsoleLogs = [\n\t\t\t'video.player.content.progress',\n\t\t\t'video.player.inProgress'\n\t\t];\n\n\t\tif (blacklistedFromConsoleLogs.includes(message)) return;\n\t\tlogger.debug(`Publishing ${message}`)();\n\t};\n\n\tpublic logError = (message: string) =>\n\t\tthis.publish(PublishableVideoLogEvents.ERROR, {\n\t\t\tmessage,\n\t\t\tcategory: this.name\n\t\t});\n\n\tpublic cancelAdvertising = () =>\n\t\tthis.publish(PublishableVideoAdEvents.AD_CANCEL);\n\n\tpublic isPlaying = async () => {\n\t\tconst isPaused = await this.isPaused();\n\t\treturn !isPaused;\n\t};\n\n\tpublic getWidth = () => this.getContainer()?.getBoundingClientRect().width;\n\tpublic getHeight = () => this.getContainer()?.getBoundingClientRect().height;\n\n\t// -= Playback functions =-\n\tpublic async play() {\n\t\tif (await this.isPlaying()) return;\n\n\t\tconst successHandler = () => true;\n\t\tconst errorHandler = (error: Error) => {\n\t\t\tif (error) {\n\t\t\t\tthis.logError(error.message);\n\t\t\t}\n\n\t\t\treturn false;\n\t\t};\n\n\t\tlet play = (this.api as HTMLMediaElement).play();\n\n\t\treturn !(play && typeof play.then === 'function')\n\t\t\t? play\n\t\t\t: play.then(successHandler, errorHandler);\n\t}\n\n\tpublic pause() {\n\t\treturn this.api.pause();\n\t}\n\n\tprotected async onReady() {\n\t\tif (this.ready) return;\n\t\tthis.publish(PublishableVideoPlayerEvents.READY);\n\n\t\t// Send video complete event with completion rate when user closes the tab\n\t\tthis._aufAddEvent(\n\t\t\twindow,\n\t\t\t'beforeunload',\n\t\t\t() => this.publish(PublishableVideoPlayerEvents.END),\n\t\t\tfalse\n\t\t);\n\n\t\tif (this._readyCb && typeof this._readyCb === 'function') {\n\t\t\tawait this._readyCb();\n\t\t}\n\n\t\tthis.ready = true;\n\t\tthis.postReady();\n\t\treturn Promise.resolve();\n\t}\n\n\tprotected onPlay() {\n\t\tthis.prePlay();\n\n\t\tthis.videoStarted = true;\n\t\tthis.publish(PublishableVideoPlayerEvents.PLAY);\n\n\t\tthis.postPlay();\n\t}\n\n\tprotected initCommonListeners() {\n\t\tthis.api.on('ready', async () => await this.onReady());\n\t\tthis.api.on('play', this.onPlay.bind(this));\n\t\tthis.api.on('pause', this.onPause.bind(this));\n\t}\n\n\tprotected onPause = () => this.publish(PublishableVideoPlayerEvents.PAUSE);\n\n\tabstract isPaused(): boolean | Promise;\n\tabstract getContainer(): HTMLElement | Element | null;\n\n\tprotected abstract initApi(adsParams?: AdsParams): Promise;\n\tprotected abstract initListeners(): void;\n\tprotected abstract initApiListeners(): void;\n\tprotected abstract initErrorsListeners(): void;\n\tprotected abstract prePlay(): void;\n\tprotected abstract postPlay(): void;\n\tprotected abstract postReady(): void;\n\tprotected abstract disableAds(): void;\n}\n","var win;\n\nif (typeof window !== \"undefined\") {\n win = window;\n} else if (typeof global !== \"undefined\") {\n win = global;\n} else if (typeof self !== \"undefined\"){\n win = self;\n} else {\n win = {};\n}\n\nmodule.exports = win;\n","var slice = Array.prototype.slice\n\nmodule.exports = iterativelyWalk\n\nfunction iterativelyWalk(nodes, cb) {\n if (!('length' in nodes)) {\n nodes = [nodes]\n }\n \n nodes = slice.call(nodes)\n\n while(nodes.length) {\n var node = nodes.shift(),\n ret = cb(node)\n\n if (ret) {\n return ret\n }\n\n if (node.childNodes && node.childNodes.length) {\n nodes = slice.call(node.childNodes).concat(nodes)\n }\n }\n}\n","module.exports = Comment\n\nfunction Comment(data, owner) {\n if (!(this instanceof Comment)) {\n return new Comment(data, owner)\n }\n\n this.data = data\n this.nodeValue = data\n this.length = data.length\n this.ownerDocument = owner || null\n}\n\nComment.prototype.nodeType = 8\nComment.prototype.nodeName = \"#comment\"\n\nComment.prototype.toString = function _Comment_toString() {\n return \"[object Comment]\"\n}\n","module.exports = DOMText\n\nfunction DOMText(value, owner) {\n if (!(this instanceof DOMText)) {\n return new DOMText(value)\n }\n\n this.data = value || \"\"\n this.length = this.data.length\n this.ownerDocument = owner || null\n}\n\nDOMText.prototype.type = \"DOMTextNode\"\nDOMText.prototype.nodeType = 3\nDOMText.prototype.nodeName = \"#text\"\n\nDOMText.prototype.toString = function _Text_toString() {\n return this.data\n}\n\nDOMText.prototype.replaceData = function replaceData(index, length, value) {\n var current = this.data\n var left = current.substring(0, index)\n var right = current.substring(index + length, current.length)\n this.data = left + value + right\n this.length = this.data.length\n}\n","module.exports = dispatchEvent\n\nfunction dispatchEvent(ev) {\n var elem = this\n var type = ev.type\n\n if (!ev.target) {\n ev.target = elem\n }\n\n if (!elem.listeners) {\n elem.listeners = {}\n }\n\n var listeners = elem.listeners[type]\n\n if (listeners) {\n return listeners.forEach(function (listener) {\n ev.currentTarget = elem\n if (typeof listener === 'function') {\n listener(ev)\n } else {\n listener.handleEvent(ev)\n }\n })\n }\n\n if (elem.parentNode) {\n elem.parentNode.dispatchEvent(ev)\n }\n}\n","module.exports = addEventListener\n\nfunction addEventListener(type, listener) {\n var elem = this\n\n if (!elem.listeners) {\n elem.listeners = {}\n }\n\n if (!elem.listeners[type]) {\n elem.listeners[type] = []\n }\n\n if (elem.listeners[type].indexOf(listener) === -1) {\n elem.listeners[type].push(listener)\n }\n}\n","module.exports = removeEventListener\n\nfunction removeEventListener(type, listener) {\n var elem = this\n\n if (!elem.listeners) {\n return\n }\n\n if (!elem.listeners[type]) {\n return\n }\n\n var list = elem.listeners[type]\n var index = list.indexOf(listener)\n if (index !== -1) {\n list.splice(index, 1)\n }\n}\n","module.exports = serializeNode\n\nvar voidElements = [\"area\",\"base\",\"br\",\"col\",\"embed\",\"hr\",\"img\",\"input\",\"keygen\",\"link\",\"menuitem\",\"meta\",\"param\",\"source\",\"track\",\"wbr\"];\n\nfunction serializeNode(node) {\n switch (node.nodeType) {\n case 3:\n return escapeText(node.data)\n case 8:\n return \"\"\n default:\n return serializeElement(node)\n }\n}\n\nfunction serializeElement(elem) {\n var strings = []\n\n var tagname = elem.tagName\n\n if (elem.namespaceURI === \"http://www.w3.org/1999/xhtml\") {\n tagname = tagname.toLowerCase()\n }\n\n strings.push(\"<\" + tagname + properties(elem) + datasetify(elem))\n\n if (voidElements.indexOf(tagname) > -1) {\n strings.push(\" />\")\n } else {\n strings.push(\">\")\n\n if (elem.childNodes.length) {\n strings.push.apply(strings, elem.childNodes.map(serializeNode))\n } else if (elem.textContent || elem.innerText) {\n strings.push(escapeText(elem.textContent || elem.innerText))\n } else if (elem.innerHTML) {\n strings.push(elem.innerHTML)\n }\n\n strings.push(\"\")\n }\n\n return strings.join(\"\")\n}\n\nfunction isProperty(elem, key) {\n var type = typeof elem[key]\n\n if (key === \"style\" && Object.keys(elem.style).length > 0) {\n return true\n }\n\n return elem.hasOwnProperty(key) &&\n (type === \"string\" || type === \"boolean\" || type === \"number\") &&\n key !== \"nodeName\" && key !== \"className\" && key !== \"tagName\" &&\n key !== \"textContent\" && key !== \"innerText\" && key !== \"namespaceURI\" && key !== \"innerHTML\"\n}\n\nfunction stylify(styles) {\n if (typeof styles === 'string') return styles\n var attr = \"\"\n Object.keys(styles).forEach(function (key) {\n var value = styles[key]\n key = key.replace(/[A-Z]/g, function(c) {\n return \"-\" + c.toLowerCase();\n })\n attr += key + \":\" + value + \";\"\n })\n return attr\n}\n\nfunction datasetify(elem) {\n var ds = elem.dataset\n var props = []\n\n for (var key in ds) {\n props.push({ name: \"data-\" + key, value: ds[key] })\n }\n\n return props.length ? stringify(props) : \"\"\n}\n\nfunction stringify(list) {\n var attributes = []\n list.forEach(function (tuple) {\n var name = tuple.name\n var value = tuple.value\n\n if (name === \"style\") {\n value = stylify(value)\n }\n\n attributes.push(name + \"=\" + \"\\\"\" + escapeAttributeValue(value) + \"\\\"\")\n })\n\n return attributes.length ? \" \" + attributes.join(\" \") : \"\"\n}\n\nfunction properties(elem) {\n var props = []\n for (var key in elem) {\n if (isProperty(elem, key)) {\n props.push({ name: key, value: elem[key] })\n }\n }\n\n for (var ns in elem._attributes) {\n for (var attribute in elem._attributes[ns]) {\n var prop = elem._attributes[ns][attribute]\n var name = (prop.prefix ? prop.prefix + \":\" : \"\") + attribute\n props.push({ name: name, value: prop.value })\n }\n }\n\n if (elem.className) {\n props.push({ name: \"class\", value: elem.className })\n }\n\n return props.length ? stringify(props) : \"\"\n}\n\nfunction escapeText(s) {\n var str = '';\n\n if (typeof(s) === 'string') { \n str = s; \n } else if (s) {\n str = s.toString();\n }\n\n return str\n .replace(/&/g, \"&\")\n .replace(//g, \">\")\n}\n\nfunction escapeAttributeValue(str) {\n return escapeText(str).replace(/\"/g, \""\")\n}\n","var domWalk = require(\"dom-walk\")\nvar dispatchEvent = require(\"./event/dispatch-event.js\")\nvar addEventListener = require(\"./event/add-event-listener.js\")\nvar removeEventListener = require(\"./event/remove-event-listener.js\")\nvar serializeNode = require(\"./serialize.js\")\n\nvar htmlns = \"http://www.w3.org/1999/xhtml\"\n\nmodule.exports = DOMElement\n\nfunction DOMElement(tagName, owner, namespace) {\n if (!(this instanceof DOMElement)) {\n return new DOMElement(tagName)\n }\n\n var ns = namespace === undefined ? htmlns : (namespace || null)\n\n this.tagName = ns === htmlns ? String(tagName).toUpperCase() : tagName\n this.nodeName = this.tagName\n this.className = \"\"\n this.dataset = {}\n this.childNodes = []\n this.parentNode = null\n this.style = {}\n this.ownerDocument = owner || null\n this.namespaceURI = ns\n this._attributes = {}\n\n if (this.tagName === 'INPUT') {\n this.type = 'text'\n }\n}\n\nDOMElement.prototype.type = \"DOMElement\"\nDOMElement.prototype.nodeType = 1\n\nDOMElement.prototype.appendChild = function _Element_appendChild(child) {\n if (child.parentNode) {\n child.parentNode.removeChild(child)\n }\n\n this.childNodes.push(child)\n child.parentNode = this\n\n return child\n}\n\nDOMElement.prototype.replaceChild =\n function _Element_replaceChild(elem, needle) {\n // TODO: Throw NotFoundError if needle.parentNode !== this\n\n if (elem.parentNode) {\n elem.parentNode.removeChild(elem)\n }\n\n var index = this.childNodes.indexOf(needle)\n\n needle.parentNode = null\n this.childNodes[index] = elem\n elem.parentNode = this\n\n return needle\n }\n\nDOMElement.prototype.removeChild = function _Element_removeChild(elem) {\n // TODO: Throw NotFoundError if elem.parentNode !== this\n\n var index = this.childNodes.indexOf(elem)\n this.childNodes.splice(index, 1)\n\n elem.parentNode = null\n return elem\n}\n\nDOMElement.prototype.insertBefore =\n function _Element_insertBefore(elem, needle) {\n // TODO: Throw NotFoundError if referenceElement is a dom node\n // and parentNode !== this\n\n if (elem.parentNode) {\n elem.parentNode.removeChild(elem)\n }\n\n var index = needle === null || needle === undefined ?\n -1 :\n this.childNodes.indexOf(needle)\n\n if (index > -1) {\n this.childNodes.splice(index, 0, elem)\n } else {\n this.childNodes.push(elem)\n }\n\n elem.parentNode = this\n return elem\n }\n\nDOMElement.prototype.setAttributeNS =\n function _Element_setAttributeNS(namespace, name, value) {\n var prefix = null\n var localName = name\n var colonPosition = name.indexOf(\":\")\n if (colonPosition > -1) {\n prefix = name.substr(0, colonPosition)\n localName = name.substr(colonPosition + 1)\n }\n if (this.tagName === 'INPUT' && name === 'type') {\n this.type = value;\n }\n else {\n var attributes = this._attributes[namespace] || (this._attributes[namespace] = {})\n attributes[localName] = {value: value, prefix: prefix}\n }\n }\n\nDOMElement.prototype.getAttributeNS =\n function _Element_getAttributeNS(namespace, name) {\n var attributes = this._attributes[namespace];\n var value = attributes && attributes[name] && attributes[name].value\n if (this.tagName === 'INPUT' && name === 'type') {\n return this.type;\n }\n if (typeof value !== \"string\") {\n return null\n }\n return value\n }\n\nDOMElement.prototype.removeAttributeNS =\n function _Element_removeAttributeNS(namespace, name) {\n var attributes = this._attributes[namespace];\n if (attributes) {\n delete attributes[name]\n }\n }\n\nDOMElement.prototype.hasAttributeNS =\n function _Element_hasAttributeNS(namespace, name) {\n var attributes = this._attributes[namespace]\n return !!attributes && name in attributes;\n }\n\nDOMElement.prototype.setAttribute = function _Element_setAttribute(name, value) {\n return this.setAttributeNS(null, name, value)\n}\n\nDOMElement.prototype.getAttribute = function _Element_getAttribute(name) {\n return this.getAttributeNS(null, name)\n}\n\nDOMElement.prototype.removeAttribute = function _Element_removeAttribute(name) {\n return this.removeAttributeNS(null, name)\n}\n\nDOMElement.prototype.hasAttribute = function _Element_hasAttribute(name) {\n return this.hasAttributeNS(null, name)\n}\n\nDOMElement.prototype.removeEventListener = removeEventListener\nDOMElement.prototype.addEventListener = addEventListener\nDOMElement.prototype.dispatchEvent = dispatchEvent\n\n// Un-implemented\nDOMElement.prototype.focus = function _Element_focus() {\n return void 0\n}\n\nDOMElement.prototype.toString = function _Element_toString() {\n return serializeNode(this)\n}\n\nDOMElement.prototype.getElementsByClassName = function _Element_getElementsByClassName(classNames) {\n var classes = classNames.split(\" \");\n var elems = []\n\n domWalk(this, function (node) {\n if (node.nodeType === 1) {\n var nodeClassName = node.className || \"\"\n var nodeClasses = nodeClassName.split(\" \")\n\n if (classes.every(function (item) {\n return nodeClasses.indexOf(item) !== -1\n })) {\n elems.push(node)\n }\n }\n })\n\n return elems\n}\n\nDOMElement.prototype.getElementsByTagName = function _Element_getElementsByTagName(tagName) {\n tagName = tagName.toLowerCase()\n var elems = []\n\n domWalk(this.childNodes, function (node) {\n if (node.nodeType === 1 && (tagName === '*' || node.tagName.toLowerCase() === tagName)) {\n elems.push(node)\n }\n })\n\n return elems\n}\n\nDOMElement.prototype.contains = function _Element_contains(element) {\n return domWalk(this, function (node) {\n return element === node\n }) || false\n}\n","var DOMElement = require(\"./dom-element.js\")\n\nmodule.exports = DocumentFragment\n\nfunction DocumentFragment(owner) {\n if (!(this instanceof DocumentFragment)) {\n return new DocumentFragment()\n }\n\n this.childNodes = []\n this.parentNode = null\n this.ownerDocument = owner || null\n}\n\nDocumentFragment.prototype.type = \"DocumentFragment\"\nDocumentFragment.prototype.nodeType = 11\nDocumentFragment.prototype.nodeName = \"#document-fragment\"\n\nDocumentFragment.prototype.appendChild = DOMElement.prototype.appendChild\nDocumentFragment.prototype.replaceChild = DOMElement.prototype.replaceChild\nDocumentFragment.prototype.removeChild = DOMElement.prototype.removeChild\n\nDocumentFragment.prototype.toString =\n function _DocumentFragment_toString() {\n return this.childNodes.map(function (node) {\n return String(node)\n }).join(\"\")\n }\n","module.exports = Event\n\nfunction Event(family) {}\n\nEvent.prototype.initEvent = function _Event_initEvent(type, bubbles, cancelable) {\n this.type = type\n this.bubbles = bubbles\n this.cancelable = cancelable\n}\n\nEvent.prototype.preventDefault = function _Event_preventDefault() {\n \n}\n","var domWalk = require(\"dom-walk\")\n\nvar Comment = require(\"./dom-comment.js\")\nvar DOMText = require(\"./dom-text.js\")\nvar DOMElement = require(\"./dom-element.js\")\nvar DocumentFragment = require(\"./dom-fragment.js\")\nvar Event = require(\"./event.js\")\nvar dispatchEvent = require(\"./event/dispatch-event.js\")\nvar addEventListener = require(\"./event/add-event-listener.js\")\nvar removeEventListener = require(\"./event/remove-event-listener.js\")\n\nmodule.exports = Document;\n\nfunction Document() {\n if (!(this instanceof Document)) {\n return new Document();\n }\n\n this.head = this.createElement(\"head\")\n this.body = this.createElement(\"body\")\n this.documentElement = this.createElement(\"html\")\n this.documentElement.appendChild(this.head)\n this.documentElement.appendChild(this.body)\n this.childNodes = [this.documentElement]\n this.nodeType = 9\n}\n\nvar proto = Document.prototype;\nproto.createTextNode = function createTextNode(value) {\n return new DOMText(value, this)\n}\n\nproto.createElementNS = function createElementNS(namespace, tagName) {\n var ns = namespace === null ? null : String(namespace)\n return new DOMElement(tagName, this, ns)\n}\n\nproto.createElement = function createElement(tagName) {\n return new DOMElement(tagName, this)\n}\n\nproto.createDocumentFragment = function createDocumentFragment() {\n return new DocumentFragment(this)\n}\n\nproto.createEvent = function createEvent(family) {\n return new Event(family)\n}\n\nproto.createComment = function createComment(data) {\n return new Comment(data, this)\n}\n\nproto.getElementById = function getElementById(id) {\n id = String(id)\n\n var result = domWalk(this.childNodes, function (node) {\n if (String(node.id) === id) {\n return node\n }\n })\n\n return result || null\n}\n\nproto.getElementsByClassName = DOMElement.prototype.getElementsByClassName\nproto.getElementsByTagName = DOMElement.prototype.getElementsByTagName\nproto.contains = DOMElement.prototype.contains\n\nproto.removeEventListener = removeEventListener\nproto.addEventListener = addEventListener\nproto.dispatchEvent = dispatchEvent\n","var Document = require('./document.js');\n\nmodule.exports = new Document();\n","var topLevel = typeof global !== 'undefined' ? global :\n typeof window !== 'undefined' ? window : {}\nvar minDoc = require('min-document');\n\nvar doccy;\n\nif (typeof document !== 'undefined') {\n doccy = document;\n} else {\n doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];\n\n if (!doccy) {\n doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;\n }\n}\n\nmodule.exports = doccy;\n","function _extends() {\n module.exports = _extends = Object.assign || function (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n\n for (var key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n\n return target;\n }, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;\n return _extends.apply(this, arguments);\n}\n\nmodule.exports = _extends, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","// Source: http://jsfiddle.net/vWx8V/\n// http://stackoverflow.com/questions/5603195/full-list-of-javascript-keycodes\n\n/**\n * Conenience method returns corresponding value for given keyName or keyCode.\n *\n * @param {Mixed} keyCode {Number} or keyName {String}\n * @return {Mixed}\n * @api public\n */\n\nfunction keyCode(searchInput) {\n // Keyboard Events\n if (searchInput && 'object' === typeof searchInput) {\n var hasKeyCode = searchInput.which || searchInput.keyCode || searchInput.charCode\n if (hasKeyCode) searchInput = hasKeyCode\n }\n\n // Numbers\n if ('number' === typeof searchInput) return names[searchInput]\n\n // Everything else (cast to string)\n var search = String(searchInput)\n\n // check codes\n var foundNamedKey = codes[search.toLowerCase()]\n if (foundNamedKey) return foundNamedKey\n\n // check aliases\n var foundNamedKey = aliases[search.toLowerCase()]\n if (foundNamedKey) return foundNamedKey\n\n // weird character?\n if (search.length === 1) return search.charCodeAt(0)\n\n return undefined\n}\n\n/**\n * Compares a keyboard event with a given keyCode or keyName.\n *\n * @param {Event} event Keyboard event that should be tested\n * @param {Mixed} keyCode {Number} or keyName {String}\n * @return {Boolean}\n * @api public\n */\nkeyCode.isEventKey = function isEventKey(event, nameOrCode) {\n if (event && 'object' === typeof event) {\n var keyCode = event.which || event.keyCode || event.charCode\n if (keyCode === null || keyCode === undefined) { return false; }\n if (typeof nameOrCode === 'string') {\n // check codes\n var foundNamedKey = codes[nameOrCode.toLowerCase()]\n if (foundNamedKey) { return foundNamedKey === keyCode; }\n \n // check aliases\n var foundNamedKey = aliases[nameOrCode.toLowerCase()]\n if (foundNamedKey) { return foundNamedKey === keyCode; }\n } else if (typeof nameOrCode === 'number') {\n return nameOrCode === keyCode;\n }\n return false;\n }\n}\n\nexports = module.exports = keyCode;\n\n/**\n * Get by name\n *\n * exports.code['enter'] // => 13\n */\n\nvar codes = exports.code = exports.codes = {\n 'backspace': 8,\n 'tab': 9,\n 'enter': 13,\n 'shift': 16,\n 'ctrl': 17,\n 'alt': 18,\n 'pause/break': 19,\n 'caps lock': 20,\n 'esc': 27,\n 'space': 32,\n 'page up': 33,\n 'page down': 34,\n 'end': 35,\n 'home': 36,\n 'left': 37,\n 'up': 38,\n 'right': 39,\n 'down': 40,\n 'insert': 45,\n 'delete': 46,\n 'command': 91,\n 'left command': 91,\n 'right command': 93,\n 'numpad *': 106,\n 'numpad +': 107,\n 'numpad -': 109,\n 'numpad .': 110,\n 'numpad /': 111,\n 'num lock': 144,\n 'scroll lock': 145,\n 'my computer': 182,\n 'my calculator': 183,\n ';': 186,\n '=': 187,\n ',': 188,\n '-': 189,\n '.': 190,\n '/': 191,\n '`': 192,\n '[': 219,\n '\\\\': 220,\n ']': 221,\n \"'\": 222\n}\n\n// Helper aliases\n\nvar aliases = exports.aliases = {\n 'windows': 91,\n '⇧': 16,\n '⌥': 18,\n '⌃': 17,\n '⌘': 91,\n 'ctl': 17,\n 'control': 17,\n 'option': 18,\n 'pause': 19,\n 'break': 19,\n 'caps': 20,\n 'return': 13,\n 'escape': 27,\n 'spc': 32,\n 'spacebar': 32,\n 'pgup': 33,\n 'pgdn': 34,\n 'ins': 45,\n 'del': 46,\n 'cmd': 91\n}\n\n/*!\n * Programatically add the following\n */\n\n// lower case chars\nfor (i = 97; i < 123; i++) codes[String.fromCharCode(i)] = i - 32\n\n// numbers\nfor (var i = 48; i < 58; i++) codes[i - 48] = i\n\n// function keys\nfor (i = 1; i < 13; i++) codes['f'+i] = i + 111\n\n// numpad keys\nfor (i = 0; i < 10; i++) codes['numpad '+i] = i + 96\n\n/**\n * Get by code\n *\n * exports.name[13] // => 'Enter'\n */\n\nvar names = exports.names = exports.title = {} // title for backward compat\n\n// Create reverse mapping\nfor (i in codes) names[codes[i]] = i\n\n// Add aliases\nfor (var alias in aliases) {\n codes[alias] = aliases[alias]\n}\n","function _assertThisInitialized(self) {\n if (self === void 0) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return self;\n}\n\nmodule.exports = _assertThisInitialized, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","function _setPrototypeOf(o, p) {\n module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {\n o.__proto__ = p;\n return o;\n }, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;\n return _setPrototypeOf(o, p);\n}\n\nmodule.exports = _setPrototypeOf, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var setPrototypeOf = require(\"./setPrototypeOf.js\");\n\nfunction _inheritsLoose(subClass, superClass) {\n subClass.prototype = Object.create(superClass.prototype);\n subClass.prototype.constructor = subClass;\n setPrototypeOf(subClass, superClass);\n}\n\nmodule.exports = _inheritsLoose, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","module.exports = SafeParseTuple\n\nfunction SafeParseTuple(obj, reviver) {\n var json\n var error = null\n\n try {\n json = JSON.parse(obj, reviver)\n } catch (err) {\n error = err\n }\n\n return [error, json]\n}\n","module.exports = isFunction\n\nvar toString = Object.prototype.toString\n\nfunction isFunction (fn) {\n if (!fn) {\n return false\n }\n var string = toString.call(fn)\n return string === '[object Function]' ||\n (typeof fn === 'function' && string !== '[object RegExp]') ||\n (typeof window !== 'undefined' &&\n // IE8 and below\n (fn === window.setTimeout ||\n fn === window.alert ||\n fn === window.confirm ||\n fn === window.prompt))\n};\n","\"use strict\";\n\nvar window = require('global/window');\n\nvar httpResponseHandler = function httpResponseHandler(callback, decodeResponseBody) {\n if (decodeResponseBody === void 0) {\n decodeResponseBody = false;\n }\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\n if (response.statusCode >= 400 && response.statusCode <= 599) {\n var cause = responseBody;\n\n if (decodeResponseBody) {\n if (window.TextDecoder) {\n var charset = getCharset(response.headers && response.headers['content-type']);\n\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\n callback({\n cause: cause\n });\n return;\n } // otherwise, request succeeded\n\n\n callback(null, responseBody);\n };\n};\n\nfunction getCharset(contentTypeHeader) {\n if (contentTypeHeader === void 0) {\n contentTypeHeader = '';\n }\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\n if (type.trim() === 'charset') {\n return value.trim();\n }\n\n return charset;\n }, 'utf-8');\n}\n\nmodule.exports = httpResponseHandler;","\"use strict\";\n\nvar window = require(\"global/window\");\n\nvar _extends = require(\"@babel/runtime/helpers/extends\");\n\nvar isFunction = require('is-function');\n\ncreateXHR.httpHandler = require('./http-handler.js');\n/**\n * @license\n * slighly modified parse-headers 2.0.2 \n * Copyright (c) 2014 David Björklund\n * Available under the MIT license\n * \n */\n\nvar parseHeaders = function parseHeaders(headers) {\n var result = {};\n\n if (!headers) {\n return result;\n }\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\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\nmodule.exports = createXHR; // Allow use of default import syntax in TypeScript\n\nmodule.exports.default = createXHR;\ncreateXHR.XMLHttpRequest = window.XMLHttpRequest || noop;\ncreateXHR.XDomainRequest = \"withCredentials\" in new createXHR.XMLHttpRequest() ? createXHR.XMLHttpRequest : window.XDomainRequest;\nforEachArray([\"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\nfunction forEachArray(array, iterator) {\n for (var i = 0; i < array.length; i++) {\n iterator(array[i]);\n }\n}\n\nfunction isEmpty(obj) {\n for (var i in obj) {\n if (obj.hasOwnProperty(i)) return false;\n }\n\n return true;\n}\n\nfunction initParams(uri, options, callback) {\n var params = uri;\n\n if (isFunction(options)) {\n callback = options;\n\n if (typeof uri === \"string\") {\n params = {\n uri: uri\n };\n }\n } else {\n params = _extends({}, options, {\n uri: uri\n });\n }\n\n params.callback = callback;\n return params;\n}\n\nfunction createXHR(uri, options, callback) {\n options = initParams(uri, options, callback);\n return _createXHR(options);\n}\n\nfunction _createXHR(options) {\n if (typeof options.callback === \"undefined\") {\n throw new Error(\"callback argument missing\");\n }\n\n var called = false;\n\n var callback = function cbOnce(err, response, body) {\n if (!called) {\n called = true;\n options.callback(err, response, body);\n }\n };\n\n function readystatechange() {\n if (xhr.readyState === 4) {\n setTimeout(loadFunc, 0);\n }\n }\n\n function getBody() {\n // Chrome with requestType=blob throws errors arround when even testing access to responseText\n var body = undefined;\n\n if (xhr.response) {\n body = xhr.response;\n } else {\n body = xhr.responseText || getXml(xhr);\n }\n\n if (isJson) {\n try {\n body = JSON.parse(body);\n } catch (e) {}\n }\n\n return body;\n }\n\n function errorFunc(evt) {\n clearTimeout(timeoutTimer);\n\n if (!(evt instanceof Error)) {\n evt = new Error(\"\" + (evt || \"Unknown XMLHttpRequest Error\"));\n }\n\n evt.statusCode = 0;\n return callback(evt, failureResponse);\n } // will load the data & process the response in a special response object\n\n\n function loadFunc() {\n if (aborted) return;\n var status;\n clearTimeout(timeoutTimer);\n\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\n var response = failureResponse;\n var err = null;\n\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\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 }\n\n return callback(err, response, response.body);\n }\n\n var xhr = options.xhr || null;\n\n if (!xhr) {\n if (options.cors || options.useXDR) {\n xhr = new createXHR.XDomainRequest();\n } else {\n xhr = new createXHR.XMLHttpRequest();\n }\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\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\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\n xhr.onabort = function () {\n aborted = true;\n };\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\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\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\n if (\"responseType\" in options) {\n xhr.responseType = options.responseType;\n }\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\n xhr.send(body || null);\n return xhr;\n}\n\nfunction 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\n var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === \"parsererror\";\n\n if (xhr.responseType === \"\" && !firefoxBugTakenEffect) {\n return xhr.responseXML;\n }\n } catch (e) {}\n\n return null;\n}\n\nfunction noop() {}","/**\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: */\nvar document = require('global/document');\n\nvar _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.\nfunction ParsingError(errorData, message) {\n this.name = \"ParsingError\";\n this.code = errorData.code;\n this.message = message || errorData.message;\n}\nParsingError.prototype = _objCreate(Error.prototype);\nParsingError.prototype.constructor = ParsingError;\n\n// ParsingError metadata for acceptable ParsingErrors.\nParsingError.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.\nfunction parseTimeStamp(input) {\n\n function computeSeconds(h, m, s, f) {\n return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000;\n }\n\n var m = input.match(/^(\\d+):(\\d{1,2})(:\\d{1,2})?\\.(\\d{3})/);\n if (!m) {\n return null;\n }\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.\nfunction Settings() {\n this.values = _objCreate(null);\n}\n\nSettings.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)) { // 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 var m;\n if ((m = 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'.\nfunction 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];\n var v = kv[1];\n callback(k, v);\n }\n}\n\nfunction 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,\n \"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\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\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\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) !== \"-->\") { // (3) next characters must match \"-->\"\n throw new ParsingError(ParsingError.Errors.BadTimeStamp,\n \"Malformed time stamp (time stamps must be separated by '-->'): \" +\n 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.\nvar TEXTAREA_ELEMENT = document.createElement && document.createElement(\"textarea\");\n\nvar 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\nvar 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\nvar TAG_ANNOTATION = {\n v: \"title\",\n lang: \"lang\"\n};\n\nvar NEEDS_PARENT = {\n rt: \"ruby\"\n};\n\n// Parse content into a document fragment.\nfunction 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\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\n function unescape(s) {\n TEXTAREA_ELEMENT.innerHTML = s;\n s = TEXTAREA_ELEMENT.textContent;\n TEXTAREA_ELEMENT.textContent = \"\";\n return s;\n }\n\n function shouldAdd(current, element) {\n return !NEEDS_PARENT[element.localName] ||\n 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\n var rootDiv = window.document.createElement(\"div\"),\n current = rootDiv,\n t,\n tagStack = [];\n\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 &&\n 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\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\n if (DEFAULT_COLOR_CLASS.hasOwnProperty(colorName)) {\n var propName = bgColor ? 'background-color' : 'color';\n var propValue = DEFAULT_COLOR_CLASS[colorName];\n\n node.style[propName] = propValue;\n }\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\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\nvar strongRTLRanges = [[0x5be, 0x5be], [0x5c0, 0x5c0], [0x5c3, 0x5c3], [0x5c6, 0x5c6],\n [0x5d0, 0x5ea], [0x5f0, 0x5f4], [0x608, 0x608], [0x60b, 0x60b], [0x60d, 0x60d],\n [0x61b, 0x61b], [0x61e, 0x64a], [0x66d, 0x66f], [0x671, 0x6d5], [0x6e5, 0x6e6],\n [0x6ee, 0x6ef], [0x6fa, 0x70d], [0x70f, 0x710], [0x712, 0x72f], [0x74d, 0x7a5],\n [0x7b1, 0x7b1], [0x7c0, 0x7ea], [0x7f4, 0x7f5], [0x7fa, 0x7fa], [0x800, 0x815],\n [0x81a, 0x81a], [0x824, 0x824], [0x828, 0x828], [0x830, 0x83e], [0x840, 0x858],\n [0x85e, 0x85e], [0x8a0, 0x8a0], [0x8a2, 0x8ac], [0x200f, 0x200f],\n [0xfb1d, 0xfb1d], [0xfb1f, 0xfb28], [0xfb2a, 0xfb36], [0xfb38, 0xfb3c],\n [0xfb3e, 0xfb3e], [0xfb40, 0xfb41], [0xfb43, 0xfb44], [0xfb46, 0xfbc1],\n [0xfbd3, 0xfd3d], [0xfd50, 0xfd8f], [0xfd92, 0xfdc7], [0xfdf0, 0xfdfc],\n [0xfe70, 0xfe74], [0xfe76, 0xfefc], [0x10800, 0x10805], [0x10808, 0x10808],\n [0x1080a, 0x10835], [0x10837, 0x10838], [0x1083c, 0x1083c], [0x1083f, 0x10855],\n [0x10857, 0x1085f], [0x10900, 0x1091b], [0x10920, 0x10939], [0x1093f, 0x1093f],\n [0x10980, 0x109b7], [0x109be, 0x109bf], [0x10a00, 0x10a00], [0x10a10, 0x10a13],\n [0x10a15, 0x10a17], [0x10a19, 0x10a33], [0x10a40, 0x10a47], [0x10a50, 0x10a58],\n [0x10a60, 0x10a7f], [0x10b00, 0x10b35], [0x10b40, 0x10b55], [0x10b58, 0x10b72],\n [0x10b78, 0x10b7f], [0x10c00, 0x10c48], [0x1ee00, 0x1ee03], [0x1ee05, 0x1ee1f],\n [0x1ee21, 0x1ee22], [0x1ee24, 0x1ee24], [0x1ee27, 0x1ee27], [0x1ee29, 0x1ee32],\n [0x1ee34, 0x1ee37], [0x1ee39, 0x1ee39], [0x1ee3b, 0x1ee3b], [0x1ee42, 0x1ee42],\n [0x1ee47, 0x1ee47], [0x1ee49, 0x1ee49], [0x1ee4b, 0x1ee4b], [0x1ee4d, 0x1ee4f],\n [0x1ee51, 0x1ee52], [0x1ee54, 0x1ee54], [0x1ee57, 0x1ee57], [0x1ee59, 0x1ee59],\n [0x1ee5b, 0x1ee5b], [0x1ee5d, 0x1ee5d], [0x1ee5f, 0x1ee5f], [0x1ee61, 0x1ee62],\n [0x1ee64, 0x1ee64], [0x1ee67, 0x1ee6a], [0x1ee6c, 0x1ee72], [0x1ee74, 0x1ee77],\n [0x1ee79, 0x1ee7c], [0x1ee7e, 0x1ee7e], [0x1ee80, 0x1ee89], [0x1ee8b, 0x1ee9b],\n [0x1eea1, 0x1eea3], [0x1eea5, 0x1eea9], [0x1eeab, 0x1eebb], [0x10fffd, 0x10fffd]];\n\nfunction 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\n return false;\n}\n\nfunction determineBidi(cueDiv) {\n var nodeStack = [],\n text = \"\",\n charCode;\n\n if (!cueDiv || !cueDiv.childNodes) {\n return \"ltr\";\n }\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\n function nextTextNode(nodeStack) {\n if (!nodeStack || !nodeStack.length) {\n return null;\n }\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\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\nfunction computeLinePos(cue) {\n if (typeof cue.line === \"number\" &&\n (cue.snapToLines || (cue.line >= 0 && cue.line <= 100))) {\n return cue.line;\n }\n if (!cue.track || !cue.track.textTrackList ||\n !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\nfunction StyleBox() {\n}\n\n// Apply styles to a div. If there is no div passed then it defaults to the\n// div on 'this'.\nStyleBox.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\nStyleBox.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).\nfunction 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\"\n : cue.vertical === \"lr\" ? \"vertical-lr\"\n : \"vertical-rl\",\n unicodeBidi: \"plaintext\"\n };\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\"\n : cue.vertical === \"lr\" ? \"vertical-lr\"\n : \"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\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 textPos = cue.position;\n break;\n case \"center\":\n textPos = cue.position - (cue.size / 2);\n break;\n case \"end\":\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\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}\nCueStyleBox.prototype = _objCreate(StyleBox.prototype);\nCueStyleBox.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.\nfunction 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\n var rects = (rects = obj.div.childNodes) && (rects = rects[0]) &&\n 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)\n : 0;\n\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.\nBoxPosition.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.\nBoxPosition.prototype.overlaps = function(b2) {\n return this.left < b2.right &&\n this.right > b2.left &&\n this.top < b2.bottom &&\n this.bottom > b2.top;\n};\n\n// Check if this box overlaps any other boxes in boxes.\nBoxPosition.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.\nBoxPosition.prototype.within = function(container) {\n return this.top >= container.top &&\n this.bottom <= container.bottom &&\n this.left >= container.left &&\n 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.\nBoxPosition.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.\nBoxPosition.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.\nBoxPosition.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.\nBoxPosition.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\n obj = obj.div ? obj.div.getBoundingClientRect() :\n 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.\nfunction moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) {\n\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]) ||\n (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\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\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\n } else {\n // If we have a percentage line value for the cue.\n var calculatedPercentage = (boxPosition.lineHeight / containerBox.height) * 100;\n\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\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\n var bestPosition = findBestPosition(boxPosition, axis);\n styleBox.move(bestPosition.toCSSCompatValues(containerBox));\n}\n\nfunction WebVTT() {\n // Nothing\n}\n\n// Helper to allow strings to be decoded instead of the default binary utf8 data.\nWebVTT.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\nWebVTT.convertCueToDOMTree = function(window, cuetext) {\n if (!window || !cuetext) {\n return null;\n }\n return parseContent(window, cuetext);\n};\n\nvar FONT_SIZE_PERCENT = 0.05;\nvar FONT_STYLE = \"sans-serif\";\nvar 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.\nWebVTT.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\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\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\n (function() {\n var styleBox, cue;\n\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\n boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox));\n }\n })();\n};\n\nWebVTT.Parser = function(window, vttjs, decoder) {\n if (!decoder) {\n decoder = vttjs;\n vttjs = {};\n }\n if (!vttjs) {\n vttjs = {};\n }\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\nWebVTT.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, {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\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\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\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\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\n line = collectNextLine();\n\n var m = line.match(/^WEBVTT([ \\t].*)?$/);\n if (!m || !m[0]) {\n throw new ParsingError(ParsingError.Errors.BadSignature);\n }\n\n self.state = \"HEADER\";\n }\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\n if (!alreadyCollectedLine) {\n line = collectNextLine();\n } else {\n alreadyCollectedLine = false;\n }\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\": // 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\nmodule.exports = WebVTT;\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\nvar autoKeyword = \"auto\";\nvar directionSetting = {\n \"\": 1,\n \"lr\": 1,\n \"rl\": 1\n};\nvar 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\nfunction 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\nfunction 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\nfunction 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\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\n \"pauseOnExit\": {\n enumerable: true,\n get: function() {\n return _pauseOnExit;\n },\n set: function(value) {\n _pauseOnExit = !!value;\n }\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\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\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\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\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\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\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\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\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\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\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\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 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\nVTTCue.prototype.getCueAsHTML = function() {\n // Assume WebVTT.convertCueToDOMTree is on the global.\n return WebVTT.convertCueToDOMTree(window, this.text);\n};\n\nmodule.exports = VTTCue;\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\nvar scrollSetting = {\n \"\": true,\n \"up\": true\n};\n\nfunction 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\nfunction isValidPercentValue(value) {\n return typeof value === \"number\" && (value >= 0 && value <= 100);\n}\n\n// VTTRegion shim http://dev.w3.org/html5/webvtt/#vttregion-interface\nfunction 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\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\nmodule.exports = VTTRegion;\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\nvar window = require('global/window');\n\nvar vttjs = module.exports = {\n WebVTT: require(\"./vtt.js\"),\n VTTCue: require(\"./vttcue.js\"),\n VTTRegion: require(\"./vttregion.js\")\n};\n\nwindow.vttjs = vttjs;\nwindow.WebVTT = vttjs.WebVTT;\n\nvar cueShim = vttjs.VTTCue;\nvar regionShim = vttjs.VTTRegion;\nvar nativeVTTCue = window.VTTCue;\nvar nativeVTTRegion = window.VTTRegion;\n\nvttjs.shim = function() {\n window.VTTCue = cueShim;\n window.VTTRegion = regionShim;\n};\n\nvttjs.restore = function() {\n window.VTTCue = nativeVTTCue;\n window.VTTRegion = nativeVTTRegion;\n};\n\nif (!window.VTTCue) {\n vttjs.shim();\n}\n","function _isNativeReflectConstruct() {\n if (typeof Reflect === \"undefined\" || !Reflect.construct) return false;\n if (Reflect.construct.sham) return false;\n if (typeof Proxy === \"function\") return true;\n\n try {\n Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));\n return true;\n } catch (e) {\n return false;\n }\n}\n\nmodule.exports = _isNativeReflectConstruct, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var setPrototypeOf = require(\"./setPrototypeOf.js\");\n\nvar isNativeReflectConstruct = require(\"./isNativeReflectConstruct.js\");\n\nfunction _construct(Parent, args, Class) {\n if (isNativeReflectConstruct()) {\n module.exports = _construct = Reflect.construct, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;\n } else {\n module.exports = _construct = function _construct(Parent, args, Class) {\n var a = [null];\n a.push.apply(a, args);\n var Constructor = Function.bind.apply(Parent, a);\n var instance = new Constructor();\n if (Class) setPrototypeOf(instance, Class.prototype);\n return instance;\n }, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;\n }\n\n return _construct.apply(null, arguments);\n}\n\nmodule.exports = _construct, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var setPrototypeOf = require(\"./setPrototypeOf.js\");\n\nfunction _inherits(subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function\");\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n writable: true,\n configurable: true\n }\n });\n Object.defineProperty(subClass, \"prototype\", {\n writable: false\n });\n if (superClass) setPrototypeOf(subClass, superClass);\n}\n\nmodule.exports = _inherits, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","// see https://tools.ietf.org/html/rfc1808\n\n(function (root) {\n var URL_REGEX =\n /^(?=((?:[a-zA-Z0-9+\\-.]+:)?))\\1(?=((?:\\/\\/[^\\/?#]*)?))\\2(?=((?:(?:[^?#\\/]*\\/)*[^;?#\\/]*)?))\\3((?:;[^?#]*)?)(\\?[^#]*)?(#[^]*)?$/;\n var FIRST_SEGMENT_REGEX = /^(?=([^\\/?#]*))\\1([^]*)$/;\n var SLASH_DOT_REGEX = /(?:\\/|^)\\.(?=\\/)/g;\n var SLASH_DOT_DOT_REGEX = /(?:\\/|^)\\.\\.\\/(?!\\.\\.\\/)[^\\/]*(?=\\/)/g;\n\n var URLToolkit = {\n // If opts.alwaysNormalize is true then the path will always be normalized even when it starts with / or //\n // E.g\n // With opts.alwaysNormalize = false (default, spec compliant)\n // http://a.com/b/cd + /e/f/../g => http://a.com/e/f/../g\n // With opts.alwaysNormalize = true (not spec compliant)\n // http://a.com/b/cd + /e/f/../g => http://a.com/e/g\n buildAbsoluteURL: function (baseURL, relativeURL, opts) {\n opts = opts || {};\n // remove any remaining space and CRLF\n baseURL = baseURL.trim();\n relativeURL = relativeURL.trim();\n if (!relativeURL) {\n // 2a) If the embedded URL is entirely empty, it inherits the\n // entire base URL (i.e., is set equal to the base URL)\n // and we are done.\n if (!opts.alwaysNormalize) {\n return baseURL;\n }\n var basePartsForNormalise = URLToolkit.parseURL(baseURL);\n if (!basePartsForNormalise) {\n throw new Error('Error trying to parse base URL.');\n }\n basePartsForNormalise.path = URLToolkit.normalizePath(\n basePartsForNormalise.path\n );\n return URLToolkit.buildURLFromParts(basePartsForNormalise);\n }\n var relativeParts = URLToolkit.parseURL(relativeURL);\n if (!relativeParts) {\n throw new Error('Error trying to parse relative URL.');\n }\n if (relativeParts.scheme) {\n // 2b) If the embedded URL starts with a scheme name, it is\n // interpreted as an absolute URL and we are done.\n if (!opts.alwaysNormalize) {\n return relativeURL;\n }\n relativeParts.path = URLToolkit.normalizePath(relativeParts.path);\n return URLToolkit.buildURLFromParts(relativeParts);\n }\n var baseParts = URLToolkit.parseURL(baseURL);\n if (!baseParts) {\n throw new Error('Error trying to parse base URL.');\n }\n if (!baseParts.netLoc && baseParts.path && baseParts.path[0] !== '/') {\n // If netLoc missing and path doesn't start with '/', assume everthing before the first '/' is the netLoc\n // This causes 'example.com/a' to be handled as '//example.com/a' instead of '/example.com/a'\n var pathParts = FIRST_SEGMENT_REGEX.exec(baseParts.path);\n baseParts.netLoc = pathParts[1];\n baseParts.path = pathParts[2];\n }\n if (baseParts.netLoc && !baseParts.path) {\n baseParts.path = '/';\n }\n var builtParts = {\n // 2c) Otherwise, the embedded URL inherits the scheme of\n // the base URL.\n scheme: baseParts.scheme,\n netLoc: relativeParts.netLoc,\n path: null,\n params: relativeParts.params,\n query: relativeParts.query,\n fragment: relativeParts.fragment,\n };\n if (!relativeParts.netLoc) {\n // 3) If the embedded URL's is non-empty, we skip to\n // Step 7. Otherwise, the embedded URL inherits the \n // (if any) of the base URL.\n builtParts.netLoc = baseParts.netLoc;\n // 4) If the embedded URL path is preceded by a slash \"/\", the\n // path is not relative and we skip to Step 7.\n if (relativeParts.path[0] !== '/') {\n if (!relativeParts.path) {\n // 5) If the embedded URL path is empty (and not preceded by a\n // slash), then the embedded URL inherits the base URL path\n builtParts.path = baseParts.path;\n // 5a) if the embedded URL's is non-empty, we skip to\n // step 7; otherwise, it inherits the of the base\n // URL (if any) and\n if (!relativeParts.params) {\n builtParts.params = baseParts.params;\n // 5b) if the embedded URL's is non-empty, we skip to\n // step 7; otherwise, it inherits the of the base\n // URL (if any) and we skip to step 7.\n if (!relativeParts.query) {\n builtParts.query = baseParts.query;\n }\n }\n } else {\n // 6) The last segment of the base URL's path (anything\n // following the rightmost slash \"/\", or the entire path if no\n // slash is present) is removed and the embedded URL's path is\n // appended in its place.\n var baseURLPath = baseParts.path;\n var newPath =\n baseURLPath.substring(0, baseURLPath.lastIndexOf('/') + 1) +\n relativeParts.path;\n builtParts.path = URLToolkit.normalizePath(newPath);\n }\n }\n }\n if (builtParts.path === null) {\n builtParts.path = opts.alwaysNormalize\n ? URLToolkit.normalizePath(relativeParts.path)\n : relativeParts.path;\n }\n return URLToolkit.buildURLFromParts(builtParts);\n },\n parseURL: function (url) {\n var parts = URL_REGEX.exec(url);\n if (!parts) {\n return null;\n }\n return {\n scheme: parts[1] || '',\n netLoc: parts[2] || '',\n path: parts[3] || '',\n params: parts[4] || '',\n query: parts[5] || '',\n fragment: parts[6] || '',\n };\n },\n normalizePath: function (path) {\n // The following operations are\n // then applied, in order, to the new path:\n // 6a) All occurrences of \"./\", where \".\" is a complete path\n // segment, are removed.\n // 6b) If the path ends with \".\" as a complete path segment,\n // that \".\" is removed.\n path = path.split('').reverse().join('').replace(SLASH_DOT_REGEX, '');\n // 6c) All occurrences of \"/../\", where is a\n // complete path segment not equal to \"..\", are removed.\n // Removal of these path segments is performed iteratively,\n // removing the leftmost matching pattern on each iteration,\n // until no matching pattern remains.\n // 6d) If the path ends with \"/..\", where is a\n // complete path segment not equal to \"..\", that\n // \"/..\" is removed.\n while (\n path.length !== (path = path.replace(SLASH_DOT_DOT_REGEX, '')).length\n ) {}\n return path.split('').reverse().join('');\n },\n buildURLFromParts: function (parts) {\n return (\n parts.scheme +\n parts.netLoc +\n parts.path +\n parts.params +\n parts.query +\n parts.fragment\n );\n },\n };\n\n if (typeof exports === 'object' && typeof module === 'object')\n module.exports = URLToolkit;\n else if (typeof define === 'function' && define.amd)\n define([], function () {\n return URLToolkit;\n });\n else if (typeof exports === 'object') exports['URLToolkit'] = URLToolkit;\n else root['URLToolkit'] = URLToolkit;\n})(this);\n","import URLToolkit from 'url-toolkit';\nimport window from 'global/window';\nvar DEFAULT_LOCATION = 'http://example.com';\n\nvar resolveUrl = function resolveUrl(baseUrl, relativeUrl) {\n // return early if we don't need to resolve\n if (/^[a-z]+:/i.test(relativeUrl)) {\n return relativeUrl;\n } // if baseUrl is a data URI, ignore it and resolve everything relative to window.location\n\n\n if (/^data:/.test(baseUrl)) {\n baseUrl = window.location && window.location.href || '';\n } // IE11 supports URL but not the URL constructor\n // feature detect the behavior we want\n\n\n var nativeURL = typeof window.URL === 'function';\n var protocolLess = /^\\/\\//.test(baseUrl); // remove location if window.location isn't available (i.e. we're in node)\n // and if baseUrl isn't an absolute url\n\n var removeLocation = !window.location && !/\\/\\//i.test(baseUrl); // if the base URL is relative then combine with the current location\n\n if (nativeURL) {\n baseUrl = new window.URL(baseUrl, window.location || DEFAULT_LOCATION);\n } else if (!/\\/\\//i.test(baseUrl)) {\n baseUrl = URLToolkit.buildAbsoluteURL(window.location && window.location.href || '', baseUrl);\n }\n\n if (nativeURL) {\n var newUrl = new URL(relativeUrl, baseUrl); // if we're a protocol-less url, remove the protocol\n // and if we're location-less, remove the location\n // otherwise, return the url unmodified\n\n if (removeLocation) {\n return newUrl.href.slice(DEFAULT_LOCATION.length);\n } else if (protocolLess) {\n return newUrl.href.slice(newUrl.protocol.length);\n }\n\n return newUrl.href;\n }\n\n return URLToolkit.buildAbsoluteURL(baseUrl, relativeUrl);\n};\n\nexport default resolveUrl;","/**\n * @file stream.js\n */\n\n/**\n * A lightweight readable stream implemention that handles event dispatching.\n *\n * @class Stream\n */\nvar Stream = /*#__PURE__*/function () {\n function Stream() {\n this.listeners = {};\n }\n /**\n * Add a listener for a specified event type.\n *\n * @param {string} type the event name\n * @param {Function} listener the callback to be invoked when an event of\n * the specified type occurs\n */\n\n\n var _proto = Stream.prototype;\n\n _proto.on = function on(type, listener) {\n if (!this.listeners[type]) {\n this.listeners[type] = [];\n }\n\n this.listeners[type].push(listener);\n }\n /**\n * Remove a listener for a specified event type.\n *\n * @param {string} type the event name\n * @param {Function} listener a function previously registered for this\n * type of event through `on`\n * @return {boolean} if we could turn it off or not\n */\n ;\n\n _proto.off = function off(type, listener) {\n if (!this.listeners[type]) {\n return false;\n }\n\n var index = this.listeners[type].indexOf(listener); // TODO: which is better?\n // In Video.js we slice listener functions\n // on trigger so that it does not mess up the order\n // while we loop through.\n //\n // Here we slice on off so that the loop in trigger\n // can continue using it's old reference to loop without\n // messing up the order.\n\n this.listeners[type] = this.listeners[type].slice(0);\n this.listeners[type].splice(index, 1);\n return index > -1;\n }\n /**\n * Trigger an event of the specified type on this stream. Any additional\n * arguments to this function are passed as parameters to event listeners.\n *\n * @param {string} type the event name\n */\n ;\n\n _proto.trigger = function trigger(type) {\n var callbacks = this.listeners[type];\n\n if (!callbacks) {\n return;\n } // Slicing the arguments on every invocation of this method\n // can add a significant amount of overhead. Avoid the\n // intermediate object creation for the common case of a\n // single callback argument\n\n\n if (arguments.length === 2) {\n var length = callbacks.length;\n\n for (var i = 0; i < length; ++i) {\n callbacks[i].call(this, arguments[1]);\n }\n } else {\n var args = Array.prototype.slice.call(arguments, 1);\n var _length = callbacks.length;\n\n for (var _i = 0; _i < _length; ++_i) {\n callbacks[_i].apply(this, args);\n }\n }\n }\n /**\n * Destroys the stream and cleans up.\n */\n ;\n\n _proto.dispose = function dispose() {\n this.listeners = {};\n }\n /**\n * Forwards all `data` events on this stream to the destination stream. The\n * destination stream should provide a method `push` to receive the data\n * events as they arrive.\n *\n * @param {Stream} destination the stream that will receive all `data` events\n * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options\n */\n ;\n\n _proto.pipe = function pipe(destination) {\n this.on('data', function (data) {\n destination.push(data);\n });\n };\n\n return Stream;\n}();\n\nexport { Stream as default };","import window from 'global/window';\n\nvar atob = function atob(s) {\n return window.atob ? window.atob(s) : Buffer.from(s, 'base64').toString('binary');\n};\n\nexport default function decodeB64ToUint8Array(b64Text) {\n var decodedString = atob(b64Text);\n var array = new Uint8Array(decodedString.length);\n\n for (var i = 0; i < decodedString.length; i++) {\n array[i] = decodedString.charCodeAt(i);\n }\n\n return array;\n}","/*! @name m3u8-parser @version 4.7.0 @license Apache-2.0 */\nimport _inheritsLoose from '@babel/runtime/helpers/inheritsLoose';\nimport Stream from '@videojs/vhs-utils/es/stream.js';\nimport _extends from '@babel/runtime/helpers/extends';\nimport _assertThisInitialized from '@babel/runtime/helpers/assertThisInitialized';\nimport decodeB64ToUint8Array from '@videojs/vhs-utils/es/decode-b64-to-uint8-array.js';\n\n/**\n * A stream that buffers string input and generates a `data` event for each\n * line.\n *\n * @class LineStream\n * @extends Stream\n */\n\nvar LineStream = /*#__PURE__*/function (_Stream) {\n _inheritsLoose(LineStream, _Stream);\n\n function LineStream() {\n var _this;\n\n _this = _Stream.call(this) || this;\n _this.buffer = '';\n return _this;\n }\n /**\n * Add new data to be parsed.\n *\n * @param {string} data the text to process\n */\n\n\n var _proto = LineStream.prototype;\n\n _proto.push = function push(data) {\n var nextNewline;\n this.buffer += data;\n nextNewline = this.buffer.indexOf('\\n');\n\n for (; nextNewline > -1; nextNewline = this.buffer.indexOf('\\n')) {\n this.trigger('data', this.buffer.substring(0, nextNewline));\n this.buffer = this.buffer.substring(nextNewline + 1);\n }\n };\n\n return LineStream;\n}(Stream);\n\nvar TAB = String.fromCharCode(0x09);\n\nvar parseByterange = function parseByterange(byterangeString) {\n // optionally match and capture 0+ digits before `@`\n // optionally match and capture 0+ digits after `@`\n var match = /([0-9.]*)?@?([0-9.]*)?/.exec(byterangeString || '');\n var result = {};\n\n if (match[1]) {\n result.length = parseInt(match[1], 10);\n }\n\n if (match[2]) {\n result.offset = parseInt(match[2], 10);\n }\n\n return result;\n};\n/**\n * \"forgiving\" attribute list psuedo-grammar:\n * attributes -> keyvalue (',' keyvalue)*\n * keyvalue -> key '=' value\n * key -> [^=]*\n * value -> '\"' [^\"]* '\"' | [^,]*\n */\n\n\nvar attributeSeparator = function attributeSeparator() {\n var key = '[^=]*';\n var value = '\"[^\"]*\"|[^,]*';\n var keyvalue = '(?:' + key + ')=(?:' + value + ')';\n return new RegExp('(?:^|,)(' + keyvalue + ')');\n};\n/**\n * Parse attributes from a line given the separator\n *\n * @param {string} attributes the attribute line to parse\n */\n\n\nvar parseAttributes = function parseAttributes(attributes) {\n // split the string using attributes as the separator\n var attrs = attributes.split(attributeSeparator());\n var result = {};\n var i = attrs.length;\n var attr;\n\n while (i--) {\n // filter out unmatched portions of the string\n if (attrs[i] === '') {\n continue;\n } // split the key and value\n\n\n attr = /([^=]*)=(.*)/.exec(attrs[i]).slice(1); // trim whitespace and remove optional quotes around the value\n\n attr[0] = attr[0].replace(/^\\s+|\\s+$/g, '');\n attr[1] = attr[1].replace(/^\\s+|\\s+$/g, '');\n attr[1] = attr[1].replace(/^['\"](.*)['\"]$/g, '$1');\n result[attr[0]] = attr[1];\n }\n\n return result;\n};\n/**\n * A line-level M3U8 parser event stream. It expects to receive input one\n * line at a time and performs a context-free parse of its contents. A stream\n * interpretation of a manifest can be useful if the manifest is expected to\n * be too large to fit comfortably into memory or the entirety of the input\n * is not immediately available. Otherwise, it's probably much easier to work\n * with a regular `Parser` object.\n *\n * Produces `data` events with an object that captures the parser's\n * interpretation of the input. That object has a property `tag` that is one\n * of `uri`, `comment`, or `tag`. URIs only have a single additional\n * property, `line`, which captures the entirety of the input without\n * interpretation. Comments similarly have a single additional property\n * `text` which is the input without the leading `#`.\n *\n * Tags always have a property `tagType` which is the lower-cased version of\n * the M3U8 directive without the `#EXT` or `#EXT-X-` prefix. For instance,\n * `#EXT-X-MEDIA-SEQUENCE` becomes `media-sequence` when parsed. Unrecognized\n * tags are given the tag type `unknown` and a single additional property\n * `data` with the remainder of the input.\n *\n * @class ParseStream\n * @extends Stream\n */\n\n\nvar ParseStream = /*#__PURE__*/function (_Stream) {\n _inheritsLoose(ParseStream, _Stream);\n\n function ParseStream() {\n var _this;\n\n _this = _Stream.call(this) || this;\n _this.customParsers = [];\n _this.tagMappers = [];\n return _this;\n }\n /**\n * Parses an additional line of input.\n *\n * @param {string} line a single line of an M3U8 file to parse\n */\n\n\n var _proto = ParseStream.prototype;\n\n _proto.push = function push(line) {\n var _this2 = this;\n\n var match;\n var event; // strip whitespace\n\n line = line.trim();\n\n if (line.length === 0) {\n // ignore empty lines\n return;\n } // URIs\n\n\n if (line[0] !== '#') {\n this.trigger('data', {\n type: 'uri',\n uri: line\n });\n return;\n } // map tags\n\n\n var newLines = this.tagMappers.reduce(function (acc, mapper) {\n var mappedLine = mapper(line); // skip if unchanged\n\n if (mappedLine === line) {\n return acc;\n }\n\n return acc.concat([mappedLine]);\n }, [line]);\n newLines.forEach(function (newLine) {\n for (var i = 0; i < _this2.customParsers.length; i++) {\n if (_this2.customParsers[i].call(_this2, newLine)) {\n return;\n }\n } // Comments\n\n\n if (newLine.indexOf('#EXT') !== 0) {\n _this2.trigger('data', {\n type: 'comment',\n text: newLine.slice(1)\n });\n\n return;\n } // strip off any carriage returns here so the regex matching\n // doesn't have to account for them.\n\n\n newLine = newLine.replace('\\r', ''); // Tags\n\n match = /^#EXTM3U/.exec(newLine);\n\n if (match) {\n _this2.trigger('data', {\n type: 'tag',\n tagType: 'm3u'\n });\n\n return;\n }\n\n match = /^#EXTINF:?([0-9\\.]*)?,?(.*)?$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'inf'\n };\n\n if (match[1]) {\n event.duration = parseFloat(match[1]);\n }\n\n if (match[2]) {\n event.title = match[2];\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-TARGETDURATION:?([0-9.]*)?/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'targetduration'\n };\n\n if (match[1]) {\n event.duration = parseInt(match[1], 10);\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-VERSION:?([0-9.]*)?/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'version'\n };\n\n if (match[1]) {\n event.version = parseInt(match[1], 10);\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-MEDIA-SEQUENCE:?(\\-?[0-9.]*)?/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'media-sequence'\n };\n\n if (match[1]) {\n event.number = parseInt(match[1], 10);\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-DISCONTINUITY-SEQUENCE:?(\\-?[0-9.]*)?/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'discontinuity-sequence'\n };\n\n if (match[1]) {\n event.number = parseInt(match[1], 10);\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-PLAYLIST-TYPE:?(.*)?$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'playlist-type'\n };\n\n if (match[1]) {\n event.playlistType = match[1];\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-BYTERANGE:?(.*)?$/.exec(newLine);\n\n if (match) {\n event = _extends(parseByterange(match[1]), {\n type: 'tag',\n tagType: 'byterange'\n });\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-ALLOW-CACHE:?(YES|NO)?/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'allow-cache'\n };\n\n if (match[1]) {\n event.allowed = !/NO/.test(match[1]);\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-MAP:?(.*)$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'map'\n };\n\n if (match[1]) {\n var attributes = parseAttributes(match[1]);\n\n if (attributes.URI) {\n event.uri = attributes.URI;\n }\n\n if (attributes.BYTERANGE) {\n event.byterange = parseByterange(attributes.BYTERANGE);\n }\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-STREAM-INF:?(.*)$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'stream-inf'\n };\n\n if (match[1]) {\n event.attributes = parseAttributes(match[1]);\n\n if (event.attributes.RESOLUTION) {\n var split = event.attributes.RESOLUTION.split('x');\n var resolution = {};\n\n if (split[0]) {\n resolution.width = parseInt(split[0], 10);\n }\n\n if (split[1]) {\n resolution.height = parseInt(split[1], 10);\n }\n\n event.attributes.RESOLUTION = resolution;\n }\n\n if (event.attributes.BANDWIDTH) {\n event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10);\n }\n\n if (event.attributes['PROGRAM-ID']) {\n event.attributes['PROGRAM-ID'] = parseInt(event.attributes['PROGRAM-ID'], 10);\n }\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-MEDIA:?(.*)$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'media'\n };\n\n if (match[1]) {\n event.attributes = parseAttributes(match[1]);\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-ENDLIST/.exec(newLine);\n\n if (match) {\n _this2.trigger('data', {\n type: 'tag',\n tagType: 'endlist'\n });\n\n return;\n }\n\n match = /^#EXT-X-DISCONTINUITY/.exec(newLine);\n\n if (match) {\n _this2.trigger('data', {\n type: 'tag',\n tagType: 'discontinuity'\n });\n\n return;\n }\n\n match = /^#EXT-X-PROGRAM-DATE-TIME:?(.*)$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'program-date-time'\n };\n\n if (match[1]) {\n event.dateTimeString = match[1];\n event.dateTimeObject = new Date(match[1]);\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-KEY:?(.*)$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'key'\n };\n\n if (match[1]) {\n event.attributes = parseAttributes(match[1]); // parse the IV string into a Uint32Array\n\n if (event.attributes.IV) {\n if (event.attributes.IV.substring(0, 2).toLowerCase() === '0x') {\n event.attributes.IV = event.attributes.IV.substring(2);\n }\n\n event.attributes.IV = event.attributes.IV.match(/.{8}/g);\n event.attributes.IV[0] = parseInt(event.attributes.IV[0], 16);\n event.attributes.IV[1] = parseInt(event.attributes.IV[1], 16);\n event.attributes.IV[2] = parseInt(event.attributes.IV[2], 16);\n event.attributes.IV[3] = parseInt(event.attributes.IV[3], 16);\n event.attributes.IV = new Uint32Array(event.attributes.IV);\n }\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-START:?(.*)$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'start'\n };\n\n if (match[1]) {\n event.attributes = parseAttributes(match[1]);\n event.attributes['TIME-OFFSET'] = parseFloat(event.attributes['TIME-OFFSET']);\n event.attributes.PRECISE = /YES/.test(event.attributes.PRECISE);\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-CUE-OUT-CONT:?(.*)?$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'cue-out-cont'\n };\n\n if (match[1]) {\n event.data = match[1];\n } else {\n event.data = '';\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-CUE-OUT:?(.*)?$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'cue-out'\n };\n\n if (match[1]) {\n event.data = match[1];\n } else {\n event.data = '';\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-CUE-IN:?(.*)?$/.exec(newLine);\n\n if (match) {\n event = {\n type: 'tag',\n tagType: 'cue-in'\n };\n\n if (match[1]) {\n event.data = match[1];\n } else {\n event.data = '';\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-SKIP:(.*)$/.exec(newLine);\n\n if (match && match[1]) {\n event = {\n type: 'tag',\n tagType: 'skip'\n };\n event.attributes = parseAttributes(match[1]);\n\n if (event.attributes.hasOwnProperty('SKIPPED-SEGMENTS')) {\n event.attributes['SKIPPED-SEGMENTS'] = parseInt(event.attributes['SKIPPED-SEGMENTS'], 10);\n }\n\n if (event.attributes.hasOwnProperty('RECENTLY-REMOVED-DATERANGES')) {\n event.attributes['RECENTLY-REMOVED-DATERANGES'] = event.attributes['RECENTLY-REMOVED-DATERANGES'].split(TAB);\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-PART:(.*)$/.exec(newLine);\n\n if (match && match[1]) {\n event = {\n type: 'tag',\n tagType: 'part'\n };\n event.attributes = parseAttributes(match[1]);\n ['DURATION'].forEach(function (key) {\n if (event.attributes.hasOwnProperty(key)) {\n event.attributes[key] = parseFloat(event.attributes[key]);\n }\n });\n ['INDEPENDENT', 'GAP'].forEach(function (key) {\n if (event.attributes.hasOwnProperty(key)) {\n event.attributes[key] = /YES/.test(event.attributes[key]);\n }\n });\n\n if (event.attributes.hasOwnProperty('BYTERANGE')) {\n event.attributes.byterange = parseByterange(event.attributes.BYTERANGE);\n }\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-SERVER-CONTROL:(.*)$/.exec(newLine);\n\n if (match && match[1]) {\n event = {\n type: 'tag',\n tagType: 'server-control'\n };\n event.attributes = parseAttributes(match[1]);\n ['CAN-SKIP-UNTIL', 'PART-HOLD-BACK', 'HOLD-BACK'].forEach(function (key) {\n if (event.attributes.hasOwnProperty(key)) {\n event.attributes[key] = parseFloat(event.attributes[key]);\n }\n });\n ['CAN-SKIP-DATERANGES', 'CAN-BLOCK-RELOAD'].forEach(function (key) {\n if (event.attributes.hasOwnProperty(key)) {\n event.attributes[key] = /YES/.test(event.attributes[key]);\n }\n });\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-PART-INF:(.*)$/.exec(newLine);\n\n if (match && match[1]) {\n event = {\n type: 'tag',\n tagType: 'part-inf'\n };\n event.attributes = parseAttributes(match[1]);\n ['PART-TARGET'].forEach(function (key) {\n if (event.attributes.hasOwnProperty(key)) {\n event.attributes[key] = parseFloat(event.attributes[key]);\n }\n });\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-PRELOAD-HINT:(.*)$/.exec(newLine);\n\n if (match && match[1]) {\n event = {\n type: 'tag',\n tagType: 'preload-hint'\n };\n event.attributes = parseAttributes(match[1]);\n ['BYTERANGE-START', 'BYTERANGE-LENGTH'].forEach(function (key) {\n if (event.attributes.hasOwnProperty(key)) {\n event.attributes[key] = parseInt(event.attributes[key], 10);\n var subkey = key === 'BYTERANGE-LENGTH' ? 'length' : 'offset';\n event.attributes.byterange = event.attributes.byterange || {};\n event.attributes.byterange[subkey] = event.attributes[key]; // only keep the parsed byterange object.\n\n delete event.attributes[key];\n }\n });\n\n _this2.trigger('data', event);\n\n return;\n }\n\n match = /^#EXT-X-RENDITION-REPORT:(.*)$/.exec(newLine);\n\n if (match && match[1]) {\n event = {\n type: 'tag',\n tagType: 'rendition-report'\n };\n event.attributes = parseAttributes(match[1]);\n ['LAST-MSN', 'LAST-PART'].forEach(function (key) {\n if (event.attributes.hasOwnProperty(key)) {\n event.attributes[key] = parseInt(event.attributes[key], 10);\n }\n });\n\n _this2.trigger('data', event);\n\n return;\n } // unknown tag type\n\n\n _this2.trigger('data', {\n type: 'tag',\n data: newLine.slice(4)\n });\n });\n }\n /**\n * Add a parser for custom headers\n *\n * @param {Object} options a map of options for the added parser\n * @param {RegExp} options.expression a regular expression to match the custom header\n * @param {string} options.customType the custom type to register to the output\n * @param {Function} [options.dataParser] function to parse the line into an object\n * @param {boolean} [options.segment] should tag data be attached to the segment object\n */\n ;\n\n _proto.addParser = function addParser(_ref) {\n var _this3 = this;\n\n var expression = _ref.expression,\n customType = _ref.customType,\n dataParser = _ref.dataParser,\n segment = _ref.segment;\n\n if (typeof dataParser !== 'function') {\n dataParser = function dataParser(line) {\n return line;\n };\n }\n\n this.customParsers.push(function (line) {\n var match = expression.exec(line);\n\n if (match) {\n _this3.trigger('data', {\n type: 'custom',\n data: dataParser(line),\n customType: customType,\n segment: segment\n });\n\n return true;\n }\n });\n }\n /**\n * Add a custom header mapper\n *\n * @param {Object} options\n * @param {RegExp} options.expression a regular expression to match the custom header\n * @param {Function} options.map function to translate tag into a different tag\n */\n ;\n\n _proto.addTagMapper = function addTagMapper(_ref2) {\n var expression = _ref2.expression,\n map = _ref2.map;\n\n var mapFn = function mapFn(line) {\n if (expression.test(line)) {\n return map(line);\n }\n\n return line;\n };\n\n this.tagMappers.push(mapFn);\n };\n\n return ParseStream;\n}(Stream);\n\nvar camelCase = function camelCase(str) {\n return str.toLowerCase().replace(/-(\\w)/g, function (a) {\n return a[1].toUpperCase();\n });\n};\n\nvar camelCaseKeys = function camelCaseKeys(attributes) {\n var result = {};\n Object.keys(attributes).forEach(function (key) {\n result[camelCase(key)] = attributes[key];\n });\n return result;\n}; // set SERVER-CONTROL hold back based upon targetDuration and partTargetDuration\n// we need this helper because defaults are based upon targetDuration and\n// partTargetDuration being set, but they may not be if SERVER-CONTROL appears before\n// target durations are set.\n\n\nvar setHoldBack = function setHoldBack(manifest) {\n var serverControl = manifest.serverControl,\n targetDuration = manifest.targetDuration,\n partTargetDuration = manifest.partTargetDuration;\n\n if (!serverControl) {\n return;\n }\n\n var tag = '#EXT-X-SERVER-CONTROL';\n var hb = 'holdBack';\n var phb = 'partHoldBack';\n var minTargetDuration = targetDuration && targetDuration * 3;\n var minPartDuration = partTargetDuration && partTargetDuration * 2;\n\n if (targetDuration && !serverControl.hasOwnProperty(hb)) {\n serverControl[hb] = minTargetDuration;\n this.trigger('info', {\n message: tag + \" defaulting HOLD-BACK to targetDuration * 3 (\" + minTargetDuration + \").\"\n });\n }\n\n if (minTargetDuration && serverControl[hb] < minTargetDuration) {\n this.trigger('warn', {\n message: tag + \" clamping HOLD-BACK (\" + serverControl[hb] + \") to targetDuration * 3 (\" + minTargetDuration + \")\"\n });\n serverControl[hb] = minTargetDuration;\n } // default no part hold back to part target duration * 3\n\n\n if (partTargetDuration && !serverControl.hasOwnProperty(phb)) {\n serverControl[phb] = partTargetDuration * 3;\n this.trigger('info', {\n message: tag + \" defaulting PART-HOLD-BACK to partTargetDuration * 3 (\" + serverControl[phb] + \").\"\n });\n } // if part hold back is too small default it to part target duration * 2\n\n\n if (partTargetDuration && serverControl[phb] < minPartDuration) {\n this.trigger('warn', {\n message: tag + \" clamping PART-HOLD-BACK (\" + serverControl[phb] + \") to partTargetDuration * 2 (\" + minPartDuration + \").\"\n });\n serverControl[phb] = minPartDuration;\n }\n};\n/**\n * A parser for M3U8 files. The current interpretation of the input is\n * exposed as a property `manifest` on parser objects. It's just two lines to\n * create and parse a manifest once you have the contents available as a string:\n *\n * ```js\n * var parser = new m3u8.Parser();\n * parser.push(xhr.responseText);\n * ```\n *\n * New input can later be applied to update the manifest object by calling\n * `push` again.\n *\n * The parser attempts to create a usable manifest object even if the\n * underlying input is somewhat nonsensical. It emits `info` and `warning`\n * events during the parse if it encounters input that seems invalid or\n * requires some property of the manifest object to be defaulted.\n *\n * @class Parser\n * @extends Stream\n */\n\n\nvar Parser = /*#__PURE__*/function (_Stream) {\n _inheritsLoose(Parser, _Stream);\n\n function Parser() {\n var _this;\n\n _this = _Stream.call(this) || this;\n _this.lineStream = new LineStream();\n _this.parseStream = new ParseStream();\n\n _this.lineStream.pipe(_this.parseStream);\n /* eslint-disable consistent-this */\n\n\n var self = _assertThisInitialized(_this);\n /* eslint-enable consistent-this */\n\n\n var uris = [];\n var currentUri = {}; // if specified, the active EXT-X-MAP definition\n\n var currentMap; // if specified, the active decryption key\n\n var _key;\n\n var hasParts = false;\n\n var noop = function noop() {};\n\n var defaultMediaGroups = {\n 'AUDIO': {},\n 'VIDEO': {},\n 'CLOSED-CAPTIONS': {},\n 'SUBTITLES': {}\n }; // This is the Widevine UUID from DASH IF IOP. The same exact string is\n // used in MPDs with Widevine encrypted streams.\n\n var widevineUuid = 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'; // group segments into numbered timelines delineated by discontinuities\n\n var currentTimeline = 0; // the manifest is empty until the parse stream begins delivering data\n\n _this.manifest = {\n allowCache: true,\n discontinuityStarts: [],\n segments: []\n }; // keep track of the last seen segment's byte range end, as segments are not required\n // to provide the offset, in which case it defaults to the next byte after the\n // previous segment\n\n var lastByterangeEnd = 0; // keep track of the last seen part's byte range end.\n\n var lastPartByterangeEnd = 0;\n\n _this.on('end', function () {\n // only add preloadSegment if we don't yet have a uri for it.\n // and we actually have parts/preloadHints\n if (currentUri.uri || !currentUri.parts && !currentUri.preloadHints) {\n return;\n }\n\n if (!currentUri.map && currentMap) {\n currentUri.map = currentMap;\n }\n\n if (!currentUri.key && _key) {\n currentUri.key = _key;\n }\n\n if (!currentUri.timeline && typeof currentTimeline === 'number') {\n currentUri.timeline = currentTimeline;\n }\n\n _this.manifest.preloadSegment = currentUri;\n }); // update the manifest with the m3u8 entry from the parse stream\n\n\n _this.parseStream.on('data', function (entry) {\n var mediaGroup;\n var rendition;\n ({\n tag: function tag() {\n // switch based on the tag type\n (({\n version: function version() {\n if (entry.version) {\n this.manifest.version = entry.version;\n }\n },\n 'allow-cache': function allowCache() {\n this.manifest.allowCache = entry.allowed;\n\n if (!('allowed' in entry)) {\n this.trigger('info', {\n message: 'defaulting allowCache to YES'\n });\n this.manifest.allowCache = true;\n }\n },\n byterange: function byterange() {\n var byterange = {};\n\n if ('length' in entry) {\n currentUri.byterange = byterange;\n byterange.length = entry.length;\n\n if (!('offset' in entry)) {\n /*\n * From the latest spec (as of this writing):\n * https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.2.2\n *\n * Same text since EXT-X-BYTERANGE's introduction in draft 7:\n * https://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.1)\n *\n * \"If o [offset] is not present, the sub-range begins at the next byte\n * following the sub-range of the previous media segment.\"\n */\n entry.offset = lastByterangeEnd;\n }\n }\n\n if ('offset' in entry) {\n currentUri.byterange = byterange;\n byterange.offset = entry.offset;\n }\n\n lastByterangeEnd = byterange.offset + byterange.length;\n },\n endlist: function endlist() {\n this.manifest.endList = true;\n },\n inf: function inf() {\n if (!('mediaSequence' in this.manifest)) {\n this.manifest.mediaSequence = 0;\n this.trigger('info', {\n message: 'defaulting media sequence to zero'\n });\n }\n\n if (!('discontinuitySequence' in this.manifest)) {\n this.manifest.discontinuitySequence = 0;\n this.trigger('info', {\n message: 'defaulting discontinuity sequence to zero'\n });\n }\n\n if (entry.duration > 0) {\n currentUri.duration = entry.duration;\n }\n\n if (entry.duration === 0) {\n currentUri.duration = 0.01;\n this.trigger('info', {\n message: 'updating zero segment duration to a small value'\n });\n }\n\n this.manifest.segments = uris;\n },\n key: function key() {\n if (!entry.attributes) {\n this.trigger('warn', {\n message: 'ignoring key declaration without attribute list'\n });\n return;\n } // clear the active encryption key\n\n\n if (entry.attributes.METHOD === 'NONE') {\n _key = null;\n return;\n }\n\n if (!entry.attributes.URI) {\n this.trigger('warn', {\n message: 'ignoring key declaration without URI'\n });\n return;\n }\n\n if (entry.attributes.KEYFORMAT === 'com.apple.streamingkeydelivery') {\n this.manifest.contentProtection = this.manifest.contentProtection || {}; // TODO: add full support for this.\n\n this.manifest.contentProtection['com.apple.fps.1_0'] = {\n attributes: entry.attributes\n };\n return;\n } // check if the content is encrypted for Widevine\n // Widevine/HLS spec: https://storage.googleapis.com/wvdocs/Widevine_DRM_HLS.pdf\n\n\n if (entry.attributes.KEYFORMAT === widevineUuid) {\n var VALID_METHODS = ['SAMPLE-AES', 'SAMPLE-AES-CTR', 'SAMPLE-AES-CENC'];\n\n if (VALID_METHODS.indexOf(entry.attributes.METHOD) === -1) {\n this.trigger('warn', {\n message: 'invalid key method provided for Widevine'\n });\n return;\n }\n\n if (entry.attributes.METHOD === 'SAMPLE-AES-CENC') {\n this.trigger('warn', {\n message: 'SAMPLE-AES-CENC is deprecated, please use SAMPLE-AES-CTR instead'\n });\n }\n\n if (entry.attributes.URI.substring(0, 23) !== 'data:text/plain;base64,') {\n this.trigger('warn', {\n message: 'invalid key URI provided for Widevine'\n });\n return;\n }\n\n if (!(entry.attributes.KEYID && entry.attributes.KEYID.substring(0, 2) === '0x')) {\n this.trigger('warn', {\n message: 'invalid key ID provided for Widevine'\n });\n return;\n } // if Widevine key attributes are valid, store them as `contentProtection`\n // on the manifest to emulate Widevine tag structure in a DASH mpd\n\n\n this.manifest.contentProtection = this.manifest.contentProtection || {};\n this.manifest.contentProtection['com.widevine.alpha'] = {\n attributes: {\n schemeIdUri: entry.attributes.KEYFORMAT,\n // remove '0x' from the key id string\n keyId: entry.attributes.KEYID.substring(2)\n },\n // decode the base64-encoded PSSH box\n pssh: decodeB64ToUint8Array(entry.attributes.URI.split(',')[1])\n };\n return;\n }\n\n if (!entry.attributes.METHOD) {\n this.trigger('warn', {\n message: 'defaulting key method to AES-128'\n });\n } // setup an encryption key for upcoming segments\n\n\n _key = {\n method: entry.attributes.METHOD || 'AES-128',\n uri: entry.attributes.URI\n };\n\n if (typeof entry.attributes.IV !== 'undefined') {\n _key.iv = entry.attributes.IV;\n }\n },\n 'media-sequence': function mediaSequence() {\n if (!isFinite(entry.number)) {\n this.trigger('warn', {\n message: 'ignoring invalid media sequence: ' + entry.number\n });\n return;\n }\n\n this.manifest.mediaSequence = entry.number;\n },\n 'discontinuity-sequence': function discontinuitySequence() {\n if (!isFinite(entry.number)) {\n this.trigger('warn', {\n message: 'ignoring invalid discontinuity sequence: ' + entry.number\n });\n return;\n }\n\n this.manifest.discontinuitySequence = entry.number;\n currentTimeline = entry.number;\n },\n 'playlist-type': function playlistType() {\n if (!/VOD|EVENT/.test(entry.playlistType)) {\n this.trigger('warn', {\n message: 'ignoring unknown playlist type: ' + entry.playlist\n });\n return;\n }\n\n this.manifest.playlistType = entry.playlistType;\n },\n map: function map() {\n currentMap = {};\n\n if (entry.uri) {\n currentMap.uri = entry.uri;\n }\n\n if (entry.byterange) {\n currentMap.byterange = entry.byterange;\n }\n\n if (_key) {\n currentMap.key = _key;\n }\n },\n 'stream-inf': function streamInf() {\n this.manifest.playlists = uris;\n this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups;\n\n if (!entry.attributes) {\n this.trigger('warn', {\n message: 'ignoring empty stream-inf attributes'\n });\n return;\n }\n\n if (!currentUri.attributes) {\n currentUri.attributes = {};\n }\n\n _extends(currentUri.attributes, entry.attributes);\n },\n media: function media() {\n this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups;\n\n if (!(entry.attributes && entry.attributes.TYPE && entry.attributes['GROUP-ID'] && entry.attributes.NAME)) {\n this.trigger('warn', {\n message: 'ignoring incomplete or missing media group'\n });\n return;\n } // find the media group, creating defaults as necessary\n\n\n var mediaGroupType = this.manifest.mediaGroups[entry.attributes.TYPE];\n mediaGroupType[entry.attributes['GROUP-ID']] = mediaGroupType[entry.attributes['GROUP-ID']] || {};\n mediaGroup = mediaGroupType[entry.attributes['GROUP-ID']]; // collect the rendition metadata\n\n rendition = {\n default: /yes/i.test(entry.attributes.DEFAULT)\n };\n\n if (rendition.default) {\n rendition.autoselect = true;\n } else {\n rendition.autoselect = /yes/i.test(entry.attributes.AUTOSELECT);\n }\n\n if (entry.attributes.LANGUAGE) {\n rendition.language = entry.attributes.LANGUAGE;\n }\n\n if (entry.attributes.URI) {\n rendition.uri = entry.attributes.URI;\n }\n\n if (entry.attributes['INSTREAM-ID']) {\n rendition.instreamId = entry.attributes['INSTREAM-ID'];\n }\n\n if (entry.attributes.CHARACTERISTICS) {\n rendition.characteristics = entry.attributes.CHARACTERISTICS;\n }\n\n if (entry.attributes.FORCED) {\n rendition.forced = /yes/i.test(entry.attributes.FORCED);\n } // insert the new rendition\n\n\n mediaGroup[entry.attributes.NAME] = rendition;\n },\n discontinuity: function discontinuity() {\n currentTimeline += 1;\n currentUri.discontinuity = true;\n this.manifest.discontinuityStarts.push(uris.length);\n },\n 'program-date-time': function programDateTime() {\n if (typeof this.manifest.dateTimeString === 'undefined') {\n // PROGRAM-DATE-TIME is a media-segment tag, but for backwards\n // compatibility, we add the first occurence of the PROGRAM-DATE-TIME tag\n // to the manifest object\n // TODO: Consider removing this in future major version\n this.manifest.dateTimeString = entry.dateTimeString;\n this.manifest.dateTimeObject = entry.dateTimeObject;\n }\n\n currentUri.dateTimeString = entry.dateTimeString;\n currentUri.dateTimeObject = entry.dateTimeObject;\n },\n targetduration: function targetduration() {\n if (!isFinite(entry.duration) || entry.duration < 0) {\n this.trigger('warn', {\n message: 'ignoring invalid target duration: ' + entry.duration\n });\n return;\n }\n\n this.manifest.targetDuration = entry.duration;\n setHoldBack.call(this, this.manifest);\n },\n start: function start() {\n if (!entry.attributes || isNaN(entry.attributes['TIME-OFFSET'])) {\n this.trigger('warn', {\n message: 'ignoring start declaration without appropriate attribute list'\n });\n return;\n }\n\n this.manifest.start = {\n timeOffset: entry.attributes['TIME-OFFSET'],\n precise: entry.attributes.PRECISE\n };\n },\n 'cue-out': function cueOut() {\n currentUri.cueOut = entry.data;\n },\n 'cue-out-cont': function cueOutCont() {\n currentUri.cueOutCont = entry.data;\n },\n 'cue-in': function cueIn() {\n currentUri.cueIn = entry.data;\n },\n 'skip': function skip() {\n this.manifest.skip = camelCaseKeys(entry.attributes);\n this.warnOnMissingAttributes_('#EXT-X-SKIP', entry.attributes, ['SKIPPED-SEGMENTS']);\n },\n 'part': function part() {\n var _this2 = this;\n\n hasParts = true; // parts are always specifed before a segment\n\n var segmentIndex = this.manifest.segments.length;\n var part = camelCaseKeys(entry.attributes);\n currentUri.parts = currentUri.parts || [];\n currentUri.parts.push(part);\n\n if (part.byterange) {\n if (!part.byterange.hasOwnProperty('offset')) {\n part.byterange.offset = lastPartByterangeEnd;\n }\n\n lastPartByterangeEnd = part.byterange.offset + part.byterange.length;\n }\n\n var partIndex = currentUri.parts.length - 1;\n this.warnOnMissingAttributes_(\"#EXT-X-PART #\" + partIndex + \" for segment #\" + segmentIndex, entry.attributes, ['URI', 'DURATION']);\n\n if (this.manifest.renditionReports) {\n this.manifest.renditionReports.forEach(function (r, i) {\n if (!r.hasOwnProperty('lastPart')) {\n _this2.trigger('warn', {\n message: \"#EXT-X-RENDITION-REPORT #\" + i + \" lacks required attribute(s): LAST-PART\"\n });\n }\n });\n }\n },\n 'server-control': function serverControl() {\n var attrs = this.manifest.serverControl = camelCaseKeys(entry.attributes);\n\n if (!attrs.hasOwnProperty('canBlockReload')) {\n attrs.canBlockReload = false;\n this.trigger('info', {\n message: '#EXT-X-SERVER-CONTROL defaulting CAN-BLOCK-RELOAD to false'\n });\n }\n\n setHoldBack.call(this, this.manifest);\n\n if (attrs.canSkipDateranges && !attrs.hasOwnProperty('canSkipUntil')) {\n this.trigger('warn', {\n message: '#EXT-X-SERVER-CONTROL lacks required attribute CAN-SKIP-UNTIL which is required when CAN-SKIP-DATERANGES is set'\n });\n }\n },\n 'preload-hint': function preloadHint() {\n // parts are always specifed before a segment\n var segmentIndex = this.manifest.segments.length;\n var hint = camelCaseKeys(entry.attributes);\n var isPart = hint.type && hint.type === 'PART';\n currentUri.preloadHints = currentUri.preloadHints || [];\n currentUri.preloadHints.push(hint);\n\n if (hint.byterange) {\n if (!hint.byterange.hasOwnProperty('offset')) {\n // use last part byterange end or zero if not a part.\n hint.byterange.offset = isPart ? lastPartByterangeEnd : 0;\n\n if (isPart) {\n lastPartByterangeEnd = hint.byterange.offset + hint.byterange.length;\n }\n }\n }\n\n var index = currentUri.preloadHints.length - 1;\n this.warnOnMissingAttributes_(\"#EXT-X-PRELOAD-HINT #\" + index + \" for segment #\" + segmentIndex, entry.attributes, ['TYPE', 'URI']);\n\n if (!hint.type) {\n return;\n } // search through all preload hints except for the current one for\n // a duplicate type.\n\n\n for (var i = 0; i < currentUri.preloadHints.length - 1; i++) {\n var otherHint = currentUri.preloadHints[i];\n\n if (!otherHint.type) {\n continue;\n }\n\n if (otherHint.type === hint.type) {\n this.trigger('warn', {\n message: \"#EXT-X-PRELOAD-HINT #\" + index + \" for segment #\" + segmentIndex + \" has the same TYPE \" + hint.type + \" as preload hint #\" + i\n });\n }\n }\n },\n 'rendition-report': function renditionReport() {\n var report = camelCaseKeys(entry.attributes);\n this.manifest.renditionReports = this.manifest.renditionReports || [];\n this.manifest.renditionReports.push(report);\n var index = this.manifest.renditionReports.length - 1;\n var required = ['LAST-MSN', 'URI'];\n\n if (hasParts) {\n required.push('LAST-PART');\n }\n\n this.warnOnMissingAttributes_(\"#EXT-X-RENDITION-REPORT #\" + index, entry.attributes, required);\n },\n 'part-inf': function partInf() {\n this.manifest.partInf = camelCaseKeys(entry.attributes);\n this.warnOnMissingAttributes_('#EXT-X-PART-INF', entry.attributes, ['PART-TARGET']);\n\n if (this.manifest.partInf.partTarget) {\n this.manifest.partTargetDuration = this.manifest.partInf.partTarget;\n }\n\n setHoldBack.call(this, this.manifest);\n }\n })[entry.tagType] || noop).call(self);\n },\n uri: function uri() {\n currentUri.uri = entry.uri;\n uris.push(currentUri); // if no explicit duration was declared, use the target duration\n\n if (this.manifest.targetDuration && !('duration' in currentUri)) {\n this.trigger('warn', {\n message: 'defaulting segment duration to the target duration'\n });\n currentUri.duration = this.manifest.targetDuration;\n } // annotate with encryption information, if necessary\n\n\n if (_key) {\n currentUri.key = _key;\n }\n\n currentUri.timeline = currentTimeline; // annotate with initialization segment information, if necessary\n\n if (currentMap) {\n currentUri.map = currentMap;\n } // reset the last byterange end as it needs to be 0 between parts\n\n\n lastPartByterangeEnd = 0; // prepare for the next URI\n\n currentUri = {};\n },\n comment: function comment() {// comments are not important for playback\n },\n custom: function custom() {\n // if this is segment-level data attach the output to the segment\n if (entry.segment) {\n currentUri.custom = currentUri.custom || {};\n currentUri.custom[entry.customType] = entry.data; // if this is manifest-level data attach to the top level manifest object\n } else {\n this.manifest.custom = this.manifest.custom || {};\n this.manifest.custom[entry.customType] = entry.data;\n }\n }\n })[entry.type].call(self);\n });\n\n return _this;\n }\n\n var _proto = Parser.prototype;\n\n _proto.warnOnMissingAttributes_ = function warnOnMissingAttributes_(identifier, attributes, required) {\n var missing = [];\n required.forEach(function (key) {\n if (!attributes.hasOwnProperty(key)) {\n missing.push(key);\n }\n });\n\n if (missing.length) {\n this.trigger('warn', {\n message: identifier + \" lacks required attribute(s): \" + missing.join(', ')\n });\n }\n }\n /**\n * Parse the input string and update the manifest object.\n *\n * @param {string} chunk a potentially incomplete portion of the manifest\n */\n ;\n\n _proto.push = function push(chunk) {\n this.lineStream.push(chunk);\n }\n /**\n * Flush any remaining input. This can be handy if the last line of an M3U8\n * manifest did not contain a trailing newline but the file has been\n * completely received.\n */\n ;\n\n _proto.end = function end() {\n // flush any buffered input\n this.lineStream.push('\\n');\n this.trigger('end');\n }\n /**\n * Add an additional parser for non-standard tags\n *\n * @param {Object} options a map of options for the added parser\n * @param {RegExp} options.expression a regular expression to match the custom header\n * @param {string} options.type the type to register to the output\n * @param {Function} [options.dataParser] function to parse the line into an object\n * @param {boolean} [options.segment] should tag data be attached to the segment object\n */\n ;\n\n _proto.addParser = function addParser(options) {\n this.parseStream.addParser(options);\n }\n /**\n * Add a custom header mapper\n *\n * @param {Object} options\n * @param {RegExp} options.expression a regular expression to match the custom header\n * @param {Function} options.map function to translate tag into a different tag\n */\n ;\n\n _proto.addTagMapper = function addTagMapper(options) {\n this.parseStream.addTagMapper(options);\n };\n\n return Parser;\n}(Stream);\n\nexport { LineStream, ParseStream, Parser };\n","import window from 'global/window';\nvar regexs = {\n // to determine mime types\n mp4: /^(av0?1|avc0?[1234]|vp0?9|flac|opus|mp3|mp4a|mp4v|stpp.ttml.im1t)/,\n webm: /^(vp0?[89]|av0?1|opus|vorbis)/,\n ogg: /^(vp0?[89]|theora|flac|opus|vorbis)/,\n // to determine if a codec is audio or video\n video: /^(av0?1|avc0?[1234]|vp0?[89]|hvc1|hev1|theora|mp4v)/,\n audio: /^(mp4a|flac|vorbis|opus|ac-[34]|ec-3|alac|mp3|speex|aac)/,\n text: /^(stpp.ttml.im1t)/,\n // mux.js support regex\n muxerVideo: /^(avc0?1)/,\n muxerAudio: /^(mp4a)/,\n // match nothing as muxer does not support text right now.\n // there cannot never be a character before the start of a string\n // so this matches nothing.\n muxerText: /a^/\n};\nvar mediaTypes = ['video', 'audio', 'text'];\nvar upperMediaTypes = ['Video', 'Audio', 'Text'];\n/**\n * Replace the old apple-style `avc1.
.
` codec string with the standard\n * `avc1.`\n *\n * @param {string} codec\n * Codec string to translate\n * @return {string}\n * The translated codec string\n */\n\nexport var translateLegacyCodec = function translateLegacyCodec(codec) {\n if (!codec) {\n return codec;\n }\n\n return codec.replace(/avc1\\.(\\d+)\\.(\\d+)/i, function (orig, profile, avcLevel) {\n var profileHex = ('00' + Number(profile).toString(16)).slice(-2);\n var avcLevelHex = ('00' + Number(avcLevel).toString(16)).slice(-2);\n return 'avc1.' + profileHex + '00' + avcLevelHex;\n });\n};\n/**\n * Replace the old apple-style `avc1.
.
` codec strings with the standard\n * `avc1.`\n *\n * @param {string[]} codecs\n * An array of codec strings to translate\n * @return {string[]}\n * The translated array of codec strings\n */\n\nexport var translateLegacyCodecs = function translateLegacyCodecs(codecs) {\n return codecs.map(translateLegacyCodec);\n};\n/**\n * Replace codecs in the codec string with the old apple-style `avc1.
.
` to the\n * standard `avc1.`.\n *\n * @param {string} codecString\n * The codec string\n * @return {string}\n * The codec string with old apple-style codecs replaced\n *\n * @private\n */\n\nexport var mapLegacyAvcCodecs = function mapLegacyAvcCodecs(codecString) {\n return codecString.replace(/avc1\\.(\\d+)\\.(\\d+)/i, function (match) {\n return translateLegacyCodecs([match])[0];\n });\n};\n/**\n * @typedef {Object} ParsedCodecInfo\n * @property {number} codecCount\n * Number of codecs parsed\n * @property {string} [videoCodec]\n * Parsed video codec (if found)\n * @property {string} [videoObjectTypeIndicator]\n * Video object type indicator (if found)\n * @property {string|null} audioProfile\n * Audio profile\n */\n\n/**\n * Parses a codec string to retrieve the number of codecs specified, the video codec and\n * object type indicator, and the audio profile.\n *\n * @param {string} [codecString]\n * The codec string to parse\n * @return {ParsedCodecInfo}\n * Parsed codec info\n */\n\nexport var parseCodecs = function parseCodecs(codecString) {\n if (codecString === void 0) {\n codecString = '';\n }\n\n var codecs = codecString.split(',');\n var result = [];\n codecs.forEach(function (codec) {\n codec = codec.trim();\n var codecType;\n mediaTypes.forEach(function (name) {\n var match = regexs[name].exec(codec.toLowerCase());\n\n if (!match || match.length <= 1) {\n return;\n }\n\n codecType = name; // maintain codec case\n\n var type = codec.substring(0, match[1].length);\n var details = codec.replace(type, '');\n result.push({\n type: type,\n details: details,\n mediaType: name\n });\n });\n\n if (!codecType) {\n result.push({\n type: codec,\n details: '',\n mediaType: 'unknown'\n });\n }\n });\n return result;\n};\n/**\n * Returns a ParsedCodecInfo object for the default alternate audio playlist if there is\n * a default alternate audio playlist for the provided audio group.\n *\n * @param {Object} master\n * The master playlist\n * @param {string} audioGroupId\n * ID of the audio group for which to find the default codec info\n * @return {ParsedCodecInfo}\n * Parsed codec info\n */\n\nexport var codecsFromDefault = function codecsFromDefault(master, audioGroupId) {\n if (!master.mediaGroups.AUDIO || !audioGroupId) {\n return null;\n }\n\n var audioGroup = master.mediaGroups.AUDIO[audioGroupId];\n\n if (!audioGroup) {\n return null;\n }\n\n for (var name in audioGroup) {\n var audioType = audioGroup[name];\n\n if (audioType.default && audioType.playlists) {\n // codec should be the same for all playlists within the audio type\n return parseCodecs(audioType.playlists[0].attributes.CODECS);\n }\n }\n\n return null;\n};\nexport var isVideoCodec = function isVideoCodec(codec) {\n if (codec === void 0) {\n codec = '';\n }\n\n return regexs.video.test(codec.trim().toLowerCase());\n};\nexport var isAudioCodec = function isAudioCodec(codec) {\n if (codec === void 0) {\n codec = '';\n }\n\n return regexs.audio.test(codec.trim().toLowerCase());\n};\nexport var isTextCodec = function isTextCodec(codec) {\n if (codec === void 0) {\n codec = '';\n }\n\n return regexs.text.test(codec.trim().toLowerCase());\n};\nexport var getMimeForCodec = function getMimeForCodec(codecString) {\n if (!codecString || typeof codecString !== 'string') {\n return;\n }\n\n var codecs = codecString.toLowerCase().split(',').map(function (c) {\n return translateLegacyCodec(c.trim());\n }); // default to video type\n\n var type = 'video'; // only change to audio type if the only codec we have is\n // audio\n\n if (codecs.length === 1 && isAudioCodec(codecs[0])) {\n type = 'audio';\n } else if (codecs.length === 1 && isTextCodec(codecs[0])) {\n // text uses application/ for now\n type = 'application';\n } // default the container to mp4\n\n\n var container = 'mp4'; // every codec must be able to go into the container\n // for that container to be the correct one\n\n if (codecs.every(function (c) {\n return regexs.mp4.test(c);\n })) {\n container = 'mp4';\n } else if (codecs.every(function (c) {\n return regexs.webm.test(c);\n })) {\n container = 'webm';\n } else if (codecs.every(function (c) {\n return regexs.ogg.test(c);\n })) {\n container = 'ogg';\n }\n\n return type + \"/\" + container + \";codecs=\\\"\" + codecString + \"\\\"\";\n};\nexport var browserSupportsCodec = function browserSupportsCodec(codecString) {\n if (codecString === void 0) {\n codecString = '';\n }\n\n return window.MediaSource && window.MediaSource.isTypeSupported && window.MediaSource.isTypeSupported(getMimeForCodec(codecString)) || false;\n};\nexport var muxerSupportsCodec = function muxerSupportsCodec(codecString) {\n if (codecString === void 0) {\n codecString = '';\n }\n\n return codecString.toLowerCase().split(',').every(function (codec) {\n codec = codec.trim(); // any match is supported.\n\n for (var i = 0; i < upperMediaTypes.length; i++) {\n var type = upperMediaTypes[i];\n\n if (regexs[\"muxer\" + type].test(codec)) {\n return true;\n }\n }\n\n return false;\n });\n};\nexport var DEFAULT_AUDIO_CODEC = 'mp4a.40.2';\nexport var DEFAULT_VIDEO_CODEC = 'avc1.4d400d';","var MPEGURL_REGEX = /^(audio|video|application)\\/(x-|vnd\\.apple\\.)?mpegurl/i;\nvar DASH_REGEX = /^application\\/dash\\+xml/i;\n/**\n * Returns a string that describes the type of source based on a video source object's\n * media type.\n *\n * @see {@link https://dev.w3.org/html5/pf-summary/video.html#dom-source-type|Source Type}\n *\n * @param {string} type\n * Video source object media type\n * @return {('hls'|'dash'|'vhs-json'|null)}\n * VHS source type string\n */\n\nexport var simpleTypeFromSourceType = function simpleTypeFromSourceType(type) {\n if (MPEGURL_REGEX.test(type)) {\n return 'hls';\n }\n\n if (DASH_REGEX.test(type)) {\n return 'dash';\n } // Denotes the special case of a manifest object passed to http-streaming instead of a\n // source URL.\n //\n // See https://en.wikipedia.org/wiki/Media_type for details on specifying media types.\n //\n // In this case, vnd stands for vendor, video.js for the organization, VHS for this\n // project, and the +json suffix identifies the structure of the media type.\n\n\n if (type === 'application/vnd.videojs.vhs+json') {\n return 'vhs-json';\n }\n\n return null;\n};","'use strict'\n\n/**\n * \"Shallow freezes\" an object to render it immutable.\n * Uses `Object.freeze` if available,\n * otherwise the immutability is only in the type.\n *\n * Is used to create \"enum like\" objects.\n *\n * @template T\n * @param {T} object the object to freeze\n * @param {Pick = Object} oc `Object` by default,\n * \t\t\t\tallows to inject custom object constructor for tests\n * @returns {Readonly}\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze\n */\nfunction freeze(object, oc) {\n\tif (oc === undefined) {\n\t\toc = Object\n\t}\n\treturn oc && typeof oc.freeze === 'function' ? oc.freeze(object) : object\n}\n\n/**\n * All mime types that are allowed as input to `DOMParser.parseFromString`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#Argument02 MDN\n * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#domparsersupportedtype WHATWG HTML Spec\n * @see DOMParser.prototype.parseFromString\n */\nvar MIME_TYPE = freeze({\n\t/**\n\t * `text/html`, the only mime type that triggers treating an XML document as HTML.\n\t *\n\t * @see DOMParser.SupportedType.isHTML\n\t * @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration\n\t * @see https://en.wikipedia.org/wiki/HTML Wikipedia\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN\n\t * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring WHATWG HTML Spec\n\t */\n\tHTML: 'text/html',\n\n\t/**\n\t * Helper method to check a mime type if it indicates an HTML document\n\t *\n\t * @param {string} [value]\n\t * @returns {boolean}\n\t *\n\t * @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration\n\t * @see https://en.wikipedia.org/wiki/HTML Wikipedia\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN\n\t * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring \t */\n\tisHTML: function (value) {\n\t\treturn value === MIME_TYPE.HTML\n\t},\n\n\t/**\n\t * `application/xml`, the standard mime type for XML documents.\n\t *\n\t * @see https://www.iana.org/assignments/media-types/application/xml IANA MimeType registration\n\t * @see https://tools.ietf.org/html/rfc7303#section-9.1 RFC 7303\n\t * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia\n\t */\n\tXML_APPLICATION: 'application/xml',\n\n\t/**\n\t * `text/html`, an alias for `application/xml`.\n\t *\n\t * @see https://tools.ietf.org/html/rfc7303#section-9.2 RFC 7303\n\t * @see https://www.iana.org/assignments/media-types/text/xml IANA MimeType registration\n\t * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia\n\t */\n\tXML_TEXT: 'text/xml',\n\n\t/**\n\t * `application/xhtml+xml`, indicates an XML document that has the default HTML namespace,\n\t * but is parsed as an XML document.\n\t *\n\t * @see https://www.iana.org/assignments/media-types/application/xhtml+xml IANA MimeType registration\n\t * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument WHATWG DOM Spec\n\t * @see https://en.wikipedia.org/wiki/XHTML Wikipedia\n\t */\n\tXML_XHTML_APPLICATION: 'application/xhtml+xml',\n\n\t/**\n\t * `image/svg+xml`,\n\t *\n\t * @see https://www.iana.org/assignments/media-types/image/svg+xml IANA MimeType registration\n\t * @see https://www.w3.org/TR/SVG11/ W3C SVG 1.1\n\t * @see https://en.wikipedia.org/wiki/Scalable_Vector_Graphics Wikipedia\n\t */\n\tXML_SVG_IMAGE: 'image/svg+xml',\n})\n\n/**\n * Namespaces that are used in this code base.\n *\n * @see http://www.w3.org/TR/REC-xml-names\n */\nvar NAMESPACE = freeze({\n\t/**\n\t * The XHTML namespace.\n\t *\n\t * @see http://www.w3.org/1999/xhtml\n\t */\n\tHTML: 'http://www.w3.org/1999/xhtml',\n\n\t/**\n\t * Checks if `uri` equals `NAMESPACE.HTML`.\n\t *\n\t * @param {string} [uri]\n\t *\n\t * @see NAMESPACE.HTML\n\t */\n\tisHTML: function (uri) {\n\t\treturn uri === NAMESPACE.HTML\n\t},\n\n\t/**\n\t * The SVG namespace.\n\t *\n\t * @see http://www.w3.org/2000/svg\n\t */\n\tSVG: 'http://www.w3.org/2000/svg',\n\n\t/**\n\t * The `xml:` namespace.\n\t *\n\t * @see http://www.w3.org/XML/1998/namespace\n\t */\n\tXML: 'http://www.w3.org/XML/1998/namespace',\n\n\t/**\n\t * The `xmlns:` namespace\n\t *\n\t * @see https://www.w3.org/2000/xmlns/\n\t */\n\tXMLNS: 'http://www.w3.org/2000/xmlns/',\n})\n\nexports.freeze = freeze;\nexports.MIME_TYPE = MIME_TYPE;\nexports.NAMESPACE = NAMESPACE;\n","var conventions = require(\"./conventions\");\n\nvar NAMESPACE = conventions.NAMESPACE;\n\n/**\n * A prerequisite for `[].filter`, to drop elements that are empty\n * @param {string} input\n * @returns {boolean}\n */\nfunction notEmptyString (input) {\n\treturn input !== ''\n}\n/**\n * @see https://infra.spec.whatwg.org/#split-on-ascii-whitespace\n * @see https://infra.spec.whatwg.org/#ascii-whitespace\n *\n * @param {string} input\n * @returns {string[]} (can be empty)\n */\nfunction splitOnASCIIWhitespace(input) {\n\t// U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, U+0020 SPACE\n\treturn input ? input.split(/[\\t\\n\\f\\r ]+/).filter(notEmptyString) : []\n}\n\n/**\n * Adds element as a key to current if it is not already present.\n *\n * @param {Record} current\n * @param {string} element\n * @returns {Record}\n */\nfunction orderedSetReducer (current, element) {\n\tif (!current.hasOwnProperty(element)) {\n\t\tcurrent[element] = true;\n\t}\n\treturn current;\n}\n\n/**\n * @see https://infra.spec.whatwg.org/#ordered-set\n * @param {string} input\n * @returns {string[]}\n */\nfunction toOrderedSet(input) {\n\tif (!input) return [];\n\tvar list = splitOnASCIIWhitespace(input);\n\treturn Object.keys(list.reduce(orderedSetReducer, {}))\n}\n\n/**\n * Uses `list.indexOf` to implement something like `Array.prototype.includes`,\n * which we can not rely on being available.\n *\n * @param {any[]} list\n * @returns {function(any): boolean}\n */\nfunction arrayIncludes (list) {\n\treturn function(element) {\n\t\treturn list && list.indexOf(element) !== -1;\n\t}\n}\n\nfunction copy(src,dest){\n\tfor(var p in src){\n\t\tdest[p] = src[p];\n\t}\n}\n\n/**\n^\\w+\\.prototype\\.([_\\w]+)\\s*=\\s*((?:.*\\{\\s*?[\\r\\n][\\s\\S]*?^})|\\S.*?(?=[;\\r\\n]));?\n^\\w+\\.prototype\\.([_\\w]+)\\s*=\\s*(\\S.*?(?=[;\\r\\n]));?\n */\nfunction _extends(Class,Super){\n\tvar pt = Class.prototype;\n\tif(!(pt instanceof Super)){\n\t\tfunction t(){};\n\t\tt.prototype = Super.prototype;\n\t\tt = new t();\n\t\tcopy(pt,t);\n\t\tClass.prototype = pt = t;\n\t}\n\tif(pt.constructor != Class){\n\t\tif(typeof Class != 'function'){\n\t\t\tconsole.error(\"unknown Class:\"+Class)\n\t\t}\n\t\tpt.constructor = Class\n\t}\n}\n\n// Node Types\nvar NodeType = {}\nvar ELEMENT_NODE = NodeType.ELEMENT_NODE = 1;\nvar ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE = 2;\nvar TEXT_NODE = NodeType.TEXT_NODE = 3;\nvar CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE = 4;\nvar ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE = 5;\nvar ENTITY_NODE = NodeType.ENTITY_NODE = 6;\nvar PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;\nvar COMMENT_NODE = NodeType.COMMENT_NODE = 8;\nvar DOCUMENT_NODE = NodeType.DOCUMENT_NODE = 9;\nvar DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE = 10;\nvar DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE = 11;\nvar NOTATION_NODE = NodeType.NOTATION_NODE = 12;\n\n// ExceptionCode\nvar ExceptionCode = {}\nvar ExceptionMessage = {};\nvar INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR = ((ExceptionMessage[1]=\"Index size error\"),1);\nvar DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR = ((ExceptionMessage[2]=\"DOMString size error\"),2);\nvar HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR = ((ExceptionMessage[3]=\"Hierarchy request error\"),3);\nvar WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR = ((ExceptionMessage[4]=\"Wrong document\"),4);\nvar INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR = ((ExceptionMessage[5]=\"Invalid character\"),5);\nvar NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR = ((ExceptionMessage[6]=\"No data allowed\"),6);\nvar NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]=\"No modification allowed\"),7);\nvar NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR = ((ExceptionMessage[8]=\"Not found\"),8);\nvar NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR = ((ExceptionMessage[9]=\"Not supported\"),9);\nvar INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR = ((ExceptionMessage[10]=\"Attribute in use\"),10);\n//level2\nvar INVALID_STATE_ERR \t= ExceptionCode.INVALID_STATE_ERR \t= ((ExceptionMessage[11]=\"Invalid state\"),11);\nvar SYNTAX_ERR \t= ExceptionCode.SYNTAX_ERR \t= ((ExceptionMessage[12]=\"Syntax error\"),12);\nvar INVALID_MODIFICATION_ERR \t= ExceptionCode.INVALID_MODIFICATION_ERR \t= ((ExceptionMessage[13]=\"Invalid modification\"),13);\nvar NAMESPACE_ERR \t= ExceptionCode.NAMESPACE_ERR \t= ((ExceptionMessage[14]=\"Invalid namespace\"),14);\nvar INVALID_ACCESS_ERR \t= ExceptionCode.INVALID_ACCESS_ERR \t= ((ExceptionMessage[15]=\"Invalid access\"),15);\n\n/**\n * DOM Level 2\n * Object DOMException\n * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html\n * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html\n */\nfunction DOMException(code, message) {\n\tif(message instanceof Error){\n\t\tvar error = message;\n\t}else{\n\t\terror = this;\n\t\tError.call(this, ExceptionMessage[code]);\n\t\tthis.message = ExceptionMessage[code];\n\t\tif(Error.captureStackTrace) Error.captureStackTrace(this, DOMException);\n\t}\n\terror.code = code;\n\tif(message) this.message = this.message + \": \" + message;\n\treturn error;\n};\nDOMException.prototype = Error.prototype;\ncopy(ExceptionCode,DOMException)\n\n/**\n * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177\n * The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live.\n * The items in the NodeList are accessible via an integral index, starting from 0.\n */\nfunction NodeList() {\n};\nNodeList.prototype = {\n\t/**\n\t * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.\n\t * @standard level1\n\t */\n\tlength:0, \n\t/**\n\t * Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null.\n\t * @standard level1\n\t * @param index unsigned long \n\t * Index into the collection.\n\t * @return Node\n\t * \tThe node at the indexth position in the NodeList, or null if that is not a valid index. \n\t */\n\titem: function(index) {\n\t\treturn this[index] || null;\n\t},\n\ttoString:function(isHTML,nodeFilter){\n\t\tfor(var buf = [], i = 0;i=0){\n\t\tvar lastIndex = list.length-1\n\t\twhile(i0 || key == 'xmlns'){\n//\t\t\treturn null;\n//\t\t}\n\t\t//console.log()\n\t\tvar i = this.length;\n\t\twhile(i--){\n\t\t\tvar attr = this[i];\n\t\t\t//console.log(attr.nodeName,key)\n\t\t\tif(attr.nodeName == key){\n\t\t\t\treturn attr;\n\t\t\t}\n\t\t}\n\t},\n\tsetNamedItem: function(attr) {\n\t\tvar el = attr.ownerElement;\n\t\tif(el && el!=this._ownerElement){\n\t\t\tthrow new DOMException(INUSE_ATTRIBUTE_ERR);\n\t\t}\n\t\tvar oldAttr = this.getNamedItem(attr.nodeName);\n\t\t_addNamedNode(this._ownerElement,this,attr,oldAttr);\n\t\treturn oldAttr;\n\t},\n\t/* returns Node */\n\tsetNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR\n\t\tvar el = attr.ownerElement, oldAttr;\n\t\tif(el && el!=this._ownerElement){\n\t\t\tthrow new DOMException(INUSE_ATTRIBUTE_ERR);\n\t\t}\n\t\toldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName);\n\t\t_addNamedNode(this._ownerElement,this,attr,oldAttr);\n\t\treturn oldAttr;\n\t},\n\n\t/* returns Node */\n\tremoveNamedItem: function(key) {\n\t\tvar attr = this.getNamedItem(key);\n\t\t_removeNamedNode(this._ownerElement,this,attr);\n\t\treturn attr;\n\t\t\n\t\t\n\t},// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR\n\t\n\t//for level2\n\tremoveNamedItemNS:function(namespaceURI,localName){\n\t\tvar attr = this.getNamedItemNS(namespaceURI,localName);\n\t\t_removeNamedNode(this._ownerElement,this,attr);\n\t\treturn attr;\n\t},\n\tgetNamedItemNS: function(namespaceURI, localName) {\n\t\tvar i = this.length;\n\t\twhile(i--){\n\t\t\tvar node = this[i];\n\t\t\tif(node.localName == localName && node.namespaceURI == namespaceURI){\n\t\t\t\treturn node;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n};\n\n/**\n * The DOMImplementation interface represents an object providing methods\n * which are not dependent on any particular document.\n * Such an object is returned by the `Document.implementation` property.\n *\n * __The individual methods describe the differences compared to the specs.__\n *\n * @constructor\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation MDN\n * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490 DOM Level 1 Core (Initial)\n * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-102161490 DOM Level 2 Core\n * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-102161490 DOM Level 3 Core\n * @see https://dom.spec.whatwg.org/#domimplementation DOM Living Standard\n */\nfunction DOMImplementation() {\n}\n\nDOMImplementation.prototype = {\n\t/**\n\t * The DOMImplementation.hasFeature() method returns a Boolean flag indicating if a given feature is supported.\n\t * The different implementations fairly diverged in what kind of features were reported.\n\t * The latest version of the spec settled to force this method to always return true, where the functionality was accurate and in use.\n\t *\n\t * @deprecated It is deprecated and modern browsers return true in all cases.\n\t *\n\t * @param {string} feature\n\t * @param {string} [version]\n\t * @returns {boolean} always true\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/hasFeature MDN\n\t * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-5CED94D7 DOM Level 1 Core\n\t * @see https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature DOM Living Standard\n\t */\n\thasFeature: function(feature, version) {\n\t\t\treturn true;\n\t},\n\t/**\n\t * Creates an XML Document object of the specified type with its document element.\n\t *\n\t * __It behaves slightly different from the description in the living standard__:\n\t * - There is no interface/class `XMLDocument`, it returns a `Document` instance.\n\t * - `contentType`, `encoding`, `mode`, `origin`, `url` fields are currently not declared.\n\t * - this implementation is not validating names or qualified names\n\t * (when parsing XML strings, the SAX parser takes care of that)\n\t *\n\t * @param {string|null} namespaceURI\n\t * @param {string} qualifiedName\n\t * @param {DocumentType=null} doctype\n\t * @returns {Document}\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocument MDN\n\t * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocument DOM Level 2 Core (initial)\n\t * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument DOM Level 2 Core\n\t *\n\t * @see https://dom.spec.whatwg.org/#validate-and-extract DOM: Validate and extract\n\t * @see https://www.w3.org/TR/xml/#NT-NameStartChar XML Spec: Names\n\t * @see https://www.w3.org/TR/xml-names/#ns-qualnames XML Namespaces: Qualified names\n\t */\n\tcreateDocument: function(namespaceURI, qualifiedName, doctype){\n\t\tvar doc = new Document();\n\t\tdoc.implementation = this;\n\t\tdoc.childNodes = new NodeList();\n\t\tdoc.doctype = doctype || null;\n\t\tif (doctype){\n\t\t\tdoc.appendChild(doctype);\n\t\t}\n\t\tif (qualifiedName){\n\t\t\tvar root = doc.createElementNS(namespaceURI, qualifiedName);\n\t\t\tdoc.appendChild(root);\n\t\t}\n\t\treturn doc;\n\t},\n\t/**\n\t * Returns a doctype, with the given `qualifiedName`, `publicId`, and `systemId`.\n\t *\n\t * __This behavior is slightly different from the in the specs__:\n\t * - this implementation is not validating names or qualified names\n\t * (when parsing XML strings, the SAX parser takes care of that)\n\t *\n\t * @param {string} qualifiedName\n\t * @param {string} [publicId]\n\t * @param {string} [systemId]\n\t * @returns {DocumentType} which can either be used with `DOMImplementation.createDocument` upon document creation\n\t * \t\t\t\t or can be put into the document via methods like `Node.insertBefore()` or `Node.replaceChild()`\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocumentType MDN\n\t * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocType DOM Level 2 Core\n\t * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype DOM Living Standard\n\t *\n\t * @see https://dom.spec.whatwg.org/#validate-and-extract DOM: Validate and extract\n\t * @see https://www.w3.org/TR/xml/#NT-NameStartChar XML Spec: Names\n\t * @see https://www.w3.org/TR/xml-names/#ns-qualnames XML Namespaces: Qualified names\n\t */\n\tcreateDocumentType: function(qualifiedName, publicId, systemId){\n\t\tvar node = new DocumentType();\n\t\tnode.name = qualifiedName;\n\t\tnode.nodeName = qualifiedName;\n\t\tnode.publicId = publicId || '';\n\t\tnode.systemId = systemId || '';\n\n\t\treturn node;\n\t}\n};\n\n\n/**\n * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247\n */\n\nfunction Node() {\n};\n\nNode.prototype = {\n\tfirstChild : null,\n\tlastChild : null,\n\tpreviousSibling : null,\n\tnextSibling : null,\n\tattributes : null,\n\tparentNode : null,\n\tchildNodes : null,\n\townerDocument : null,\n\tnodeValue : null,\n\tnamespaceURI : null,\n\tprefix : null,\n\tlocalName : null,\n\t// Modified in DOM Level 2:\n\tinsertBefore:function(newChild, refChild){//raises \n\t\treturn _insertBefore(this,newChild,refChild);\n\t},\n\treplaceChild:function(newChild, oldChild){//raises \n\t\tthis.insertBefore(newChild,oldChild);\n\t\tif(oldChild){\n\t\t\tthis.removeChild(oldChild);\n\t\t}\n\t},\n\tremoveChild:function(oldChild){\n\t\treturn _removeChild(this,oldChild);\n\t},\n\tappendChild:function(newChild){\n\t\treturn this.insertBefore(newChild,null);\n\t},\n\thasChildNodes:function(){\n\t\treturn this.firstChild != null;\n\t},\n\tcloneNode:function(deep){\n\t\treturn cloneNode(this.ownerDocument||this,this,deep);\n\t},\n\t// Modified in DOM Level 2:\n\tnormalize:function(){\n\t\tvar child = this.firstChild;\n\t\twhile(child){\n\t\t\tvar next = child.nextSibling;\n\t\t\tif(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){\n\t\t\t\tthis.removeChild(next);\n\t\t\t\tchild.appendData(next.data);\n\t\t\t}else{\n\t\t\t\tchild.normalize();\n\t\t\t\tchild = next;\n\t\t\t}\n\t\t}\n\t},\n \t// Introduced in DOM Level 2:\n\tisSupported:function(feature, version){\n\t\treturn this.ownerDocument.implementation.hasFeature(feature,version);\n\t},\n // Introduced in DOM Level 2:\n hasAttributes:function(){\n \treturn this.attributes.length>0;\n },\n\t/**\n\t * Look up the prefix associated to the given namespace URI, starting from this node.\n\t * **The default namespace declarations are ignored by this method.**\n\t * See Namespace Prefix Lookup for details on the algorithm used by this method.\n\t *\n\t * _Note: The implementation seems to be incomplete when compared to the algorithm described in the specs._\n\t *\n\t * @param {string | null} namespaceURI\n\t * @returns {string | null}\n\t * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespacePrefix\n\t * @see https://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespacePrefixAlgo\n\t * @see https://dom.spec.whatwg.org/#dom-node-lookupprefix\n\t * @see https://github.com/xmldom/xmldom/issues/322\n\t */\n lookupPrefix:function(namespaceURI){\n \tvar el = this;\n \twhile(el){\n \t\tvar map = el._nsMap;\n \t\t//console.dir(map)\n \t\tif(map){\n \t\t\tfor(var n in map){\n \t\t\t\tif(map[n] == namespaceURI){\n \t\t\t\t\treturn n;\n \t\t\t\t}\n \t\t\t}\n \t\t}\n \t\tel = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;\n \t}\n \treturn null;\n },\n // Introduced in DOM Level 3:\n lookupNamespaceURI:function(prefix){\n \tvar el = this;\n \twhile(el){\n \t\tvar map = el._nsMap;\n \t\t//console.dir(map)\n \t\tif(map){\n \t\t\tif(prefix in map){\n \t\t\t\treturn map[prefix] ;\n \t\t\t}\n \t\t}\n \t\tel = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;\n \t}\n \treturn null;\n },\n // Introduced in DOM Level 3:\n isDefaultNamespace:function(namespaceURI){\n \tvar prefix = this.lookupPrefix(namespaceURI);\n \treturn prefix == null;\n }\n};\n\n\nfunction _xmlEncoder(c){\n\treturn c == '<' && '<' ||\n c == '>' && '>' ||\n c == '&' && '&' ||\n c == '\"' && '"' ||\n '&#'+c.charCodeAt()+';'\n}\n\n\ncopy(NodeType,Node);\ncopy(NodeType,Node.prototype);\n\n/**\n * @param callback return true for continue,false for break\n * @return boolean true: break visit;\n */\nfunction _visitNode(node,callback){\n\tif(callback(node)){\n\t\treturn true;\n\t}\n\tif(node = node.firstChild){\n\t\tdo{\n\t\t\tif(_visitNode(node,callback)){return true}\n }while(node=node.nextSibling)\n }\n}\n\n\n\nfunction Document(){\n}\n\nfunction _onAddAttribute(doc,el,newAttr){\n\tdoc && doc._inc++;\n\tvar ns = newAttr.namespaceURI ;\n\tif(ns === NAMESPACE.XMLNS){\n\t\t//update namespace\n\t\tel._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value\n\t}\n}\n\nfunction _onRemoveAttribute(doc,el,newAttr,remove){\n\tdoc && doc._inc++;\n\tvar ns = newAttr.namespaceURI ;\n\tif(ns === NAMESPACE.XMLNS){\n\t\t//update namespace\n\t\tdelete el._nsMap[newAttr.prefix?newAttr.localName:'']\n\t}\n}\n\nfunction _onUpdateChild(doc,el,newChild){\n\tif(doc && doc._inc){\n\t\tdoc._inc++;\n\t\t//update childNodes\n\t\tvar cs = el.childNodes;\n\t\tif(newChild){\n\t\t\tcs[cs.length++] = newChild;\n\t\t}else{\n\t\t\t//console.log(1)\n\t\t\tvar child = el.firstChild;\n\t\t\tvar i = 0;\n\t\t\twhile(child){\n\t\t\t\tcs[i++] = child;\n\t\t\t\tchild =child.nextSibling;\n\t\t\t}\n\t\t\tcs.length = i;\n\t\t}\n\t}\n}\n\n/**\n * attributes;\n * children;\n * \n * writeable properties:\n * nodeValue,Attr:value,CharacterData:data\n * prefix\n */\nfunction _removeChild(parentNode,child){\n\tvar previous = child.previousSibling;\n\tvar next = child.nextSibling;\n\tif(previous){\n\t\tprevious.nextSibling = next;\n\t}else{\n\t\tparentNode.firstChild = next\n\t}\n\tif(next){\n\t\tnext.previousSibling = previous;\n\t}else{\n\t\tparentNode.lastChild = previous;\n\t}\n\t_onUpdateChild(parentNode.ownerDocument,parentNode);\n\treturn child;\n}\n/**\n * preformance key(refChild == null)\n */\nfunction _insertBefore(parentNode,newChild,nextChild){\n\tvar cp = newChild.parentNode;\n\tif(cp){\n\t\tcp.removeChild(newChild);//remove and update\n\t}\n\tif(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){\n\t\tvar newFirst = newChild.firstChild;\n\t\tif (newFirst == null) {\n\t\t\treturn newChild;\n\t\t}\n\t\tvar newLast = newChild.lastChild;\n\t}else{\n\t\tnewFirst = newLast = newChild;\n\t}\n\tvar pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;\n\n\tnewFirst.previousSibling = pre;\n\tnewLast.nextSibling = nextChild;\n\t\n\t\n\tif(pre){\n\t\tpre.nextSibling = newFirst;\n\t}else{\n\t\tparentNode.firstChild = newFirst;\n\t}\n\tif(nextChild == null){\n\t\tparentNode.lastChild = newLast;\n\t}else{\n\t\tnextChild.previousSibling = newLast;\n\t}\n\tdo{\n\t\tnewFirst.parentNode = parentNode;\n\t}while(newFirst !== newLast && (newFirst= newFirst.nextSibling))\n\t_onUpdateChild(parentNode.ownerDocument||parentNode,parentNode);\n\t//console.log(parentNode.lastChild.nextSibling == null)\n\tif (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {\n\t\tnewChild.firstChild = newChild.lastChild = null;\n\t}\n\treturn newChild;\n}\nfunction _appendSingleChild(parentNode,newChild){\n\tvar cp = newChild.parentNode;\n\tif(cp){\n\t\tvar pre = parentNode.lastChild;\n\t\tcp.removeChild(newChild);//remove and update\n\t\tvar pre = parentNode.lastChild;\n\t}\n\tvar pre = parentNode.lastChild;\n\tnewChild.parentNode = parentNode;\n\tnewChild.previousSibling = pre;\n\tnewChild.nextSibling = null;\n\tif(pre){\n\t\tpre.nextSibling = newChild;\n\t}else{\n\t\tparentNode.firstChild = newChild;\n\t}\n\tparentNode.lastChild = newChild;\n\t_onUpdateChild(parentNode.ownerDocument,parentNode,newChild);\n\treturn newChild;\n\t//console.log(\"__aa\",parentNode.lastChild.nextSibling == null)\n}\nDocument.prototype = {\n\t//implementation : null,\n\tnodeName : '#document',\n\tnodeType : DOCUMENT_NODE,\n\t/**\n\t * The DocumentType node of the document.\n\t *\n\t * @readonly\n\t * @type DocumentType\n\t */\n\tdoctype : null,\n\tdocumentElement : null,\n\t_inc : 1,\n\n\tinsertBefore : function(newChild, refChild){//raises\n\t\tif(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){\n\t\t\tvar child = newChild.firstChild;\n\t\t\twhile(child){\n\t\t\t\tvar next = child.nextSibling;\n\t\t\t\tthis.insertBefore(child,refChild);\n\t\t\t\tchild = next;\n\t\t\t}\n\t\t\treturn newChild;\n\t\t}\n\t\tif(this.documentElement == null && newChild.nodeType == ELEMENT_NODE){\n\t\t\tthis.documentElement = newChild;\n\t\t}\n\n\t\treturn _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild;\n\t},\n\tremoveChild : function(oldChild){\n\t\tif(this.documentElement == oldChild){\n\t\t\tthis.documentElement = null;\n\t\t}\n\t\treturn _removeChild(this,oldChild);\n\t},\n\t// Introduced in DOM Level 2:\n\timportNode : function(importedNode,deep){\n\t\treturn importNode(this,importedNode,deep);\n\t},\n\t// Introduced in DOM Level 2:\n\tgetElementById :\tfunction(id){\n\t\tvar rtv = null;\n\t\t_visitNode(this.documentElement,function(node){\n\t\t\tif(node.nodeType == ELEMENT_NODE){\n\t\t\t\tif(node.getAttribute('id') == id){\n\t\t\t\t\trtv = node;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\treturn rtv;\n\t},\n\n\t/**\n\t * The `getElementsByClassName` method of `Document` interface returns an array-like object\n\t * of all child elements which have **all** of the given class name(s).\n\t *\n\t * Returns an empty list if `classeNames` is an empty string or only contains HTML white space characters.\n\t *\n\t *\n\t * Warning: This is a live LiveNodeList.\n\t * Changes in the DOM will reflect in the array as the changes occur.\n\t * If an element selected by this array no longer qualifies for the selector,\n\t * it will automatically be removed. Be aware of this for iteration purposes.\n\t *\n\t * @param {string} classNames is a string representing the class name(s) to match; multiple class names are separated by (ASCII-)whitespace\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName\n\t * @see https://dom.spec.whatwg.org/#concept-getelementsbyclassname\n\t */\n\tgetElementsByClassName: function(classNames) {\n\t\tvar classNamesSet = toOrderedSet(classNames)\n\t\treturn new LiveNodeList(this, function(base) {\n\t\t\tvar ls = [];\n\t\t\tif (classNamesSet.length > 0) {\n\t\t\t\t_visitNode(base.documentElement, function(node) {\n\t\t\t\t\tif(node !== base && node.nodeType === ELEMENT_NODE) {\n\t\t\t\t\t\tvar nodeClassNames = node.getAttribute('class')\n\t\t\t\t\t\t// can be null if the attribute does not exist\n\t\t\t\t\t\tif (nodeClassNames) {\n\t\t\t\t\t\t\t// before splitting and iterating just compare them for the most common case\n\t\t\t\t\t\t\tvar matches = classNames === nodeClassNames;\n\t\t\t\t\t\t\tif (!matches) {\n\t\t\t\t\t\t\t\tvar nodeClassNamesSet = toOrderedSet(nodeClassNames)\n\t\t\t\t\t\t\t\tmatches = classNamesSet.every(arrayIncludes(nodeClassNamesSet))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(matches) {\n\t\t\t\t\t\t\t\tls.push(node);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn ls;\n\t\t});\n\t},\n\n\t//document factory method:\n\tcreateElement :\tfunction(tagName){\n\t\tvar node = new Element();\n\t\tnode.ownerDocument = this;\n\t\tnode.nodeName = tagName;\n\t\tnode.tagName = tagName;\n\t\tnode.localName = tagName;\n\t\tnode.childNodes = new NodeList();\n\t\tvar attrs\t= node.attributes = new NamedNodeMap();\n\t\tattrs._ownerElement = node;\n\t\treturn node;\n\t},\n\tcreateDocumentFragment :\tfunction(){\n\t\tvar node = new DocumentFragment();\n\t\tnode.ownerDocument = this;\n\t\tnode.childNodes = new NodeList();\n\t\treturn node;\n\t},\n\tcreateTextNode :\tfunction(data){\n\t\tvar node = new Text();\n\t\tnode.ownerDocument = this;\n\t\tnode.appendData(data)\n\t\treturn node;\n\t},\n\tcreateComment :\tfunction(data){\n\t\tvar node = new Comment();\n\t\tnode.ownerDocument = this;\n\t\tnode.appendData(data)\n\t\treturn node;\n\t},\n\tcreateCDATASection :\tfunction(data){\n\t\tvar node = new CDATASection();\n\t\tnode.ownerDocument = this;\n\t\tnode.appendData(data)\n\t\treturn node;\n\t},\n\tcreateProcessingInstruction :\tfunction(target,data){\n\t\tvar node = new ProcessingInstruction();\n\t\tnode.ownerDocument = this;\n\t\tnode.tagName = node.target = target;\n\t\tnode.nodeValue= node.data = data;\n\t\treturn node;\n\t},\n\tcreateAttribute :\tfunction(name){\n\t\tvar node = new Attr();\n\t\tnode.ownerDocument\t= this;\n\t\tnode.name = name;\n\t\tnode.nodeName\t= name;\n\t\tnode.localName = name;\n\t\tnode.specified = true;\n\t\treturn node;\n\t},\n\tcreateEntityReference :\tfunction(name){\n\t\tvar node = new EntityReference();\n\t\tnode.ownerDocument\t= this;\n\t\tnode.nodeName\t= name;\n\t\treturn node;\n\t},\n\t// Introduced in DOM Level 2:\n\tcreateElementNS :\tfunction(namespaceURI,qualifiedName){\n\t\tvar node = new Element();\n\t\tvar pl = qualifiedName.split(':');\n\t\tvar attrs\t= node.attributes = new NamedNodeMap();\n\t\tnode.childNodes = new NodeList();\n\t\tnode.ownerDocument = this;\n\t\tnode.nodeName = qualifiedName;\n\t\tnode.tagName = qualifiedName;\n\t\tnode.namespaceURI = namespaceURI;\n\t\tif(pl.length == 2){\n\t\t\tnode.prefix = pl[0];\n\t\t\tnode.localName = pl[1];\n\t\t}else{\n\t\t\t//el.prefix = null;\n\t\t\tnode.localName = qualifiedName;\n\t\t}\n\t\tattrs._ownerElement = node;\n\t\treturn node;\n\t},\n\t// Introduced in DOM Level 2:\n\tcreateAttributeNS :\tfunction(namespaceURI,qualifiedName){\n\t\tvar node = new Attr();\n\t\tvar pl = qualifiedName.split(':');\n\t\tnode.ownerDocument = this;\n\t\tnode.nodeName = qualifiedName;\n\t\tnode.name = qualifiedName;\n\t\tnode.namespaceURI = namespaceURI;\n\t\tnode.specified = true;\n\t\tif(pl.length == 2){\n\t\t\tnode.prefix = pl[0];\n\t\t\tnode.localName = pl[1];\n\t\t}else{\n\t\t\t//el.prefix = null;\n\t\t\tnode.localName = qualifiedName;\n\t\t}\n\t\treturn node;\n\t}\n};\n_extends(Document,Node);\n\n\nfunction Element() {\n\tthis._nsMap = {};\n};\nElement.prototype = {\n\tnodeType : ELEMENT_NODE,\n\thasAttribute : function(name){\n\t\treturn this.getAttributeNode(name)!=null;\n\t},\n\tgetAttribute : function(name){\n\t\tvar attr = this.getAttributeNode(name);\n\t\treturn attr && attr.value || '';\n\t},\n\tgetAttributeNode : function(name){\n\t\treturn this.attributes.getNamedItem(name);\n\t},\n\tsetAttribute : function(name, value){\n\t\tvar attr = this.ownerDocument.createAttribute(name);\n\t\tattr.value = attr.nodeValue = \"\" + value;\n\t\tthis.setAttributeNode(attr)\n\t},\n\tremoveAttribute : function(name){\n\t\tvar attr = this.getAttributeNode(name)\n\t\tattr && this.removeAttributeNode(attr);\n\t},\n\t\n\t//four real opeartion method\n\tappendChild:function(newChild){\n\t\tif(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){\n\t\t\treturn this.insertBefore(newChild,null);\n\t\t}else{\n\t\t\treturn _appendSingleChild(this,newChild);\n\t\t}\n\t},\n\tsetAttributeNode : function(newAttr){\n\t\treturn this.attributes.setNamedItem(newAttr);\n\t},\n\tsetAttributeNodeNS : function(newAttr){\n\t\treturn this.attributes.setNamedItemNS(newAttr);\n\t},\n\tremoveAttributeNode : function(oldAttr){\n\t\t//console.log(this == oldAttr.ownerElement)\n\t\treturn this.attributes.removeNamedItem(oldAttr.nodeName);\n\t},\n\t//get real attribute name,and remove it by removeAttributeNode\n\tremoveAttributeNS : function(namespaceURI, localName){\n\t\tvar old = this.getAttributeNodeNS(namespaceURI, localName);\n\t\told && this.removeAttributeNode(old);\n\t},\n\t\n\thasAttributeNS : function(namespaceURI, localName){\n\t\treturn this.getAttributeNodeNS(namespaceURI, localName)!=null;\n\t},\n\tgetAttributeNS : function(namespaceURI, localName){\n\t\tvar attr = this.getAttributeNodeNS(namespaceURI, localName);\n\t\treturn attr && attr.value || '';\n\t},\n\tsetAttributeNS : function(namespaceURI, qualifiedName, value){\n\t\tvar attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);\n\t\tattr.value = attr.nodeValue = \"\" + value;\n\t\tthis.setAttributeNode(attr)\n\t},\n\tgetAttributeNodeNS : function(namespaceURI, localName){\n\t\treturn this.attributes.getNamedItemNS(namespaceURI, localName);\n\t},\n\t\n\tgetElementsByTagName : function(tagName){\n\t\treturn new LiveNodeList(this,function(base){\n\t\t\tvar ls = [];\n\t\t\t_visitNode(base,function(node){\n\t\t\t\tif(node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)){\n\t\t\t\t\tls.push(node);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn ls;\n\t\t});\n\t},\n\tgetElementsByTagNameNS : function(namespaceURI, localName){\n\t\treturn new LiveNodeList(this,function(base){\n\t\t\tvar ls = [];\n\t\t\t_visitNode(base,function(node){\n\t\t\t\tif(node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)){\n\t\t\t\t\tls.push(node);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn ls;\n\t\t\t\n\t\t});\n\t}\n};\nDocument.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;\nDocument.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;\n\n\n_extends(Element,Node);\nfunction Attr() {\n};\nAttr.prototype.nodeType = ATTRIBUTE_NODE;\n_extends(Attr,Node);\n\n\nfunction CharacterData() {\n};\nCharacterData.prototype = {\n\tdata : '',\n\tsubstringData : function(offset, count) {\n\t\treturn this.data.substring(offset, offset+count);\n\t},\n\tappendData: function(text) {\n\t\ttext = this.data+text;\n\t\tthis.nodeValue = this.data = text;\n\t\tthis.length = text.length;\n\t},\n\tinsertData: function(offset,text) {\n\t\tthis.replaceData(offset,0,text);\n\t\n\t},\n\tappendChild:function(newChild){\n\t\tthrow new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR])\n\t},\n\tdeleteData: function(offset, count) {\n\t\tthis.replaceData(offset,count,\"\");\n\t},\n\treplaceData: function(offset, count, text) {\n\t\tvar start = this.data.substring(0,offset);\n\t\tvar end = this.data.substring(offset+count);\n\t\ttext = start + text + end;\n\t\tthis.nodeValue = this.data = text;\n\t\tthis.length = text.length;\n\t}\n}\n_extends(CharacterData,Node);\nfunction Text() {\n};\nText.prototype = {\n\tnodeName : \"#text\",\n\tnodeType : TEXT_NODE,\n\tsplitText : function(offset) {\n\t\tvar text = this.data;\n\t\tvar newText = text.substring(offset);\n\t\ttext = text.substring(0, offset);\n\t\tthis.data = this.nodeValue = text;\n\t\tthis.length = text.length;\n\t\tvar newNode = this.ownerDocument.createTextNode(newText);\n\t\tif(this.parentNode){\n\t\t\tthis.parentNode.insertBefore(newNode, this.nextSibling);\n\t\t}\n\t\treturn newNode;\n\t}\n}\n_extends(Text,CharacterData);\nfunction Comment() {\n};\nComment.prototype = {\n\tnodeName : \"#comment\",\n\tnodeType : COMMENT_NODE\n}\n_extends(Comment,CharacterData);\n\nfunction CDATASection() {\n};\nCDATASection.prototype = {\n\tnodeName : \"#cdata-section\",\n\tnodeType : CDATA_SECTION_NODE\n}\n_extends(CDATASection,CharacterData);\n\n\nfunction DocumentType() {\n};\nDocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;\n_extends(DocumentType,Node);\n\nfunction Notation() {\n};\nNotation.prototype.nodeType = NOTATION_NODE;\n_extends(Notation,Node);\n\nfunction Entity() {\n};\nEntity.prototype.nodeType = ENTITY_NODE;\n_extends(Entity,Node);\n\nfunction EntityReference() {\n};\nEntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;\n_extends(EntityReference,Node);\n\nfunction DocumentFragment() {\n};\nDocumentFragment.prototype.nodeName =\t\"#document-fragment\";\nDocumentFragment.prototype.nodeType =\tDOCUMENT_FRAGMENT_NODE;\n_extends(DocumentFragment,Node);\n\n\nfunction ProcessingInstruction() {\n}\nProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;\n_extends(ProcessingInstruction,Node);\nfunction XMLSerializer(){}\nXMLSerializer.prototype.serializeToString = function(node,isHtml,nodeFilter){\n\treturn nodeSerializeToString.call(node,isHtml,nodeFilter);\n}\nNode.prototype.toString = nodeSerializeToString;\nfunction nodeSerializeToString(isHtml,nodeFilter){\n\tvar buf = [];\n\tvar refNode = this.nodeType == 9 && this.documentElement || this;\n\tvar prefix = refNode.prefix;\n\tvar uri = refNode.namespaceURI;\n\t\n\tif(uri && prefix == null){\n\t\t//console.log(prefix)\n\t\tvar prefix = refNode.lookupPrefix(uri);\n\t\tif(prefix == null){\n\t\t\t//isHTML = true;\n\t\t\tvar visibleNamespaces=[\n\t\t\t{namespace:uri,prefix:null}\n\t\t\t//{namespace:uri,prefix:''}\n\t\t\t]\n\t\t}\n\t}\n\tserializeToString(this,buf,isHtml,nodeFilter,visibleNamespaces);\n\t//console.log('###',this.nodeType,uri,prefix,buf.join(''))\n\treturn buf.join('');\n}\n\nfunction needNamespaceDefine(node, isHTML, visibleNamespaces) {\n\tvar prefix = node.prefix || '';\n\tvar uri = node.namespaceURI;\n\t// According to [Namespaces in XML 1.0](https://www.w3.org/TR/REC-xml-names/#ns-using) ,\n\t// and more specifically https://www.w3.org/TR/REC-xml-names/#nsc-NoPrefixUndecl :\n\t// > In a namespace declaration for a prefix [...], the attribute value MUST NOT be empty.\n\t// in a similar manner [Namespaces in XML 1.1](https://www.w3.org/TR/xml-names11/#ns-using)\n\t// and more specifically https://www.w3.org/TR/xml-names11/#nsc-NSDeclared :\n\t// > [...] Furthermore, the attribute value [...] must not be an empty string.\n\t// so serializing empty namespace value like xmlns:ds=\"\" would produce an invalid XML document.\n\tif (!uri) {\n\t\treturn false;\n\t}\n\tif (prefix === \"xml\" && uri === NAMESPACE.XML || uri === NAMESPACE.XMLNS) {\n\t\treturn false;\n\t}\n\t\n\tvar i = visibleNamespaces.length \n\twhile (i--) {\n\t\tvar ns = visibleNamespaces[i];\n\t\t// get namespace prefix\n\t\tif (ns.prefix === prefix) {\n\t\t\treturn ns.namespace !== uri;\n\t\t}\n\t}\n\treturn true;\n}\n/**\n * Well-formed constraint: No < in Attribute Values\n * The replacement text of any entity referred to directly or indirectly in an attribute value must not contain a <.\n * @see https://www.w3.org/TR/xml/#CleanAttrVals\n * @see https://www.w3.org/TR/xml/#NT-AttValue\n */\nfunction addSerializedAttribute(buf, qualifiedName, value) {\n\tbuf.push(' ', qualifiedName, '=\"', value.replace(/[<&\"]/g,_xmlEncoder), '\"')\n}\n\nfunction serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){\n\tif (!visibleNamespaces) {\n\t\tvisibleNamespaces = [];\n\t}\n\n\tif(nodeFilter){\n\t\tnode = nodeFilter(node);\n\t\tif(node){\n\t\t\tif(typeof node == 'string'){\n\t\t\t\tbuf.push(node);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}else{\n\t\t\treturn;\n\t\t}\n\t\t//buf.sort.apply(attrs, attributeSorter);\n\t}\n\n\tswitch(node.nodeType){\n\tcase ELEMENT_NODE:\n\t\tvar attrs = node.attributes;\n\t\tvar len = attrs.length;\n\t\tvar child = node.firstChild;\n\t\tvar nodeName = node.tagName;\n\t\t\n\t\tisHTML = NAMESPACE.isHTML(node.namespaceURI) || isHTML\n\n\t\tvar prefixedNodeName = nodeName\n\t\tif (!isHTML && !node.prefix && node.namespaceURI) {\n\t\t\tvar defaultNS\n\t\t\t// lookup current default ns from `xmlns` attribute\n\t\t\tfor (var ai = 0; ai < attrs.length; ai++) {\n\t\t\t\tif (attrs.item(ai).name === 'xmlns') {\n\t\t\t\t\tdefaultNS = attrs.item(ai).value\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!defaultNS) {\n\t\t\t\t// lookup current default ns in visibleNamespaces\n\t\t\t\tfor (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {\n\t\t\t\t\tvar namespace = visibleNamespaces[nsi]\n\t\t\t\t\tif (namespace.prefix === '' && namespace.namespace === node.namespaceURI) {\n\t\t\t\t\t\tdefaultNS = namespace.namespace\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (defaultNS !== node.namespaceURI) {\n\t\t\t\tfor (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {\n\t\t\t\t\tvar namespace = visibleNamespaces[nsi]\n\t\t\t\t\tif (namespace.namespace === node.namespaceURI) {\n\t\t\t\t\t\tif (namespace.prefix) {\n\t\t\t\t\t\t\tprefixedNodeName = namespace.prefix + ':' + nodeName\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbuf.push('<', prefixedNodeName);\n\n\t\tfor(var i=0;i');\n\t\t\t//if is cdata child node\n\t\t\tif(isHTML && /^script$/i.test(nodeName)){\n\t\t\t\twhile(child){\n\t\t\t\t\tif(child.data){\n\t\t\t\t\t\tbuf.push(child.data);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tserializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());\n\t\t\t\t\t}\n\t\t\t\t\tchild = child.nextSibling;\n\t\t\t\t}\n\t\t\t}else\n\t\t\t{\n\t\t\t\twhile(child){\n\t\t\t\t\tserializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());\n\t\t\t\t\tchild = child.nextSibling;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf.push('');\n\t\t}else{\n\t\t\tbuf.push('/>');\n\t\t}\n\t\t// remove added visible namespaces\n\t\t//visibleNamespaces.length = startVisibleNamespaces;\n\t\treturn;\n\tcase DOCUMENT_NODE:\n\tcase DOCUMENT_FRAGMENT_NODE:\n\t\tvar child = node.firstChild;\n\t\twhile(child){\n\t\t\tserializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());\n\t\t\tchild = child.nextSibling;\n\t\t}\n\t\treturn;\n\tcase ATTRIBUTE_NODE:\n\t\treturn addSerializedAttribute(buf, node.name, node.value);\n\tcase TEXT_NODE:\n\t\t/**\n\t\t * The ampersand character (&) and the left angle bracket (<) must not appear in their literal form,\n\t\t * except when used as markup delimiters, or within a comment, a processing instruction, or a CDATA section.\n\t\t * If they are needed elsewhere, they must be escaped using either numeric character references or the strings\n\t\t * `&` and `<` respectively.\n\t\t * The right angle bracket (>) may be represented using the string \" > \", and must, for compatibility,\n\t\t * be escaped using either `>` or a character reference when it appears in the string `]]>` in content,\n\t\t * when that string is not marking the end of a CDATA section.\n\t\t *\n\t\t * In the content of elements, character data is any string of characters\n\t\t * which does not contain the start-delimiter of any markup\n\t\t * and does not include the CDATA-section-close delimiter, `]]>`.\n\t\t *\n\t\t * @see https://www.w3.org/TR/xml/#NT-CharData\n\t\t */\n\t\treturn buf.push(node.data\n\t\t\t.replace(/[<&]/g,_xmlEncoder)\n\t\t\t.replace(/]]>/g, ']]>')\n\t\t);\n\tcase CDATA_SECTION_NODE:\n\t\treturn buf.push( '');\n\tcase COMMENT_NODE:\n\t\treturn buf.push( \"\");\n\tcase DOCUMENT_TYPE_NODE:\n\t\tvar pubid = node.publicId;\n\t\tvar sysid = node.systemId;\n\t\tbuf.push('');\n\t\t}else if(sysid && sysid!='.'){\n\t\t\tbuf.push(' SYSTEM ', sysid, '>');\n\t\t}else{\n\t\t\tvar sub = node.internalSubset;\n\t\t\tif(sub){\n\t\t\t\tbuf.push(\" [\",sub,\"]\");\n\t\t\t}\n\t\t\tbuf.push(\">\");\n\t\t}\n\t\treturn;\n\tcase PROCESSING_INSTRUCTION_NODE:\n\t\treturn buf.push( \"\");\n\tcase ENTITY_REFERENCE_NODE:\n\t\treturn buf.push( '&',node.nodeName,';');\n\t//case ENTITY_NODE:\n\t//case NOTATION_NODE:\n\tdefault:\n\t\tbuf.push('??',node.nodeName);\n\t}\n}\nfunction importNode(doc,node,deep){\n\tvar node2;\n\tswitch (node.nodeType) {\n\tcase ELEMENT_NODE:\n\t\tnode2 = node.cloneNode(false);\n\t\tnode2.ownerDocument = doc;\n\t\t//var attrs = node2.attributes;\n\t\t//var len = attrs.length;\n\t\t//for(var i=0;i', lt:'<', quot:'\"'})\n\n/**\n * A map of currently 241 entities that are detected in an HTML document.\n * They contain all entries from `XML_ENTITIES`.\n *\n * @see XML_ENTITIES\n * @see DOMParser.parseFromString\n * @see DOMImplementation.prototype.createHTMLDocument\n * @see https://html.spec.whatwg.org/#named-character-references WHATWG HTML(5) Spec\n * @see https://www.w3.org/TR/xml-entity-names/ W3C XML Entity Names\n * @see https://www.w3.org/TR/html4/sgml/entities.html W3C HTML4/SGML\n * @see https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Character_entity_references_in_HTML Wikipedia (HTML)\n * @see https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Entities_representing_special_characters_in_XHTML Wikpedia (XHTML)\n */\nexports.HTML_ENTITIES = freeze({\n lt: '<',\n gt: '>',\n amp: '&',\n quot: '\"',\n apos: \"'\",\n Agrave: \"À\",\n Aacute: \"Á\",\n Acirc: \"Â\",\n Atilde: \"Ã\",\n Auml: \"Ä\",\n Aring: \"Å\",\n AElig: \"Æ\",\n Ccedil: \"Ç\",\n Egrave: \"È\",\n Eacute: \"É\",\n Ecirc: \"Ê\",\n Euml: \"Ë\",\n Igrave: \"Ì\",\n Iacute: \"Í\",\n Icirc: \"Î\",\n Iuml: \"Ï\",\n ETH: \"Ð\",\n Ntilde: \"Ñ\",\n Ograve: \"Ò\",\n Oacute: \"Ó\",\n Ocirc: \"Ô\",\n Otilde: \"Õ\",\n Ouml: \"Ö\",\n Oslash: \"Ø\",\n Ugrave: \"Ù\",\n Uacute: \"Ú\",\n Ucirc: \"Û\",\n Uuml: \"Ü\",\n Yacute: \"Ý\",\n THORN: \"Þ\",\n szlig: \"ß\",\n agrave: \"à\",\n aacute: \"á\",\n acirc: \"â\",\n atilde: \"ã\",\n auml: \"ä\",\n aring: \"å\",\n aelig: \"æ\",\n ccedil: \"ç\",\n egrave: \"è\",\n eacute: \"é\",\n ecirc: \"ê\",\n euml: \"ë\",\n igrave: \"ì\",\n iacute: \"í\",\n icirc: \"î\",\n iuml: \"ï\",\n eth: \"ð\",\n ntilde: \"ñ\",\n ograve: \"ò\",\n oacute: \"ó\",\n ocirc: \"ô\",\n otilde: \"õ\",\n ouml: \"ö\",\n oslash: \"ø\",\n ugrave: \"ù\",\n uacute: \"ú\",\n ucirc: \"û\",\n uuml: \"ü\",\n yacute: \"ý\",\n thorn: \"þ\",\n yuml: \"ÿ\",\n nbsp: \"\\u00a0\",\n iexcl: \"¡\",\n cent: \"¢\",\n pound: \"£\",\n curren: \"¤\",\n yen: \"¥\",\n brvbar: \"¦\",\n sect: \"§\",\n uml: \"¨\",\n copy: \"©\",\n ordf: \"ª\",\n laquo: \"«\",\n not: \"¬\",\n shy: \"­­\",\n reg: \"®\",\n macr: \"¯\",\n deg: \"°\",\n plusmn: \"±\",\n sup2: \"²\",\n sup3: \"³\",\n acute: \"´\",\n micro: \"µ\",\n para: \"¶\",\n middot: \"·\",\n cedil: \"¸\",\n sup1: \"¹\",\n ordm: \"º\",\n raquo: \"»\",\n frac14: \"¼\",\n frac12: \"½\",\n frac34: \"¾\",\n iquest: \"¿\",\n times: \"×\",\n divide: \"÷\",\n forall: \"∀\",\n part: \"∂\",\n exist: \"∃\",\n empty: \"∅\",\n nabla: \"∇\",\n isin: \"∈\",\n notin: \"∉\",\n ni: \"∋\",\n prod: \"∏\",\n sum: \"∑\",\n minus: \"−\",\n lowast: \"∗\",\n radic: \"√\",\n prop: \"∝\",\n infin: \"∞\",\n ang: \"∠\",\n and: \"∧\",\n or: \"∨\",\n cap: \"∩\",\n cup: \"∪\",\n 'int': \"∫\",\n there4: \"∴\",\n sim: \"∼\",\n cong: \"≅\",\n asymp: \"≈\",\n ne: \"≠\",\n equiv: \"≡\",\n le: \"≤\",\n ge: \"≥\",\n sub: \"⊂\",\n sup: \"⊃\",\n nsub: \"⊄\",\n sube: \"⊆\",\n supe: \"⊇\",\n oplus: \"⊕\",\n otimes: \"⊗\",\n perp: \"⊥\",\n sdot: \"⋅\",\n Alpha: \"Α\",\n Beta: \"Β\",\n Gamma: \"Γ\",\n Delta: \"Δ\",\n Epsilon: \"Ε\",\n Zeta: \"Ζ\",\n Eta: \"Η\",\n Theta: \"Θ\",\n Iota: \"Ι\",\n Kappa: \"Κ\",\n Lambda: \"Λ\",\n Mu: \"Μ\",\n Nu: \"Ν\",\n Xi: \"Ξ\",\n Omicron: \"Ο\",\n Pi: \"Π\",\n Rho: \"Ρ\",\n Sigma: \"Σ\",\n Tau: \"Τ\",\n Upsilon: \"Υ\",\n Phi: \"Φ\",\n Chi: \"Χ\",\n Psi: \"Ψ\",\n Omega: \"Ω\",\n alpha: \"α\",\n beta: \"β\",\n gamma: \"γ\",\n delta: \"δ\",\n epsilon: \"ε\",\n zeta: \"ζ\",\n eta: \"η\",\n theta: \"θ\",\n iota: \"ι\",\n kappa: \"κ\",\n lambda: \"λ\",\n mu: \"μ\",\n nu: \"ν\",\n xi: \"ξ\",\n omicron: \"ο\",\n pi: \"π\",\n rho: \"ρ\",\n sigmaf: \"ς\",\n sigma: \"σ\",\n tau: \"τ\",\n upsilon: \"υ\",\n phi: \"φ\",\n chi: \"χ\",\n psi: \"ψ\",\n omega: \"ω\",\n thetasym: \"ϑ\",\n upsih: \"ϒ\",\n piv: \"ϖ\",\n OElig: \"Œ\",\n oelig: \"œ\",\n Scaron: \"Š\",\n scaron: \"š\",\n Yuml: \"Ÿ\",\n fnof: \"ƒ\",\n circ: \"ˆ\",\n tilde: \"˜\",\n ensp: \" \",\n emsp: \" \",\n thinsp: \" \",\n zwnj: \"‌\",\n zwj: \"‍\",\n lrm: \"‎\",\n rlm: \"‏\",\n ndash: \"–\",\n mdash: \"—\",\n lsquo: \"‘\",\n rsquo: \"’\",\n sbquo: \"‚\",\n ldquo: \"“\",\n rdquo: \"”\",\n bdquo: \"„\",\n dagger: \"†\",\n Dagger: \"‡\",\n bull: \"•\",\n hellip: \"…\",\n permil: \"‰\",\n prime: \"′\",\n Prime: \"″\",\n lsaquo: \"‹\",\n rsaquo: \"›\",\n oline: \"‾\",\n euro: \"€\",\n trade: \"™\",\n larr: \"←\",\n uarr: \"↑\",\n rarr: \"→\",\n darr: \"↓\",\n harr: \"↔\",\n crarr: \"↵\",\n lceil: \"⌈\",\n rceil: \"⌉\",\n lfloor: \"⌊\",\n rfloor: \"⌋\",\n loz: \"◊\",\n spades: \"♠\",\n clubs: \"♣\",\n hearts: \"♥\",\n diams: \"♦\"\n});\n\n/**\n * @deprecated use `HTML_ENTITIES` instead\n * @see HTML_ENTITIES\n */\nexports.entityMap = exports.HTML_ENTITIES\n","var NAMESPACE = require(\"./conventions\").NAMESPACE;\n\n//[4] \tNameStartChar\t ::= \t\":\" | [A-Z] | \"_\" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]\n//[4a] \tNameChar\t ::= \tNameStartChar | \"-\" | \".\" | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]\n//[5] \tName\t ::= \tNameStartChar (NameChar)*\nvar nameStartChar = /[A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD]///\\u10000-\\uEFFFF\nvar nameChar = new RegExp(\"[\\\\-\\\\.0-9\"+nameStartChar.source.slice(1,-1)+\"\\\\u00B7\\\\u0300-\\\\u036F\\\\u203F-\\\\u2040]\");\nvar tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\\:'+nameStartChar.source+nameChar.source+'*)?$');\n//var tagNamePattern = /^[a-zA-Z_][\\w\\-\\.]*(?:\\:[a-zA-Z_][\\w\\-\\.]*)?$/\n//var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')\n\n//S_TAG,\tS_ATTR,\tS_EQ,\tS_ATTR_NOQUOT_VALUE\n//S_ATTR_SPACE,\tS_ATTR_END,\tS_TAG_SPACE, S_TAG_CLOSE\nvar S_TAG = 0;//tag name offerring\nvar S_ATTR = 1;//attr name offerring \nvar S_ATTR_SPACE=2;//attr name end and space offer\nvar S_EQ = 3;//=space?\nvar S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only)\nvar S_ATTR_END = 5;//attr value end and no space(quot end)\nvar S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer)\nvar S_TAG_CLOSE = 7;//closed el\n\n/**\n * Creates an error that will not be caught by XMLReader aka the SAX parser.\n *\n * @param {string} message\n * @param {any?} locator Optional, can provide details about the location in the source\n * @constructor\n */\nfunction ParseError(message, locator) {\n\tthis.message = message\n\tthis.locator = locator\n\tif(Error.captureStackTrace) Error.captureStackTrace(this, ParseError);\n}\nParseError.prototype = new Error();\nParseError.prototype.name = ParseError.name\n\nfunction XMLReader(){\n\t\n}\n\nXMLReader.prototype = {\n\tparse:function(source,defaultNSMap,entityMap){\n\t\tvar domBuilder = this.domBuilder;\n\t\tdomBuilder.startDocument();\n\t\t_copy(defaultNSMap ,defaultNSMap = {})\n\t\tparse(source,defaultNSMap,entityMap,\n\t\t\t\tdomBuilder,this.errorHandler);\n\t\tdomBuilder.endDocument();\n\t}\n}\nfunction parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){\n\tfunction fixedFromCharCode(code) {\n\t\t// String.prototype.fromCharCode does not supports\n\t\t// > 2 bytes unicode chars directly\n\t\tif (code > 0xffff) {\n\t\t\tcode -= 0x10000;\n\t\t\tvar surrogate1 = 0xd800 + (code >> 10)\n\t\t\t\t, surrogate2 = 0xdc00 + (code & 0x3ff);\n\n\t\t\treturn String.fromCharCode(surrogate1, surrogate2);\n\t\t} else {\n\t\t\treturn String.fromCharCode(code);\n\t\t}\n\t}\n\tfunction entityReplacer(a){\n\t\tvar k = a.slice(1,-1);\n\t\tif(k in entityMap){\n\t\t\treturn entityMap[k]; \n\t\t}else if(k.charAt(0) === '#'){\n\t\t\treturn fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))\n\t\t}else{\n\t\t\terrorHandler.error('entity not found:'+a);\n\t\t\treturn a;\n\t\t}\n\t}\n\tfunction appendText(end){//has some bugs\n\t\tif(end>start){\n\t\t\tvar xt = source.substring(start,end).replace(/&#?\\w+;/g,entityReplacer);\n\t\t\tlocator&&position(start);\n\t\t\tdomBuilder.characters(xt,0,end-start);\n\t\t\tstart = end\n\t\t}\n\t}\n\tfunction position(p,m){\n\t\twhile(p>=lineEnd && (m = linePattern.exec(source))){\n\t\t\tlineStart = m.index;\n\t\t\tlineEnd = lineStart + m[0].length;\n\t\t\tlocator.lineNumber++;\n\t\t\t//console.log('line++:',locator,startPos,endPos)\n\t\t}\n\t\tlocator.columnNumber = p-lineStart+1;\n\t}\n\tvar lineStart = 0;\n\tvar lineEnd = 0;\n\tvar linePattern = /.*(?:\\r\\n?|\\n)|.*$/g\n\tvar locator = domBuilder.locator;\n\t\n\tvar parseStack = [{currentNSMap:defaultNSMapCopy}]\n\tvar closeMap = {};\n\tvar start = 0;\n\twhile(true){\n\t\ttry{\n\t\t\tvar tagStart = source.indexOf('<',start);\n\t\t\tif(tagStart<0){\n\t\t\t\tif(!source.substr(start).match(/^\\s*$/)){\n\t\t\t\t\tvar doc = domBuilder.doc;\n\t \t\t\tvar text = doc.createTextNode(source.substr(start));\n\t \t\t\tdoc.appendChild(text);\n\t \t\t\tdomBuilder.currentElement = text;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif(tagStart>start){\n\t\t\t\tappendText(tagStart);\n\t\t\t}\n\t\t\tswitch(source.charAt(tagStart+1)){\n\t\t\tcase '/':\n\t\t\t\tvar end = source.indexOf('>',tagStart+3);\n\t\t\t\tvar tagName = source.substring(tagStart + 2, end).replace(/[ \\t\\n\\r]+$/g, '');\n\t\t\t\tvar config = parseStack.pop();\n\t\t\t\tif(end<0){\n\t\t\t\t\t\n\t \t\ttagName = source.substring(tagStart+2).replace(/[\\s<].*/,'');\n\t \t\terrorHandler.error(\"end tag name: \"+tagName+' is not complete:'+config.tagName);\n\t \t\tend = tagStart+1+tagName.length;\n\t \t}else if(tagName.match(/\\s\n\t\t\t\tlocator&&position(tagStart);\n\t\t\t\tend = parseInstruction(source,tagStart,domBuilder);\n\t\t\t\tbreak;\n\t\t\tcase '!':// start){\n\t\t\tstart = end;\n\t\t}else{\n\t\t\t//TODO: 这里有可能sax回退,有位置错误风险\n\t\t\tappendText(Math.max(tagStart,start)+1);\n\t\t}\n\t}\n}\nfunction copyLocator(f,t){\n\tt.lineNumber = f.lineNumber;\n\tt.columnNumber = f.columnNumber;\n\treturn t;\n}\n\n/**\n * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);\n * @return end of the elementStartPart(end of elementEndPart for selfClosed el)\n */\nfunction parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){\n\n\t/**\n\t * @param {string} qname\n\t * @param {string} value\n\t * @param {number} startIndex\n\t */\n\tfunction addAttribute(qname, value, startIndex) {\n\t\tif (el.attributeNames.hasOwnProperty(qname)) {\n\t\t\terrorHandler.fatalError('Attribute ' + qname + ' redefined')\n\t\t}\n\t\tel.addValue(qname, value, startIndex)\n\t}\n\tvar attrName;\n\tvar value;\n\tvar p = ++start;\n\tvar s = S_TAG;//status\n\twhile(true){\n\t\tvar c = source.charAt(p);\n\t\tswitch(c){\n\t\tcase '=':\n\t\t\tif(s === S_ATTR){//attrName\n\t\t\t\tattrName = source.slice(start,p);\n\t\t\t\ts = S_EQ;\n\t\t\t}else if(s === S_ATTR_SPACE){\n\t\t\t\ts = S_EQ;\n\t\t\t}else{\n\t\t\t\t//fatalError: equal must after attrName or space after attrName\n\t\t\t\tthrow new Error('attribute equal must after attrName'); // No known test case\n\t\t\t}\n\t\t\tbreak;\n\t\tcase '\\'':\n\t\tcase '\"':\n\t\t\tif(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE\n\t\t\t\t){//equal\n\t\t\t\tif(s === S_ATTR){\n\t\t\t\t\terrorHandler.warning('attribute value must after \"=\"')\n\t\t\t\t\tattrName = source.slice(start,p)\n\t\t\t\t}\n\t\t\t\tstart = p+1;\n\t\t\t\tp = source.indexOf(c,start)\n\t\t\t\tif(p>0){\n\t\t\t\t\tvalue = source.slice(start,p).replace(/&#?\\w+;/g,entityReplacer);\n\t\t\t\t\taddAttribute(attrName, value, start-1);\n\t\t\t\t\ts = S_ATTR_END;\n\t\t\t\t}else{\n\t\t\t\t\t//fatalError: no end quot match\n\t\t\t\t\tthrow new Error('attribute value no end \\''+c+'\\' match');\n\t\t\t\t}\n\t\t\t}else if(s == S_ATTR_NOQUOT_VALUE){\n\t\t\t\tvalue = source.slice(start,p).replace(/&#?\\w+;/g,entityReplacer);\n\t\t\t\t//console.log(attrName,value,start,p)\n\t\t\t\taddAttribute(attrName, value, start);\n\t\t\t\t//console.dir(el)\n\t\t\t\terrorHandler.warning('attribute \"'+attrName+'\" missed start quot('+c+')!!');\n\t\t\t\tstart = p+1;\n\t\t\t\ts = S_ATTR_END\n\t\t\t}else{\n\t\t\t\t//fatalError: no equal before\n\t\t\t\tthrow new Error('attribute value must after \"=\"'); // No known test case\n\t\t\t}\n\t\t\tbreak;\n\t\tcase '/':\n\t\t\tswitch(s){\n\t\t\tcase S_TAG:\n\t\t\t\tel.setTagName(source.slice(start,p));\n\t\t\tcase S_ATTR_END:\n\t\t\tcase S_TAG_SPACE:\n\t\t\tcase S_TAG_CLOSE:\n\t\t\t\ts =S_TAG_CLOSE;\n\t\t\t\tel.closed = true;\n\t\t\tcase S_ATTR_NOQUOT_VALUE:\n\t\t\tcase S_ATTR:\n\t\t\tcase S_ATTR_SPACE:\n\t\t\t\tbreak;\n\t\t\t//case S_EQ:\n\t\t\tdefault:\n\t\t\t\tthrow new Error(\"attribute invalid close char('/')\") // No known test case\n\t\t\t}\n\t\t\tbreak;\n\t\tcase ''://end document\n\t\t\terrorHandler.error('unexpected end of input');\n\t\t\tif(s == S_TAG){\n\t\t\t\tel.setTagName(source.slice(start,p));\n\t\t\t}\n\t\t\treturn p;\n\t\tcase '>':\n\t\t\tswitch(s){\n\t\t\tcase S_TAG:\n\t\t\t\tel.setTagName(source.slice(start,p));\n\t\t\tcase S_ATTR_END:\n\t\t\tcase S_TAG_SPACE:\n\t\t\tcase S_TAG_CLOSE:\n\t\t\t\tbreak;//normal\n\t\t\tcase S_ATTR_NOQUOT_VALUE://Compatible state\n\t\t\tcase S_ATTR:\n\t\t\t\tvalue = source.slice(start,p);\n\t\t\t\tif(value.slice(-1) === '/'){\n\t\t\t\t\tel.closed = true;\n\t\t\t\t\tvalue = value.slice(0,-1)\n\t\t\t\t}\n\t\t\tcase S_ATTR_SPACE:\n\t\t\t\tif(s === S_ATTR_SPACE){\n\t\t\t\t\tvalue = attrName;\n\t\t\t\t}\n\t\t\t\tif(s == S_ATTR_NOQUOT_VALUE){\n\t\t\t\t\terrorHandler.warning('attribute \"'+value+'\" missed quot(\")!');\n\t\t\t\t\taddAttribute(attrName, value.replace(/&#?\\w+;/g,entityReplacer), start)\n\t\t\t\t}else{\n\t\t\t\t\tif(!NAMESPACE.isHTML(currentNSMap['']) || !value.match(/^(?:disabled|checked|selected)$/i)){\n\t\t\t\t\t\terrorHandler.warning('attribute \"'+value+'\" missed value!! \"'+value+'\" instead!!')\n\t\t\t\t\t}\n\t\t\t\t\taddAttribute(value, value, start)\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase S_EQ:\n\t\t\t\tthrow new Error('attribute value missed!!');\n\t\t\t}\n//\t\t\tconsole.log(tagName,tagNamePattern,tagNamePattern.test(tagName))\n\t\t\treturn p;\n\t\t/*xml space '\\x20' | #x9 | #xD | #xA; */\n\t\tcase '\\u0080':\n\t\t\tc = ' ';\n\t\tdefault:\n\t\t\tif(c<= ' '){//space\n\t\t\t\tswitch(s){\n\t\t\t\tcase S_TAG:\n\t\t\t\t\tel.setTagName(source.slice(start,p));//tagName\n\t\t\t\t\ts = S_TAG_SPACE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase S_ATTR:\n\t\t\t\t\tattrName = source.slice(start,p)\n\t\t\t\t\ts = S_ATTR_SPACE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase S_ATTR_NOQUOT_VALUE:\n\t\t\t\t\tvar value = source.slice(start,p).replace(/&#?\\w+;/g,entityReplacer);\n\t\t\t\t\terrorHandler.warning('attribute \"'+value+'\" missed quot(\")!!');\n\t\t\t\t\taddAttribute(attrName, value, start)\n\t\t\t\tcase S_ATTR_END:\n\t\t\t\t\ts = S_TAG_SPACE;\n\t\t\t\t\tbreak;\n\t\t\t\t//case S_TAG_SPACE:\n\t\t\t\t//case S_EQ:\n\t\t\t\t//case S_ATTR_SPACE:\n\t\t\t\t//\tvoid();break;\n\t\t\t\t//case S_TAG_CLOSE:\n\t\t\t\t\t//ignore warning\n\t\t\t\t}\n\t\t\t}else{//not space\n//S_TAG,\tS_ATTR,\tS_EQ,\tS_ATTR_NOQUOT_VALUE\n//S_ATTR_SPACE,\tS_ATTR_END,\tS_TAG_SPACE, S_TAG_CLOSE\n\t\t\t\tswitch(s){\n\t\t\t\t//case S_TAG:void();break;\n\t\t\t\t//case S_ATTR:void();break;\n\t\t\t\t//case S_ATTR_NOQUOT_VALUE:void();break;\n\t\t\t\tcase S_ATTR_SPACE:\n\t\t\t\t\tvar tagName = el.tagName;\n\t\t\t\t\tif (!NAMESPACE.isHTML(currentNSMap['']) || !attrName.match(/^(?:disabled|checked|selected)$/i)) {\n\t\t\t\t\t\terrorHandler.warning('attribute \"'+attrName+'\" missed value!! \"'+attrName+'\" instead2!!')\n\t\t\t\t\t}\n\t\t\t\t\taddAttribute(attrName, attrName, start);\n\t\t\t\t\tstart = p;\n\t\t\t\t\ts = S_ATTR;\n\t\t\t\t\tbreak;\n\t\t\t\tcase S_ATTR_END:\n\t\t\t\t\terrorHandler.warning('attribute space is required\"'+attrName+'\"!!')\n\t\t\t\tcase S_TAG_SPACE:\n\t\t\t\t\ts = S_ATTR;\n\t\t\t\t\tstart = p;\n\t\t\t\t\tbreak;\n\t\t\t\tcase S_EQ:\n\t\t\t\t\ts = S_ATTR_NOQUOT_VALUE;\n\t\t\t\t\tstart = p;\n\t\t\t\t\tbreak;\n\t\t\t\tcase S_TAG_CLOSE:\n\t\t\t\t\tthrow new Error(\"elements closed character '/' and '>' must be connected to\");\n\t\t\t\t}\n\t\t\t}\n\t\t}//end outer switch\n\t\t//console.log('p++',p)\n\t\tp++;\n\t}\n}\n/**\n * @return true if has new namespace define\n */\nfunction appendElement(el,domBuilder,currentNSMap){\n\tvar tagName = el.tagName;\n\tvar localNSMap = null;\n\t//var currentNSMap = parseStack[parseStack.length-1].currentNSMap;\n\tvar i = el.length;\n\twhile(i--){\n\t\tvar a = el[i];\n\t\tvar qName = a.qName;\n\t\tvar value = a.value;\n\t\tvar nsp = qName.indexOf(':');\n\t\tif(nsp>0){\n\t\t\tvar prefix = a.prefix = qName.slice(0,nsp);\n\t\t\tvar localName = qName.slice(nsp+1);\n\t\t\tvar nsPrefix = prefix === 'xmlns' && localName\n\t\t}else{\n\t\t\tlocalName = qName;\n\t\t\tprefix = null\n\t\t\tnsPrefix = qName === 'xmlns' && ''\n\t\t}\n\t\t//can not set prefix,because prefix !== ''\n\t\ta.localName = localName ;\n\t\t//prefix == null for no ns prefix attribute \n\t\tif(nsPrefix !== false){//hack!!\n\t\t\tif(localNSMap == null){\n\t\t\t\tlocalNSMap = {}\n\t\t\t\t//console.log(currentNSMap,0)\n\t\t\t\t_copy(currentNSMap,currentNSMap={})\n\t\t\t\t//console.log(currentNSMap,1)\n\t\t\t}\n\t\t\tcurrentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;\n\t\t\ta.uri = NAMESPACE.XMLNS\n\t\t\tdomBuilder.startPrefixMapping(nsPrefix, value) \n\t\t}\n\t}\n\tvar i = el.length;\n\twhile(i--){\n\t\ta = el[i];\n\t\tvar prefix = a.prefix;\n\t\tif(prefix){//no prefix attribute has no namespace\n\t\t\tif(prefix === 'xml'){\n\t\t\t\ta.uri = NAMESPACE.XML;\n\t\t\t}if(prefix !== 'xmlns'){\n\t\t\t\ta.uri = currentNSMap[prefix || '']\n\t\t\t\t\n\t\t\t\t//{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}\n\t\t\t}\n\t\t}\n\t}\n\tvar nsp = tagName.indexOf(':');\n\tif(nsp>0){\n\t\tprefix = el.prefix = tagName.slice(0,nsp);\n\t\tlocalName = el.localName = tagName.slice(nsp+1);\n\t}else{\n\t\tprefix = null;//important!!\n\t\tlocalName = el.localName = tagName;\n\t}\n\t//no prefix element has default namespace\n\tvar ns = el.uri = currentNSMap[prefix || ''];\n\tdomBuilder.startElement(ns,localName,tagName,el);\n\t//endPrefixMapping and startPrefixMapping have not any help for dom builder\n\t//localNSMap = null\n\tif(el.closed){\n\t\tdomBuilder.endElement(ns,localName,tagName);\n\t\tif(localNSMap){\n\t\t\tfor(prefix in localNSMap){\n\t\t\t\tdomBuilder.endPrefixMapping(prefix) \n\t\t\t}\n\t\t}\n\t}else{\n\t\tel.currentNSMap = currentNSMap;\n\t\tel.localNSMap = localNSMap;\n\t\t//parseStack.push(el);\n\t\treturn true;\n\t}\n}\nfunction parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){\n\tif(/^(?:script|textarea)$/i.test(tagName)){\n\t\tvar elEndStart = source.indexOf('',elStartEnd);\n\t\tvar text = source.substring(elStartEnd+1,elEndStart);\n\t\tif(/[&<]/.test(text)){\n\t\t\tif(/^script$/i.test(tagName)){\n\t\t\t\t//if(!/\\]\\]>/.test(text)){\n\t\t\t\t\t//lexHandler.startCDATA();\n\t\t\t\t\tdomBuilder.characters(text,0,text.length);\n\t\t\t\t\t//lexHandler.endCDATA();\n\t\t\t\t\treturn elEndStart;\n\t\t\t\t//}\n\t\t\t}//}else{//text area\n\t\t\t\ttext = text.replace(/&#?\\w+;/g,entityReplacer);\n\t\t\t\tdomBuilder.characters(text,0,text.length);\n\t\t\t\treturn elEndStart;\n\t\t\t//}\n\t\t\t\n\t\t}\n\t}\n\treturn elStartEnd+1;\n}\nfunction fixSelfClosed(source,elStartEnd,tagName,closeMap){\n\t//if(tagName in closeMap){\n\tvar pos = closeMap[tagName];\n\tif(pos == null){\n\t\t//console.log(tagName)\n\t\tpos = source.lastIndexOf('')\n\t\tif(pos',start+4);\n\t\t\t//append comment source.substring(4,end)//