├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmrc ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── TODO.md ├── dist ├── ads-manager.es.js └── ads-manager.js ├── docs └── ADSMANAGER.md ├── jest.config.js ├── package-lock.json ├── package.json ├── public ├── css │ └── global.css ├── iframe.html ├── iframe2.html ├── index.html └── js │ ├── ads-manager.js │ └── index.js ├── spec └── test.spec.js ├── src ├── ad-error.js ├── ad.js ├── ads-manager.js ├── index.js └── utils.js ├── test ├── mocha.opts └── test.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.js] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | trim_trailing_whitespace = true 12 | 13 | 14 | [*.md] 15 | indent_style = space 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | dist_old/ 3 | public/ 4 | .babelrc 5 | !.eslintrc.js 6 | node_modules/ 7 | test/ 8 | spec/ 9 | jest.config.js 10 | webpack.config.js 11 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es6: true, 5 | node: true, 6 | }, 7 | extends: 'eslint:recommended', 8 | parser: 'babel-eslint', 9 | parserOptions: { 10 | ecmaVersion: 2015, 11 | sourceType: 'module', 12 | }, 13 | plugins: ['import'], 14 | rules: { 15 | quotes: ['error', 'single'], 16 | //'array-callback-return': ['error'], 17 | camelcase: ['warn'], 18 | semi: ['off'], 19 | eqeqeq: ['off'], 20 | //'func-style': ['error', 'declaration', { allowArrowFunctions: true }], 21 | 'import/named': ['error'], 22 | 'import/newline-after-import': ['warn'], 23 | 'import/no-unresolved': ['error'], 24 | 'linebreak-style': ['warn', 'unix'], 25 | 'max-classes-per-file': ['error', 1], 26 | 'no-alert': ['error'], 27 | //'no-console': ['error'], 28 | 'no-const-assign': ['error'], 29 | 'no-debugger': ['error'], 30 | 'no-duplicate-imports': ['error'], 31 | 'no-else-return': ['error'], 32 | 'no-extra-bind': ['error'], 33 | 'no-invalid-this': ['error'], 34 | 'no-multiple-empty-lines': ['warn'], 35 | 'no-multi-spaces': [ 36 | 'warn', 37 | { exceptions: { VariableDeclarator: true, ImportDeclaration: true } }, 38 | ], 39 | 'no-restricted-globals': ['error', 'fdescribe', 'fit'], 40 | 'no-shadow': ['error'], 41 | 'no-empty': ['error', {'allowEmptyCatch': true}], 42 | 'no-trailing-spaces': ['warn'], 43 | 'no-undef': ['error'], 44 | 'no-unreachable': ['error'], 45 | 'no-unused-vars': [ 46 | 'error', 47 | { argsIgnorePattern: '^_', ignoreRestSiblings: true, args: 'after-used' }, 48 | ], 49 | 'no-prototype-builtins': ['off'], 50 | 'no-var': ['error'], 51 | 'object-shorthand': ['warn'], 52 | 'prefer-const': ['error'], 53 | 'prefer-rest-params': ['error'], 54 | 'prefer-spread': ['warn'], 55 | 'prefer-template': ['warn'], 56 | }, 57 | }; 58 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Provide a description of the changes introduced in the PR. 4 | 5 | ## Issue 6 | 7 | Issue Link [Optional] 8 | 9 | ## Type of change 10 | 11 | - [ ] Bugfix 12 | - [ ] Feature 13 | - [ ] Code style update (formatting, local variables) 14 | - [ ] Refactoring 15 | - [ ] Build related changes 16 | - [ ] CI related changes 17 | - [ ] Documentation 18 | - [ ] Other 19 | 20 | ## Other information 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | 4 | ## Directory-based project 5 | .idea/ 6 | 7 | # VS Code 8 | .vscode/ 9 | 10 | # MacOs system files 11 | .DS_Store 12 | 13 | # Dist folders 14 | #dist/ 15 | dist_old/ 16 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | legacy-peer-deps=true 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to ads-manager.js 2 | 3 | Contributions are always welcome. To contribute, [fork](https://help.github.com/articles/fork-a-repo/) ads-manager, 4 | commit your changes, and [open a pull request](https://help.github.com/articles/using-pull-requests/) against the 5 | master branch. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![npm version](https://badgen.net/npm/v/ads-manager)](https://badgen.net/npm/v/ads-manager) 2 | [![downloads per week](https://badgen.net/npm/dw/ads-manager)](https://badgen.net/npm/dw/ads-manager) 3 | [![license](https://badgen.net/github/license/basil79/ads-manager)](https://badgen.net/github/license/basil79/ads-manager) 4 | 5 | # ads-manager 6 | 7 | > HTML5 Video Ads Manager based on @dailymotion/vast-client 8 | 9 | This SDK supports: 10 | 11 | - VAST versions 2.0, 3.0 and 4.0+ up to 4.2 (included) - Complies with the [VAST 4.2 specification](https://iabtechlab.com/wp-content/uploads/2019/06/VAST_4.2_final_june26.pdf) provided by the [Interactive Advertising Bureau (IAB)](https://www.iab.com/). 12 | - Inline Linear 13 | - Wrapper 14 | - AdPod 15 | - Tracker for VAST tracking events 16 | - Media Types (Assets): 17 | - `video/mp4; codecs=“avc1.42E01E, mp4a.40.2”` 18 | - `video/webm; codecs=“vp8, vorbis”` 19 | - `video/ogg; codecs=“theora, vorbis”` 20 | - `video/3gpp; codecs=“mp4v.20.8, samr”` (Safari) 21 | - `application/javascript` (VPAID) 22 | - [VPAID 2.0](https://iabtechlab.com/wp-content/uploads/2016/04/VPAID_2_0_Final_04-10-2012.pdf) 23 | 24 | This README is for developers who want to use and/or contribute to ads-manager. 25 | 26 | **Table of Contents** 27 | 28 | - [Usage](#Usage) 29 | - [Documentation](#Documentation) 30 | - [Install](#Install) 31 | - [Build](#Build) 32 | - [Run](#Run) 33 | - [Contribute](#Contribute) 34 | 35 | 36 | ## Usage 37 | 38 | ```javascript 39 | import AdsManager from 'ads-manager'; 40 | 41 | // Get your video element 42 | const videoElement = document.getElementById('video-element'); 43 | // Get your HTML element for ad container 44 | const adContainer = document.getElementById('ad-container'); 45 | // Define ads manager and pass ad container 46 | const adsManager = new AdsManager(adContainer); 47 | // Subscribe for events 48 | // AdsManagerLoaded 49 | adsManager.addEventListener('AdsManagerLoaded', function() { 50 | // Get height and width of your video element 51 | let width = videoElement.clientWidth; 52 | let height = videoElement.clientHeight; 53 | let viewMode = 'normal'; // fullscreen 54 | // Init 55 | try { 56 | adsManager.init(width, height, viewMode); 57 | } catch (adError) { 58 | // Play your context without ads, if an error occurs 59 | } 60 | }); 61 | // AdError 62 | adsManager.addEventListener('AdError', function(adError) { 63 | if(adsManager) { 64 | // Removes ad assets loaded at runtime that need to be properly removed at the time of ad completion 65 | // and stops the ad and all tracking. 66 | adsManager.abort(); 67 | } 68 | // ... 69 | }); 70 | // AdLoaded 71 | adsManager.addEventListener('AdLoaded', function(adEvent) { 72 | // Ad loaded, awaiting start 73 | // Check if ad type is linear 74 | if(adEvent.isLinear()) { 75 | try { 76 | // Start ad 77 | adsManager.start(); 78 | } catch (adError) { 79 | // Play video content without ads in case of error 80 | } 81 | } else { 82 | // Ad is not linear 83 | } 84 | }); 85 | // AdStarted 86 | adsManager.addEventListener('AdStarted', function() { 87 | // Pause your video content 88 | videoElement.pause(); 89 | }); 90 | // ... 91 | // AdDurationChange 92 | // AdSizeChange 93 | // AdImpression 94 | // AdVideoStart 95 | // AdVideoFirstQuartile 96 | // AdVideoMidpoint 97 | // AdVideoThirdQuartile 98 | // AdVideoComplete 99 | // AdPaused 100 | // AdPlaying 101 | // AdStopped 102 | // AdSkipped 103 | // AdClickThru 104 | // ... 105 | // AllAdsCompleted 106 | adsManager.addEventListener('AllAdsCompleted', function() { 107 | // Play your video content 108 | videoElement.play(); 109 | }); 110 | 111 | 112 | // VAST tag url 113 | let vastUrl = 'your VAST tag url'; 114 | 115 | // Request Ads 116 | adsManager.requestAds(vastUrl); 117 | 118 | /* 119 | // VAST XML 120 | let vastXML = ` 121 | 122 | 123 | `; 124 | adsManager.requestAds(vastXML); 125 | */ 126 | ``` 127 | 128 | ## Documentation 129 | 130 | For the full documentation: 131 | 132 | * [AdsManager](docs/ADSMANAGER.md) 133 | 134 | ### Pre-bundled versions 135 | 136 | #### Browser script 137 | 138 | A pre-bundled version of ads-manager is available: [`ads-manager.js`](dist/ads-manager.js) [minified]. 139 | 140 | You can add the script directly to your page and access the library's components through the `adserve` object. 141 | 142 | ```html 143 | 144 | ``` 145 | 146 | ```javascript 147 | // Get your HTML element for ad container 148 | const adContainer = document.getElementById('ad-container'); 149 | // Define ads manager and pass ad container 150 | const adsManager = new adserve.AdsManager(adContainer); 151 | ``` 152 | 153 | ## Install 154 | 155 | ### Get Started 156 | 157 | ads-manager is available as an NPM package and can be easily installed with: 158 | 159 | $ npm i ads-manager 160 | 161 | ### Using Git 162 | 163 | $ git clone https://github.com/basil79/ads-manager 164 | $ cd ads-manager 165 | $ npm ci 166 | 167 | 168 | ## Build 169 | 170 | To build the project for development: 171 | 172 | $ npm run build:dev 173 | 174 | To build the project for production: 175 | 176 | $ npm run build:prod 177 | 178 | This will generate the following file: 179 | 180 | + `./dist/ads-manager.js` - Minified browser production code 181 | 182 | ## Run 183 | 184 | $ npm start 185 | 186 | Then navigate to: http://localhost:8081 in your browser 187 | 188 | ### Supported Browsers 189 | 190 | ads-manager is supported all modern browsers. 191 | 192 | ## Contribute 193 | 194 | See [CONTRIBUTING](./CONTRIBUTING.md) 195 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | ## SIMID Survey Pre-roll 4 | ```text 5 | https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/simid&description_url=https%3A%2F%2Fdevelopers.google.com%2Finteractive-media-ads&sz=640x480&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator= 6 | ``` 7 | 8 | ## OM SDK Sample Pre-roll 9 | ```text 10 | https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/omid_ad_samples&env=vp&gdfp_req=1&output=vast&sz=640x480&description_url=http%3A%2F%2Ftest_site.com%2Fhomepage&vpmute=0&vpa=0&vad_format=linear&url=http%3A%2F%2Ftest_site.com&vpos=preroll&unviewed_position_start=1&correlator= 11 | ``` 12 | -------------------------------------------------------------------------------- /dist/ads-manager.js: -------------------------------------------------------------------------------- 1 | (()=>{var e={686:function(e,t){!function(e){"use strict";function t(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,r)}return i}function i(e){for(var i=1;ie.length)&&(t=e.length);for(var i=0,r=new Array(t);i0&&void 0!==arguments[0]?arguments[0]:{};return{id:e.id||null,adId:e.adId||null,sequence:e.sequence||null,apiFramework:e.apiFramework||null,universalAdIds:[],creativeExtensions:[]}}var f=["ADCATEGORIES","ADCOUNT","ADPLAYHEAD","ADSERVINGID","ADTYPE","APIFRAMEWORKS","APPBUNDLE","ASSETURI","BLOCKEDADCATEGORIES","BREAKMAXADLENGTH","BREAKMAXADS","BREAKMAXDURATION","BREAKMINADLENGTH","BREAKMINDURATION","BREAKPOSITION","CLICKPOS","CLICKTYPE","CLIENTUA","CONTENTID","CONTENTPLAYHEAD","CONTENTURI","DEVICEIP","DEVICEUA","DOMAIN","EXTENSIONS","GDPRCONSENT","IFA","IFATYPE","INVENTORYSTATE","LATLONG","LIMITADTRACKING","MEDIAMIME","MEDIAPLAYHEAD","OMIDPARTNER","PAGEURL","PLACEMENTTYPE","PLAYERCAPABILITIES","PLAYERSIZE","PLAYERSTATE","PODSEQUENCE","REGULATIONS","SERVERSIDE","SERVERUA","TRANSACTIONID","UNIVERSALADID","VASTVERSIONS","VERIFICATIONVENDORS"];function A(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=[],n=E(e);for(var a in!t.ERRORCODE||i.isCustomCode||/^[0-9]{3}$/.test(t.ERRORCODE)||(t.ERRORCODE=900),t.CACHEBUSTING=R(Math.round(1e8*Math.random())),t.TIMESTAMP=(new Date).toISOString(),t.RANDOM=t.random=t.CACHEBUSTING,t)t[a]=S(t[a]);for(var o in n){var s=n[o];"string"==typeof s&&r.push(g(s,t))}return r}function g(e,t){var i=(e=T(e,t)).match(/[^[\]]+(?=])/g);if(!i)return e;var r=i.filter((function(e){return f.indexOf(e)>-1}));return 0===r.length?e:T(e,r=r.reduce((function(e,t){return e[t]=-1,e}),{}))}function T(e,t){var i=e;for(var r in t){var n=t[r];i=i.replace(new RegExp("(?:\\[|%%)(".concat(r,")(?:\\]|%%)"),"g"),n)}return i}function E(e){return Array.isArray(e)?e.map((function(e){return e&&e.hasOwnProperty("url")?e.url:e})):e}function _(e,t){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:8;return e.toString().padStart(t,"0")}var k={track:function(e,t,i){A(e,t,i).forEach((function(e){"undefined"!=typeof window&&null!==window&&((new Image).src=e)}))},resolveURLTemplates:A,extractURLsFromTemplates:E,containsTemplateObject:_,isTemplateObjectEqual:y,encodeURIComponentRFC3986:S,replaceUrlMacros:g,isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},flatten:function e(t){return t.reduce((function(t,i){return t.concat(Array.isArray(i)?e(i):i)}),[])},joinArrayOfUniqueTemplateObjs:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],i=Array.isArray(e)?e:[],r=Array.isArray(t)?t:[];return i.concat(r).reduce((function(e,t){return _(t,e)||e.push(t),e}),[])},isValidTimeValue:function(e){return Number.isFinite(e)&&e>=-2},addLeadingZeros:R};function b(e){return-1!==["true","TRUE","True","1"].indexOf(e)}var C={childByName:function(e,t){var i=e.childNodes;for(var r in i){var n=i[r];if(n.nodeName===t)return n}},childrenByName:function(e,t){var i=[],r=e.childNodes;for(var n in r){var a=r[n];a.nodeName===t&&i.push(a)}return i},resolveVastAdTagURI:function(e,t){if(!t)return e;if(0===e.indexOf("//")){var i=location.protocol;return"".concat(i).concat(e)}if(-1===e.indexOf("://")){var r=t.slice(0,t.lastIndexOf("/"));return"".concat(r,"/").concat(e)}return e},parseBoolean:b,parseNodeText:function(e){return e&&(e.textContent||e.text||"").trim()},copyNodeAttribute:function(e,t,i){var r=t.getAttribute(e);r&&i.setAttribute(e,r)},parseAttributes:function(e){for(var t=e.attributes,i={},r=0;r3600||r>60?-1:a+n+r},splitVAST:function(e){var t=[],i=null;return e.forEach((function(r,n){if(r.sequence&&(r.sequence=parseInt(r.sequence,10)),r.sequence>1){var a=e[n-1];if(a&&a.sequence===r.sequence-1)return void(i&&i.push(r));delete r.sequence}i=[r],t.push(i)})),t},assignAttributes:function(e,t){if(e)for(var i in e){var r=e[i];if(r.nodeName&&r.nodeValue&&t.hasOwnProperty(r.nodeName)){var n=r.nodeValue;"boolean"==typeof t[r.nodeName]&&(n=b(n)),t[r.nodeName]=n}}},mergeWrapperAdData:function(e,t){e.errorURLTemplates=t.errorURLTemplates.concat(e.errorURLTemplates),e.impressionURLTemplates=t.impressionURLTemplates.concat(e.impressionURLTemplates),e.extensions=t.extensions.concat(e.extensions),t.viewableImpression.length>0&&(e.viewableImpression=[].concat(p(e.viewableImpression),p(t.viewableImpression))),e.followAdditionalWrappers=t.followAdditionalWrappers,e.allowMultipleAds=t.allowMultipleAds,e.fallbackOnNoAd=t.fallbackOnNoAd;var i=(t.creatives||[]).filter((function(e){return e&&"companion"===e.type})),r=i.reduce((function(e,t){return(t.variations||[]).forEach((function(t){(t.companionClickTrackingURLTemplates||[]).forEach((function(t){k.containsTemplateObject(t,e)||e.push(t)}))})),e}),[]);e.creatives=i.concat(e.creatives);var n=t.videoClickTrackingURLTemplates&&t.videoClickTrackingURLTemplates.length,a=t.videoCustomClickURLTemplates&&t.videoCustomClickURLTemplates.length;e.creatives.forEach((function(e){if(t.trackingEvents&&t.trackingEvents[e.type])for(var i in t.trackingEvents[e.type]){var o=t.trackingEvents[e.type][i];Array.isArray(e.trackingEvents[i])||(e.trackingEvents[i]=[]),e.trackingEvents[i]=e.trackingEvents[i].concat(o)}"linear"===e.type&&(n&&(e.videoClickTrackingURLTemplates=e.videoClickTrackingURLTemplates.concat(t.videoClickTrackingURLTemplates)),a&&(e.videoCustomClickURLTemplates=e.videoCustomClickURLTemplates.concat(t.videoCustomClickURLTemplates)),!t.videoClickThroughURLTemplate||null!==e.videoClickThroughURLTemplate&&void 0!==e.videoClickThroughURLTemplate||(e.videoClickThroughURLTemplate=t.videoClickThroughURLTemplate)),"companion"===e.type&&r.length&&(e.variations||[]).forEach((function(e){e.companionClickTrackingURLTemplates=k.joinArrayOfUniqueTemplateObjs(e.companionClickTrackingURLTemplates,r)}))})),t.adVerifications&&(e.adVerifications=e.adVerifications.concat(t.adVerifications)),t.blockedAdCategories&&(e.blockedAdCategories=e.blockedAdCategories.concat(t.blockedAdCategories))}};function V(e,t){var i=function(){var e=m(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{});return{id:e.id,adId:e.adId,sequence:e.sequence,apiFramework:e.apiFramework,type:"companion",required:null,variations:[]}}(t);return i.required=e.getAttribute("required")||null,i.variations=C.childrenByName(e,"Companion").map((function(e){var t=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{id:e.id||null,adType:"companionAd",width:e.width||0,height:e.height||0,assetWidth:e.assetWidth||null,assetHeight:e.assetHeight||null,expandedWidth:e.expandedWidth||null,expandedHeight:e.expandedHeight||null,apiFramework:e.apiFramework||null,adSlotID:e.adSlotID||null,pxratio:e.pxratio||"1",renderingMode:e.renderingMode||"default",staticResources:[],htmlResources:[],iframeResources:[],adParameters:null,xmlEncoded:null,altText:null,companionClickThroughURLTemplate:null,companionClickTrackingURLTemplates:[],trackingEvents:{}}}(C.parseAttributes(e));t.htmlResources=C.childrenByName(e,"HTMLResource").reduce((function(e,t){var i=C.parseNodeText(t);return i?e.concat(i):e}),[]),t.iframeResources=C.childrenByName(e,"IFrameResource").reduce((function(e,t){var i=C.parseNodeText(t);return i?e.concat(i):e}),[]),t.staticResources=C.childrenByName(e,"StaticResource").reduce((function(e,t){var i=C.parseNodeText(t);return i?e.concat({url:i,creativeType:t.getAttribute("creativeType")||null}):e}),[]),t.altText=C.parseNodeText(C.childByName(e,"AltText"))||null;var i=C.childByName(e,"TrackingEvents");i&&C.childrenByName(i,"Tracking").forEach((function(e){var i=e.getAttribute("event"),r=C.parseNodeText(e);i&&r&&(Array.isArray(t.trackingEvents[i])||(t.trackingEvents[i]=[]),t.trackingEvents[i].push(r))})),t.companionClickTrackingURLTemplates=C.childrenByName(e,"CompanionClickTracking").map((function(e){return{id:e.getAttribute("id")||null,url:C.parseNodeText(e)}})),t.companionClickThroughURLTemplate=C.parseNodeText(C.childByName(e,"CompanionClickThrough"))||null;var r=C.childByName(e,"AdParameters");return r&&(t.adParameters=C.parseNodeText(r),t.xmlEncoded=r.getAttribute("xmlEncoded")||null),t})),i}function I(e){return"linear"===e.type}function L(e,t){var i,r=function(){var e=m(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{});return{id:e.id,adId:e.adId,sequence:e.sequence,apiFramework:e.apiFramework,type:"linear",duration:0,skipDelay:null,mediaFiles:[],mezzanine:null,interactiveCreativeFile:null,closedCaptionFiles:[],videoClickThroughURLTemplate:null,videoClickTrackingURLTemplates:[],videoCustomClickURLTemplates:[],adParameters:null,icons:[],trackingEvents:{}}}(t);r.duration=C.parseDuration(C.parseNodeText(C.childByName(e,"Duration")));var n=e.getAttribute("skipoffset");if(null==n)r.skipDelay=null;else if("%"===n.charAt(n.length-1)&&-1!==r.duration){var a=parseInt(n,10);r.skipDelay=r.duration*(a/100)}else r.skipDelay=C.parseDuration(n);var o=C.childByName(e,"VideoClicks");if(o){var s=C.childByName(o,"ClickThrough");r.videoClickThroughURLTemplate=s?{id:s.getAttribute("id")||null,url:C.parseNodeText(s)}:null,C.childrenByName(o,"ClickTracking").forEach((function(e){r.videoClickTrackingURLTemplates.push({id:e.getAttribute("id")||null,url:C.parseNodeText(e)})})),C.childrenByName(o,"CustomClick").forEach((function(e){r.videoCustomClickURLTemplates.push({id:e.getAttribute("id")||null,url:C.parseNodeText(e)})}))}var l=C.childByName(e,"AdParameters");l&&(r.adParameters=C.parseNodeText(l)),C.childrenByName(e,"TrackingEvents").forEach((function(e){C.childrenByName(e,"Tracking").forEach((function(e){var t=e.getAttribute("event"),n=C.parseNodeText(e);if(t&&n){if("progress"===t){if(!(i=e.getAttribute("offset")))return;t="%"===i.charAt(i.length-1)?"progress-".concat(i):"progress-".concat(Math.round(C.parseDuration(i)))}Array.isArray(r.trackingEvents[t])||(r.trackingEvents[t]=[]),r.trackingEvents[t].push(n)}}))})),C.childrenByName(e,"MediaFiles").forEach((function(e){C.childrenByName(e,"MediaFile").forEach((function(e){r.mediaFiles.push(function(e){var t={id:null,fileURL:null,fileSize:0,deliveryType:"progressive",mimeType:null,mediaType:null,codec:null,bitrate:0,minBitrate:0,maxBitrate:0,width:0,height:0,apiFramework:null,scalable:null,maintainAspectRatio:null};t.id=e.getAttribute("id"),t.fileURL=C.parseNodeText(e),t.deliveryType=e.getAttribute("delivery"),t.codec=e.getAttribute("codec"),t.mimeType=e.getAttribute("type"),t.mediaType=e.getAttribute("mediaType")||"2D",t.apiFramework=e.getAttribute("apiFramework"),t.fileSize=parseInt(e.getAttribute("fileSize")||0),t.bitrate=parseInt(e.getAttribute("bitrate")||0),t.minBitrate=parseInt(e.getAttribute("minBitrate")||0),t.maxBitrate=parseInt(e.getAttribute("maxBitrate")||0),t.width=parseInt(e.getAttribute("width")||0),t.height=parseInt(e.getAttribute("height")||0);var i=e.getAttribute("scalable");i&&"string"==typeof i&&(t.scalable=C.parseBoolean(i));var r=e.getAttribute("maintainAspectRatio");return r&&"string"==typeof r&&(t.maintainAspectRatio=C.parseBoolean(r)),t}(e))}));var t=C.childByName(e,"InteractiveCreativeFile");t&&(r.interactiveCreativeFile=function(e){var t=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{type:e.type||null,apiFramework:e.apiFramework||null,variableDuration:C.parseBoolean(e.variableDuration),fileURL:null}}(C.parseAttributes(e));return t.fileURL=C.parseNodeText(e),t}(t));var i=C.childByName(e,"ClosedCaptionFiles");i&&C.childrenByName(i,"ClosedCaptionFile").forEach((function(e){var t=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{type:e.type||null,language:e.language||null,fileURL:null}}(C.parseAttributes(e));t.fileURL=C.parseNodeText(e),r.closedCaptionFiles.push(t)}));var n,a,o,s=C.childByName(e,"Mezzanine"),l=(n=s,a={},o=!1,["delivery","type","width","height"].forEach((function(e){n&&n.getAttribute(e)?a[e]=n.getAttribute(e):o=!0})),o?null:a);if(l){var d={id:null,fileURL:null,delivery:null,codec:null,type:null,width:0,height:0,fileSize:0,mediaType:"2D"};d.id=s.getAttribute("id"),d.fileURL=C.parseNodeText(s),d.delivery=l.delivery,d.codec=s.getAttribute("codec"),d.type=l.type,d.width=parseInt(l.width,10),d.height=parseInt(l.height,10),d.fileSize=parseInt(s.getAttribute("fileSize"),10),d.mediaType=s.getAttribute("mediaType")||"2D",r.mezzanine=d}}));var d=C.childByName(e,"Icons");return d&&C.childrenByName(d,"Icon").forEach((function(e){r.icons.push(function(e){var t={program:null,height:0,width:0,xPosition:0,yPosition:0,apiFramework:null,offset:null,duration:0,type:null,staticResource:null,htmlResource:null,iframeResource:null,pxratio:"1",iconClickThroughURLTemplate:null,iconClickTrackingURLTemplates:[],iconViewTrackingURLTemplate:null};t.program=e.getAttribute("program"),t.height=parseInt(e.getAttribute("height")||0),t.width=parseInt(e.getAttribute("width")||0),t.xPosition=function(e){return-1!==["left","right"].indexOf(e)?e:parseInt(e||0)}(e.getAttribute("xPosition")),t.yPosition=function(e){return-1!==["top","bottom"].indexOf(e)?e:parseInt(e||0)}(e.getAttribute("yPosition")),t.apiFramework=e.getAttribute("apiFramework"),t.pxratio=e.getAttribute("pxratio")||"1",t.offset=C.parseDuration(e.getAttribute("offset")),t.duration=C.parseDuration(e.getAttribute("duration")),C.childrenByName(e,"HTMLResource").forEach((function(e){t.type=e.getAttribute("creativeType")||"text/html",t.htmlResource=C.parseNodeText(e)})),C.childrenByName(e,"IFrameResource").forEach((function(e){t.type=e.getAttribute("creativeType")||0,t.iframeResource=C.parseNodeText(e)})),C.childrenByName(e,"StaticResource").forEach((function(e){t.type=e.getAttribute("creativeType")||0,t.staticResource=C.parseNodeText(e)}));var i=C.childByName(e,"IconClicks");return i&&(t.iconClickThroughURLTemplate=C.parseNodeText(C.childByName(i,"IconClickThrough")),C.childrenByName(i,"IconClickTracking").forEach((function(e){t.iconClickTrackingURLTemplates.push({id:e.getAttribute("id")||null,url:C.parseNodeText(e)})}))),t.iconViewTrackingURLTemplate=C.parseNodeText(C.childByName(e,"IconViewTracking")),t}(e))})),r}function N(e,t){var i=function(){var e=m(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{});return{id:e.id,adId:e.adId,sequence:e.sequence,apiFramework:e.apiFramework,type:"nonlinear",variations:[],trackingEvents:{}}}(t);return C.childrenByName(e,"TrackingEvents").forEach((function(e){var t,r;C.childrenByName(e,"Tracking").forEach((function(e){t=e.getAttribute("event"),r=C.parseNodeText(e),t&&r&&(Array.isArray(i.trackingEvents[t])||(i.trackingEvents[t]=[]),i.trackingEvents[t].push(r))}))})),C.childrenByName(e,"NonLinear").forEach((function(e){var t={id:null,width:0,height:0,expandedWidth:0,expandedHeight:0,scalable:!0,maintainAspectRatio:!0,minSuggestedDuration:0,apiFramework:"static",adType:"nonLinearAd",type:null,staticResource:null,htmlResource:null,iframeResource:null,nonlinearClickThroughURLTemplate:null,nonlinearClickTrackingURLTemplates:[],adParameters:null};t.id=e.getAttribute("id")||null,t.width=e.getAttribute("width"),t.height=e.getAttribute("height"),t.expandedWidth=e.getAttribute("expandedWidth"),t.expandedHeight=e.getAttribute("expandedHeight"),t.scalable=C.parseBoolean(e.getAttribute("scalable")),t.maintainAspectRatio=C.parseBoolean(e.getAttribute("maintainAspectRatio")),t.minSuggestedDuration=C.parseDuration(e.getAttribute("minSuggestedDuration")),t.apiFramework=e.getAttribute("apiFramework"),C.childrenByName(e,"HTMLResource").forEach((function(e){t.type=e.getAttribute("creativeType")||"text/html",t.htmlResource=C.parseNodeText(e)})),C.childrenByName(e,"IFrameResource").forEach((function(e){t.type=e.getAttribute("creativeType")||0,t.iframeResource=C.parseNodeText(e)})),C.childrenByName(e,"StaticResource").forEach((function(e){t.type=e.getAttribute("creativeType")||0,t.staticResource=C.parseNodeText(e)}));var r=C.childByName(e,"AdParameters");r&&(t.adParameters=C.parseNodeText(r)),t.nonlinearClickThroughURLTemplate=C.parseNodeText(C.childByName(e,"NonLinearClickThrough")),C.childrenByName(e,"NonLinearClickTracking").forEach((function(e){t.nonlinearClickTrackingURLTemplates.push({id:e.getAttribute("id")||null,url:C.parseNodeText(e)})})),i.variations.push(t)})),i}function w(e){var t=[];return e.forEach((function(e){var i=D(e);i&&t.push(i)})),t}function D(e){if("#comment"===e.nodeName)return null;var t,i={name:null,value:null,attributes:{},children:[]},r=e.attributes,n=e.childNodes;if(i.name=e.nodeName,e.attributes)for(var a in r)if(r.hasOwnProperty(a)){var o=r[a];o.nodeName&&o.nodeValue&&(i.attributes[o.nodeName]=o.nodeValue)}for(var s in n)if(n.hasOwnProperty(s)){var l=D(n[s]);l&&i.children.push(l)}if(0===i.children.length||1===i.children.length&&["#cdata-section","#text"].indexOf(i.children[0].name)>=0){var d=C.parseNodeText(e);""!==d&&(i.value=d),i.children=[]}return null===(t=i).value&&0===Object.keys(t.attributes).length&&0===t.children.length?null:i}function O(e){var t=[];return e.forEach((function(e){var i,r={id:e.getAttribute("id")||null,adId:P(e),sequence:e.getAttribute("sequence")||null,apiFramework:e.getAttribute("apiFramework")||null},n=[];C.childrenByName(e,"UniversalAdId").forEach((function(e){var t={idRegistry:e.getAttribute("idRegistry")||"unknown",value:C.parseNodeText(e)};n.push(t)}));var a=C.childByName(e,"CreativeExtensions");for(var o in a&&(i=w(C.childrenByName(a,"CreativeExtension"))),e.childNodes){var s=e.childNodes[o],l=void 0;switch(s.nodeName){case"Linear":l=L(s,r);break;case"NonLinearAds":l=N(s,r);break;case"CompanionAds":l=V(s,r)}l&&(n&&(l.universalAdIds=n),i&&(l.creativeExtensions=i),t.push(l))}})),t}function P(e){return e.getAttribute("AdID")||e.getAttribute("adID")||e.getAttribute("adId")||null}var U={Wrapper:{subElements:["VASTAdTagURI","Impression"]},BlockedAdCategories:{attributes:["authority"]},InLine:{subElements:["AdSystem","AdTitle","Impression","AdServingId","Creatives"]},Category:{attributes:["authority"]},Pricing:{attributes:["model","currency"]},Verification:{oneOfinLineResources:["JavaScriptResource","ExecutableResource"],attributes:["vendor"]},UniversalAdId:{attributes:["idRegistry"]},JavaScriptResource:{attributes:["apiFramework","browserOptional"]},ExecutableResource:{attributes:["apiFramework","type"]},Tracking:{attributes:["event"]},Creatives:{subElements:["Creative"]},Creative:{subElements:["UniversalAdId"]},Linear:{subElements:["MediaFiles","Duration"]},MediaFiles:{subElements:["MediaFile"]},MediaFile:{attributes:["delivery","type","width","height"]},Mezzanine:{attributes:["delivery","type","width","height"]},NonLinear:{oneOfinLineResources:["StaticResource","IFrameResource","HTMLResource"],attributes:["width","height"]},Companion:{oneOfinLineResources:["StaticResource","IFrameResource","HTMLResource"],attributes:["width","height"]},StaticResource:{attributes:["creativeType"]},Icons:{subElements:["Icon"]},Icon:{oneOfinLineResources:["StaticResource","IFrameResource","HTMLResource"]}};function x(e,t){if(U[e.nodeName]&&U[e.nodeName].attributes){var i=U[e.nodeName].attributes.filter((function(t){return!e.getAttribute(t)}));i.length>0&&B({name:e.nodeName,parentName:e.parentNode.nodeName,attributes:i},t)}}function M(e,t,i){var r=U[e.nodeName],n=!i&&"Wrapper"!==e.nodeName;if(r&&!n){if(r.subElements){var a=r.subElements.filter((function(t){return!C.childByName(e,t)}));a.length>0&&B({name:e.nodeName,parentName:e.parentNode.nodeName,subElements:a},t)}i&&r.oneOfinLineResources&&(r.oneOfinLineResources.some((function(t){return C.childByName(e,t)}))||B({name:e.nodeName,parentName:e.parentNode.nodeName,oneOfResources:r.oneOfinLineResources},t))}}function F(e){return e.children&&0!==e.children.length}function B(e,t){var i=e.name,r=e.parentName,n=e.attributes,a=e.subElements,o=e.oneOfResources,s="Element '".concat(i,"'");t("VAST-warning",{message:s+=n?" missing required attribute(s) '".concat(n.join(", "),"' "):a?" missing required sub element(s) '".concat(a.join(", "),"' "):o?" must provide one of the following '".concat(o.join(", "),"' "):" is empty",parentElement:r,specVersion:4.1})}var j={verifyRequiredValues:function e(t,i,r){if(t&&t.nodeName)if("InLine"===t.nodeName&&(r=!0),x(t,i),F(t)){M(t,i,r);for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:{},r=i.allowMultipleAds,n=i.followAdditionalWrappers,a=e.childNodes;for(var o in a){var s=a[o];if(-1!==["Wrapper","InLine"].indexOf(s.nodeName)&&("Wrapper"!==s.nodeName||!1!==n)){if(C.copyNodeAttribute("id",e,s),C.copyNodeAttribute("sequence",e,s),C.copyNodeAttribute("adType",e,s),"Wrapper"===s.nodeName)return{ad:Q(s,t),type:"WRAPPER"};if("InLine"===s.nodeName)return{ad:q(s,t,{allowMultipleAds:r}),type:"INLINE"}}}}function q(e,t){return!1===(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).allowMultipleAds&&e.getAttribute("sequence")?null:H(e,t)}function H(e,t){var i=[];t&&j.verifyRequiredValues(e,t);var r=e.childNodes,n=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{id:e.id||null,sequence:e.sequence||null,adType:e.adType||null,adServingId:null,categories:[],expires:null,viewableImpression:[],system:null,title:null,description:null,advertiser:null,pricing:null,survey:null,errorURLTemplates:[],impressionURLTemplates:[],creatives:[],extensions:[],adVerifications:[],blockedAdCategories:[],followAdditionalWrappers:!0,allowMultipleAds:!1,fallbackOnNoAd:null}}(C.parseAttributes(e));for(var a in r){var o=r[a];switch(o.nodeName){case"Error":n.errorURLTemplates.push(C.parseNodeText(o));break;case"Impression":n.impressionURLTemplates.push({id:o.getAttribute("id")||null,url:C.parseNodeText(o)});break;case"Creatives":n.creatives=O(C.childrenByName(o,"Creative"));break;case"Extensions":var s=C.childrenByName(o,"Extension");n.extensions=w(s),n.adVerifications.length||(i=G(s));break;case"AdVerifications":n.adVerifications=z(C.childrenByName(o,"Verification"));break;case"AdSystem":n.system={value:C.parseNodeText(o),version:o.getAttribute("version")||null};break;case"AdTitle":n.title=C.parseNodeText(o);break;case"AdServingId":n.adServingId=C.parseNodeText(o);break;case"Category":n.categories.push({authority:o.getAttribute("authority")||null,value:C.parseNodeText(o)});break;case"Expires":n.expires=parseInt(C.parseNodeText(o),10);break;case"ViewableImpression":n.viewableImpression.push(Y(o));break;case"Description":n.description=C.parseNodeText(o);break;case"Advertiser":n.advertiser={id:o.getAttribute("id")||null,value:C.parseNodeText(o)};break;case"Pricing":n.pricing={value:C.parseNodeText(o),model:o.getAttribute("model")||null,currency:o.getAttribute("currency")||null};break;case"Survey":n.survey=C.parseNodeText(o);break;case"BlockedAdCategories":n.blockedAdCategories.push({authority:o.getAttribute("authority")||null,value:C.parseNodeText(o)})}}return i.length&&(n.adVerifications=n.adVerifications.concat(i)),n}function Q(e,t){var i=H(e,t),r=e.getAttribute("followAdditionalWrappers"),n=e.getAttribute("allowMultipleAds"),a=e.getAttribute("fallbackOnNoAd");i.followAdditionalWrappers=!r||C.parseBoolean(r),i.allowMultipleAds=!!n&&C.parseBoolean(n),i.fallbackOnNoAd=a?C.parseBoolean(a):null;var o=C.childByName(e,"VASTAdTagURI");if(o?i.nextWrapperURL=C.parseNodeText(o):(o=C.childByName(e,"VASTAdTagURL"))&&(i.nextWrapperURL=C.parseNodeText(C.childByName(o,"URL"))),i.creatives.forEach((function(e){if(-1!==["linear","nonlinear"].indexOf(e.type)){if(e.trackingEvents){i.trackingEvents||(i.trackingEvents={}),i.trackingEvents[e.type]||(i.trackingEvents[e.type]={});var t=function(t){var r=e.trackingEvents[t];Array.isArray(i.trackingEvents[e.type][t])||(i.trackingEvents[e.type][t]=[]),r.forEach((function(r){i.trackingEvents[e.type][t].push(r)}))};for(var r in e.trackingEvents)t(r)}e.videoClickTrackingURLTemplates&&(Array.isArray(i.videoClickTrackingURLTemplates)||(i.videoClickTrackingURLTemplates=[]),e.videoClickTrackingURLTemplates.forEach((function(e){i.videoClickTrackingURLTemplates.push(e)}))),e.videoClickThroughURLTemplate&&(i.videoClickThroughURLTemplate=e.videoClickThroughURLTemplate),e.videoCustomClickURLTemplates&&(Array.isArray(i.videoCustomClickURLTemplates)||(i.videoCustomClickURLTemplates=[]),e.videoCustomClickURLTemplates.forEach((function(e){i.videoCustomClickURLTemplates.push(e)})))}})),i.nextWrapperURL)return i}function z(e){var t=[];return e.forEach((function(e){var i={resource:null,vendor:null,browserOptional:!1,apiFramework:null,type:null,parameters:null,trackingEvents:{}},r=e.childNodes;for(var n in C.assignAttributes(e.attributes,i),r){var a=r[n];switch(a.nodeName){case"JavaScriptResource":case"ExecutableResource":i.resource=C.parseNodeText(a),C.assignAttributes(a.attributes,i);break;case"VerificationParameters":i.parameters=C.parseNodeText(a)}}var o=C.childByName(e,"TrackingEvents");o&&C.childrenByName(o,"Tracking").forEach((function(e){var t=e.getAttribute("event"),r=C.parseNodeText(e);t&&r&&(Array.isArray(i.trackingEvents[t])||(i.trackingEvents[t]=[]),i.trackingEvents[t].push(r))})),t.push(i)})),t}function G(e){var t=null,i=[];return e.some((function(e){return t=C.childByName(e,"AdVerifications")})),t&&(i=z(C.childrenByName(t,"Verification"))),i}function Y(e){var t={};t.id=e.getAttribute("id")||null;var i=e.childNodes;for(var r in i){var n=i[r],a=n.nodeName,o=C.parseNodeText(n);if(("Viewable"===a||"NotViewable"===a||"ViewUndetermined"===a)&&o){var s=a.toLowerCase();Array.isArray(t[s])||(t[s]=[]),t[s].push(o)}}return t}var K=function(){function e(){n(this,e),this._handlers=[]}return o(e,[{key:"on",value:function(e,t){if("function"!=typeof t)throw new TypeError("The handler argument must be of type Function. Received type ".concat(r(t)));if(!e)throw new TypeError("The event argument must be of type String. Received type ".concat(r(e)));return this._handlers.push({event:e,handler:t}),this}},{key:"once",value:function(e,t){return this.on(e,function(e,t,i){var r={fired:!1,wrapFn:void 0};function n(){r.fired||(e.off(t,r.wrapFn),r.fired=!0,i.bind(e).apply(void 0,arguments))}return r.wrapFn=n,n}(this,e,t))}},{key:"off",value:function(e,t){return this._handlers=this._handlers.filter((function(i){return i.event!==e||i.handler!==t})),this}},{key:"emit",value:function(e){for(var t=arguments.length,i=new Array(t>1?t-1:0),r=1;r2?i-2:0),n=2;n1&&void 0!==arguments[1]?arguments[1]:0,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;return new Promise((function(a,o){t.URLTemplateFilters.forEach((function(t){e=t(e)})),t.parentURLs.push(e);var s=Date.now();t.emit("VAST-resolving",{url:e,previousUrl:r,wrapperDepth:i,maxWrapperDepth:t.maxWrapperDepth,timeout:t.fetchingOptions.timeout,wrapperAd:n}),t.urlHandler.get(e,t.fetchingOptions,(function(n,l){var d=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},u=Math.round(Date.now()-s),c=Object.assign({url:e,previousUrl:r,wrapperDepth:i,error:n,duration:u},d);t.emit("VAST-resolved",c),ne(d.byteLength,u),n?o(n):a(l)}))}))}},{key:"initParsingStatus",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.errorURLTemplates=[],this.fetchingOptions={timeout:e.timeout||Z,withCredentials:e.withCredentials},this.maxWrapperDepth=e.wrapperLimit||10,this.parentURLs=[],this.parsingOptions={allowMultipleAds:e.allowMultipleAds},this.remainingAds=[],this.rootErrorURLTemplates=[],this.rootURL="",this.urlHandler=e.urlHandler||e.urlhandler||te,this.vastVersion=null,ne(e.byteLength,e.requestDuration)}},{key:"getRemainingAds",value:function(e){var t=this;if(0===this.remainingAds.length)return Promise.reject(new Error("No more ads are available for the given VAST"));var i=e?k.flatten(this.remainingAds):this.remainingAds.shift();return this.errorURLTemplates=[],this.parentURLs=[],this.resolveAds(i,{wrapperDepth:0,url:this.rootURL}).then((function(e){return t.buildVASTResponse(e)}))}},{key:"getAndParseVAST",value:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return this.initParsingStatus(i),this.URLTemplateFilters.forEach((function(t){e=t(e)})),this.rootURL=e,this.fetchVAST(e).then((function(r){return i.previousUrl=e,i.isRootVAST=!0,i.url=e,t.parse(r,i).then((function(e){return t.buildVASTResponse(e)}))}))}},{key:"parseVAST",value:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return this.initParsingStatus(i),i.isRootVAST=!0,this.parse(e,i).then((function(e){return t.buildVASTResponse(e)}))}},{key:"buildVASTResponse",value:function(e){var t,i={ads:(t={ads:e,errorURLTemplates:this.getErrorURLTemplates(),version:this.vastVersion}).ads||[],errorURLTemplates:t.errorURLTemplates||[],version:t.version||null};return this.completeWrapperResolving(i),i}},{key:"parseVastXml",value:function(e,t){var i=t.isRootVAST,r=void 0!==i&&i,n=t.url,a=void 0===n?null:n,o=t.wrapperDepth,s=void 0===o?0:o,l=t.allowMultipleAds,d=t.followAdditionalWrappers;if(!e||!e.documentElement||"VAST"!==e.documentElement.nodeName)throw this.emit("VAST-ad-parsed",{type:"ERROR",url:a,wrapperDepth:s}),new Error("Invalid VAST XMLDocument");var u=[],c=e.documentElement.childNodes,h=e.documentElement.getAttribute("version");for(var p in r&&h&&(this.vastVersion=h),c){var v=c[p];if("Error"===v.nodeName){var m=C.parseNodeText(v);r?this.rootErrorURLTemplates.push(m):this.errorURLTemplates.push(m)}else if("Ad"===v.nodeName){if(this.vastVersion&&parseFloat(this.vastVersion)<3)l=!0;else if(!1===l&&u.length>1)break;var f=W(v,this.emit.bind(this),{allowMultipleAds:l,followAdditionalWrappers:d});f.ad?(u.push(f.ad),this.emit("VAST-ad-parsed",{type:f.type,url:a,wrapperDepth:s,adIndex:u.length-1,vastVersion:h})):this.trackVastError(this.getErrorURLTemplates(),{ERRORCODE:101})}}return u}},{key:"parse",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=t.url,r=void 0===i?null:i,n=t.resolveAll,a=void 0===n||n,o=t.wrapperSequence,s=void 0===o?null:o,l=t.previousUrl,d=void 0===l?null:l,u=t.wrapperDepth,c=void 0===u?0:u,h=t.isRootVAST,p=void 0!==h&&h,v=t.followAdditionalWrappers,m=t.allowMultipleAds,f=[];this.vastVersion&&parseFloat(this.vastVersion)<3&&p&&(m=!0);try{f=this.parseVastXml(e,{isRootVAST:p,url:r,wrapperDepth:c,allowMultipleAds:m,followAdditionalWrappers:v})}catch(e){return Promise.reject(e)}return 1===f.length&&null!=s&&(f[0].sequence=s),!1===a&&(this.remainingAds=C.splitVAST(f),f=this.remainingAds.shift()),this.resolveAds(f,{wrapperDepth:c,previousUrl:d,url:r})}},{key:"resolveAds",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],i=arguments.length>1?arguments[1]:void 0,r=i.wrapperDepth,n=i.previousUrl,a=i.url,o=[];return n=a,t.forEach((function(t){var i=e.resolveWrappers(t,r,n);o.push(i)})),Promise.all(o).then((function(t){var i=k.flatten(t);if(!i&&e.remainingAds.length>0){var o=e.remainingAds.shift();return e.resolveAds(o,{wrapperDepth:r,previousUrl:n,url:a})}return i}))}},{key:"resolveWrappers",value:function(e,t,i){var r=this;return new Promise((function(n){var a;if(t++,!e.nextWrapperURL)return delete e.nextWrapperURL,n(e);if(t>=r.maxWrapperDepth||-1!==r.parentURLs.indexOf(e.nextWrapperURL))return e.errorCode=302,delete e.nextWrapperURL,n(e);e.nextWrapperURL=C.resolveVastAdTagURI(e.nextWrapperURL,i),r.URLTemplateFilters.forEach((function(t){e.nextWrapperURL=t(e.nextWrapperURL)}));var o=null!==(a=r.parsingOptions.allowMultipleAds)&&void 0!==a?a:e.allowMultipleAds,s=e.sequence;r.fetchVAST(e.nextWrapperURL,t,i,e).then((function(a){return r.parse(a,{url:e.nextWrapperURL,previousUrl:i,wrapperSequence:s,wrapperDepth:t,followAdditionalWrappers:e.followAdditionalWrappers,allowMultipleAds:o}).then((function(t){if(delete e.nextWrapperURL,0===t.length)return e.creatives=[],n(e);t.forEach((function(t){t&&C.mergeWrapperAdData(t,e)})),n(t)}))})).catch((function(t){e.errorCode=301,e.errorMessage=t.message,n(e)}))}))}},{key:"completeWrapperResolving",value:function(e){if(0===e.ads.length)this.trackVastError(e.errorURLTemplates,{ERRORCODE:303});else for(var t=e.ads.length-1;t>=0;t--){var i=e.ads[t];(i.errorCode||0===i.creatives.length)&&(this.trackVastError(i.errorURLTemplates.concat(e.errorURLTemplates),{ERRORCODE:i.errorCode||303},{ERRORMESSAGE:i.errorMessage||""},{extensions:i.extensions},{system:i.system}),e.ads.splice(t,1))}}}]),i}(K),se=null,le={data:{},length:0,getItem:function(e){return this.data[e]},setItem:function(e,t){this.data[e]=t,this.length=Object.keys(this.data).length},removeItem:function(e){delete this.data[e],this.length=Object.keys(this.data).length},clear:function(){this.data={},this.length=0}},de=function(){function e(){n(this,e),this.storage=this.initStorage()}return o(e,[{key:"initStorage",value:function(){if(se)return se;try{se="undefined"!=typeof window&&null!==window?window.localStorage||window.sessionStorage:null}catch(e){se=null}return se&&!this.isStorageDisabled(se)||(se=le).clear(),se}},{key:"isStorageDisabled",value:function(e){var t="__VASTStorage__";try{if(e.setItem(t,t),e.getItem(t)!==t)return e.removeItem(t),!0}catch(e){return!0}return e.removeItem(t),!1}},{key:"getItem",value:function(e){return this.storage.getItem(e)}},{key:"setItem",value:function(e,t){return this.storage.setItem(e,t)}},{key:"removeItem",value:function(e){return this.storage.removeItem(e)}},{key:"clear",value:function(){return this.storage.clear()}}]),e}(),ue=function(){function e(t,i,r){n(this,e),this.cappingFreeLunch=t||0,this.cappingMinimumTimeInterval=i||0,this.defaultOptions={withCredentials:!1,timeout:0},this.vastParser=new oe,this.storage=r||new de,void 0===this.lastSuccessfulAd&&(this.lastSuccessfulAd=0),void 0===this.totalCalls&&(this.totalCalls=0),void 0===this.totalCallsTimeout&&(this.totalCallsTimeout=0)}return o(e,[{key:"getParser",value:function(){return this.vastParser}},{key:"lastSuccessfulAd",get:function(){return this.storage.getItem("vast-client-last-successful-ad")},set:function(e){this.storage.setItem("vast-client-last-successful-ad",e)}},{key:"totalCalls",get:function(){return this.storage.getItem("vast-client-total-calls")},set:function(e){this.storage.setItem("vast-client-total-calls",e)}},{key:"totalCallsTimeout",get:function(){return this.storage.getItem("vast-client-total-calls-timeout")},set:function(e){this.storage.setItem("vast-client-total-calls-timeout",e)}},{key:"hasRemainingAds",value:function(){return this.vastParser.remainingAds.length>0}},{key:"getNextAds",value:function(e){return this.vastParser.getRemainingAds(e)}},{key:"get",value:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=Date.now();return(i=Object.assign({},this.defaultOptions,i)).hasOwnProperty("resolveAll")||(i.resolveAll=!1),this.totalCallsTimeout=t.totalCalls)return a(new Error("VAST call canceled – FreeLunch capping not reached yet ".concat(t.totalCalls,"/").concat(t.cappingFreeLunch)));var o=r-t.lastSuccessfulAd;if(o<0)t.lastSuccessfulAd=0;else if(o3&&void 0!==arguments[3]?arguments[3]:null;for(var l in n(this,a),(o=t.call(this)).ad=i,o.creative=r,o.variation=s,o.muted=!1,o.impressed=!1,o.skippable=!1,o.trackingEvents={},o.lastPercentage=0,o._alreadyTriggeredQuartiles={},o.emitAlwaysEvents=["creativeView","start","firstQuartile","midpoint","thirdQuartile","complete","resume","pause","rewind","skip","closeLinear","close"],o.creative.trackingEvents){var d=o.creative.trackingEvents[l];o.trackingEvents[l]=d.slice(0)}return I(o.creative)?o._initLinearTracking():o._initVariationTracking(),e&&o.on("start",(function(){e.lastSuccessfulAd=Date.now()})),o}return o(a,[{key:"_initLinearTracking",value:function(){this.linear=!0,this.skipDelay=this.creative.skipDelay,this.setDuration(this.creative.duration),this.clickThroughURLTemplate=this.creative.videoClickThroughURLTemplate,this.clickTrackingURLTemplates=this.creative.videoClickTrackingURLTemplates}},{key:"_initVariationTracking",value:function(){if(this.linear=!1,this.skipDelay=-1,this.variation){for(var e in this.variation.trackingEvents){var t=this.variation.trackingEvents[e];this.trackingEvents[e]?this.trackingEvents[e]=this.trackingEvents[e].concat(t.slice(0)):this.trackingEvents[e]=t.slice(0)}"nonLinearAd"===this.variation.adType?(this.clickThroughURLTemplate=this.variation.nonlinearClickThroughURLTemplate,this.clickTrackingURLTemplates=this.variation.nonlinearClickTrackingURLTemplates,this.setDuration(this.variation.minSuggestedDuration)):function(e){return"companionAd"===e.adType}(this.variation)&&(this.clickThroughURLTemplate=this.variation.companionClickThroughURLTemplate,this.clickTrackingURLTemplates=this.variation.companionClickTrackingURLTemplates)}}},{key:"setDuration",value:function(e){k.isValidTimeValue(e)&&(this.assetDuration=e,this.quartiles={firstQuartile:Math.round(25*this.assetDuration)/100,midpoint:Math.round(50*this.assetDuration)/100,thirdQuartile:Math.round(75*this.assetDuration)/100})}},{key:"setProgress",value:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(k.isValidTimeValue(e)&&"object"===r(i)){var n=this.skipDelay||-1;if(-1===n||this.skippable||(n>e?this.emit("skip-countdown",n-e):(this.skippable=!0,this.emit("skip-countdown",0))),this.assetDuration>0){var a=Math.round(e/this.assetDuration*100),o=[];if(e>0){o.push("start");for(var s=this.lastPercentage;s1&&void 0!==arguments[1]?arguments[1]:{};"boolean"==typeof e&&"object"===r(t)&&(this.muted!==e&&this.track(e?"mute":"unmute",{macros:t}),this.muted=e)}},{key:"setPaused",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};"boolean"==typeof e&&"object"===r(t)&&(this.paused!==e&&this.track(e?"pause":"resume",{macros:t}),this.paused=e)}},{key:"setFullscreen",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};"boolean"==typeof e&&"object"===r(t)&&(this.fullscreen!==e&&this.track(e?"fullscreen":"exitFullscreen",{macros:t}),this.fullscreen=e)}},{key:"setExpand",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};"boolean"==typeof e&&"object"===r(t)&&(this.expanded!==e&&(this.track(e?"expand":"collapse",{macros:t}),this.track(e?"playerExpand":"playerCollapse",{macros:t})),this.expanded=e)}},{key:"setSkipDelay",value:function(e){k.isValidTimeValue(e)&&(this.skipDelay=e)}},{key:"trackImpression",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&(this.impressed||(this.impressed=!0,this.trackURLs(this.ad.impressionURLTemplates,e),this.track("creativeView",{macros:e})))}},{key:"error",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];"object"===r(e)&&"boolean"==typeof t&&this.trackURLs(this.ad.errorURLTemplates,e,{isCustomCode:t})}},{key:"errorWithCode",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];"string"==typeof e&&"boolean"==typeof t&&this.error({ERRORCODE:e},t)}},{key:"complete",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&this.track("complete",{macros:e})}},{key:"notUsed",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&(this.track("notUsed",{macros:e}),this.trackingEvents=[])}},{key:"otherAdInteraction",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&this.track("otherAdInteraction",{macros:e})}},{key:"acceptInvitation",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&this.track("acceptInvitation",{macros:e})}},{key:"adExpand",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&this.track("adExpand",{macros:e})}},{key:"adCollapse",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&this.track("adCollapse",{macros:e})}},{key:"minimize",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&this.track("minimize",{macros:e})}},{key:"verificationNotExecuted",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if("string"==typeof e&&"object"===r(t)){if(!this.ad||!this.ad.adVerifications||!this.ad.adVerifications.length)throw new Error("No adVerifications provided");if(!e)throw new Error("No vendor provided, unable to find associated verificationNotExecuted");var i=this.ad.adVerifications.find((function(t){return t.vendor===e}));if(!i)throw new Error("No associated verification element found for vendor: ".concat(e));var n=i.trackingEvents;if(n&&n.verificationNotExecuted){var a=n.verificationNotExecuted;this.trackURLs(a,t),this.emit("verificationNotExecuted",{trackingURLTemplates:a})}}}},{key:"overlayViewDuration",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};"string"==typeof e&&"object"===r(t)&&(t.ADPLAYHEAD=e,this.track("overlayViewDuration",{macros:t}))}},{key:"close",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&this.track(this.linear?"closeLinear":"close",{macros:e})}},{key:"skip",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&this.track("skip",{macros:e})}},{key:"load",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};"object"===r(e)&&this.track("loaded",{macros:e})}},{key:"click",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if((null===e||"string"==typeof e)&&"object"===r(t)){this.clickTrackingURLTemplates&&this.clickTrackingURLTemplates.length&&this.trackURLs(this.clickTrackingURLTemplates,t);var n=this.clickThroughURLTemplate||e,a=i({},t);if(n){this.progress&&(a.ADPLAYHEAD=this.progressFormatted());var o=k.resolveURLTemplates([n],a)[0];this.emit("clickthrough",o)}}}},{key:"track",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=t.macros,n=void 0===i?{}:i,a=t.once,o=void 0!==a&&a;if("object"===r(n)){"closeLinear"===e&&!this.trackingEvents[e]&&this.trackingEvents.close&&(e="close");var s=this.trackingEvents[e],l=this.emitAlwaysEvents.indexOf(e)>-1;s?(this.emit(e,{trackingURLTemplates:s}),this.trackURLs(s,n)):l&&this.emit(e,null),o&&(delete this.trackingEvents[e],l&&this.emitAlwaysEvents.splice(this.emitAlwaysEvents.indexOf(e),1))}}},{key:"trackURLs",value:function(e){var t,r,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},a=i({},arguments.length>1&&void 0!==arguments[1]?arguments[1]:{});this.linear&&(this.creative&&this.creative.mediaFiles&&this.creative.mediaFiles[0]&&this.creative.mediaFiles[0].fileURL&&(a.ASSETURI=this.creative.mediaFiles[0].fileURL),this.progress&&(a.ADPLAYHEAD=this.progressFormatted())),null!==(t=this.creative)&&void 0!==t&&null!==(r=t.universalAdIds)&&void 0!==r&&r.length&&(a.UNIVERSALADID=this.creative.universalAdIds.map((function(e){return e.idRegistry.concat(" ",e.value)})).join(",")),this.ad&&(this.ad.sequence&&(a.PODSEQUENCE=this.ad.sequence),this.ad.adType&&(a.ADTYPE=this.ad.adType),this.ad.adServingId&&(a.ADSERVINGID=this.ad.adServingId),this.ad.categories&&this.ad.categories.length&&(a.ADCATEGORIES=this.ad.categories.map((function(e){return e.value})).join(",")),this.ad.blockedAdCategories&&this.ad.blockedAdCategories.length&&(a.BLOCKEDADCATEGORIES=this.ad.blockedAdCategories)),k.track(e,a,n)}},{key:"convertToTimecode",value:function(e){if(!k.isValidTimeValue(e))return"";var t=1e3*e,i=Math.floor(t/36e5),r=Math.floor(t/6e4%60),n=Math.floor(t/1e3%60),a=Math.floor(t%1e3);return"".concat(k.addLeadingZeros(i,2),":").concat(k.addLeadingZeros(r,2),":").concat(k.addLeadingZeros(n,2),".").concat(k.addLeadingZeros(a,3))}},{key:"progressFormatted",value:function(){return this.convertToTimecode(this.progress)}}]),a}(K);e.VASTClient=ue,e.VASTParser=oe,e.VASTTracker=ce,Object.defineProperty(e,"__esModule",{value:!0})}(t)}},t={};function i(r){var n=t[r];if(void 0!==n)return n.exports;var a=t[r]={exports:{}};return e[r].call(a.exports,a,a.exports,i),a.exports}(()=>{"use strict";var e=i(686);const t=function(e,t,i){this.message=e,this.errorCode=t,this.innerError=i};t.prototype.getMessage=function(){return this.message},t.prototype.getErrorCode=function(){return this.errorCode},t.prototype.getInnerError=function(){return this.innerError instanceof Object?this.innerError:null},t.prototype.setInnerError=function(e){this.innerError=e},t.prototype.formatMessage=function(...e){return this.message=function(e,...t){try{t.forEach(((t,i)=>{e=e.replace(new RegExp("\\{"+i+"}","g"),t)}))}catch(e){}return e}(this.message,e),this},t.prototype.toString=function(){return"AdError "+this.getErrorCode()+": "+this.getMessage()+(null!=this.getInnerError()?" Caused by: "+this.getInnerError():"")};const r=t,n=function(e){this.adId=e.adId,this.duration=e.duration,this.linear="linear"===e.type};n.prototype.getAdId=function(){return this.adId},n.prototype.getDuration=function(){return this.duration},n.prototype.getMediaUrl=function(){return null},n.prototype.isLinear=function(){return this.linear};const a=n,o=function(e){if(!e||!(e instanceof HTMLElement||e.getRootNode))throw new Error("ad container is not defined");this._adContainer=e,this._ownSlot=null,this._videoSlot=null,this._slot=null,this.createOwnSlot(),this.EVENTS={AdsManagerLoaded:"AdsManagerLoaded",AdStarted:"AdStarted",AdStopped:"AdStopped",AdSkipped:"AdSkipped",AdLoaded:"AdLoaded",AdLinearChange:"AdLinearChange",AdSizeChange:"AdSizeChange",AdExpandedChange:"AdExpandedChange",AdSkippableStateChange:"AdSkippableStateChange",AdDurationChange:"AdDurationChange",AdRemainingTimeChange:"AdRemainingTimeChange",AdVolumeChange:"AdVolumeChange",AdImpression:"AdImpression",AdClickThru:"AdClickThru",AdInteraction:"AdInteraction",AdVideoStart:"AdVideoStart",AdVideoFirstQuartile:"AdVideoFirstQuartile",AdVideoMidpoint:"AdVideoMidpoint",AdVideoThirdQuartile:"AdVideoThirdQuartile",AdVideoComplete:"AdVideoComplete",AdUserAcceptInvitation:"AdUserAcceptInvitation",AdUserMinimize:"AdUserMinimize",AdUserClose:"AdUserClose",AdPaused:"AdPaused",AdPlaying:"AdPlaying",AdError:"AdError",AdLog:"AdLog",AllAdsCompleted:"AllAdsCompleted"},this._eventCallbacks={},this._creativeEventCallbacks={},this._attributes={width:300,height:154,viewMode:"normal",desiredBitrate:-1,duration:10,remainingTime:10,currentTime:0,volume:0,version:"1.2.16"},this._quartileEvents=[{event:"AdImpression",value:0},{event:"AdVideoStart",value:0},{event:"AdVideoFirstQuartile",value:25},{event:"AdVideoMidpoint",value:50},{event:"AdVideoThirdQuartile",value:75},{event:"AdVideoComplete",value:100}],this._nextQuartileIndex=0,this._defaultEventCallbacks={AdImpression:this.onAdImpression.bind(this),AdVideoStart:this.onAdVideoStart.bind(this),AdVideoFirstQuartile:this.onAdVideoFirstQuartile.bind(this),AdVideoMidpoint:this.onAdVideoMidpoint.bind(this),AdVideoThirdQuartile:this.onAdVideoThirdQuartile.bind(this),AdVideoComplete:this.onAdVideoComplete.bind(this)},this._options={autoplay:!0,muted:!0,vastLoadTimeout:23e3,loadVideoTimeout:8e3,withCredentials:!1,wrapperLimit:10,resolveAll:!0},this.ERROR_CODES={VAST_MALFORMED_RESPONSE:100,ADS_REQUEST_NETWORK_ERROR:1012,FAILED_TO_REQUEST_ADS:1005,UNKNOWN_AD_RESPONSE:1010,VAST_ASSET_NOT_FOUND:1007,VAST_EMPTY_RESPONSE:1009,VAST_LINEAR_ASSET_MISMATCH:403,VAST_LOAD_TIMEOUT:301,VAST_MEDIA_LOAD_TIMEOUT:402,VIDEO_PLAY_ERROR:400,VPAID_ERROR:901},this.ERROR_MESSAGES={VAST_MALFORMED_RESPONSE:"VAST response was malformed and could not be parsed.",ADS_REQUEST_ERROR:"Unable to request ads from server. Cause: {0}.",ADS_REQUEST_NETWORK_ERROR:"Unable to request ads from server due to network error.",FAILED_TO_REQUEST_ADS:"The was a problem requesting ads from the server.",NO_ADS_FOUND:"The response does not contain any valid ads.",UNKNOWN_AD_RESPONSE:"The ad response was not understood and cannot be parsed.",VAST_ASSET_NOT_FOUND:"No assets were found in the VAST ad response.",VAST_EMPTY_RESPONSE:"The VAST response document is empty.",VAST_LINEAR_ASSET_MISMATCH:"Linear assets were found in the VAST ad response, but none of them matched the player's capabilities.",VAST_LOAD_TIMEOUT:"Ad request reached a timeout.",VAST_MEDIA_LOAD_TIMEOUT:"VAST media file loading reached a timeout of {0} seconds.",VIDEO_PLAY_ERROR:"There was an error playing the video ad.",VPAID_CREATIVE_ERROR:"An unexpected error occurred within the VPAID creative. Refer to the inner error for more info."},this.ERRORS={VAST_MALFORMED_RESPONSE:new r(this.ERROR_MESSAGES.VAST_MALFORMED_RESPONSE,this.ERROR_CODES.VAST_MALFORMED_RESPONSE),VAST_EMPTY_RESPONSE:new r(this.ERROR_MESSAGES.VAST_EMPTY_RESPONSE,this.ERROR_CODES.VAST_EMPTY_RESPONSE),VAST_ASSET_NOT_FOUND:new r(this.ERROR_MESSAGES.VAST_ASSET_NOT_FOUND,this.ERROR_CODES.VAST_ASSET_NOT_FOUND),VAST_LINEAR_ASSET_MISMATCH:new r(this.ERROR_MESSAGES.VAST_LINEAR_ASSET_MISMATCH,this.ERROR_CODES.VAST_LINEAR_ASSET_MISMATCH),VAST_LOAD_TIMEOUT:new r(this.ERROR_MESSAGES.VAST_LOAD_TIMEOUT,this.ERROR_CODES.VAST_LOAD_TIMEOUT),VAST_MEDIA_LOAD_TIMEOUT:new r(this.ERROR_MESSAGES.VAST_MEDIA_LOAD_TIMEOUT,this.ERROR_CODES.VAST_MEDIA_LOAD_TIMEOUT),VIDEO_PLAY_ERROR:new r(this.ERROR_MESSAGES.VIDEO_PLAY_ERROR,this.ERROR_CODES.VIDEO_PLAY_ERROR),VPAID_CREATIVE_ERROR:new r(this.ERROR_MESSAGES.VPAID_CREATIVE_ERROR,this.ERROR_CODES.VPAID_ERROR)},this._vastClient=null,this._vastParser=null,this._vastTracker=null,this._ad=null,this._adPod=null,this._isAdPod=!1,this._creative=null,this._mediaFiles=null,this._mediaFileIndex=0,this._mediaFile=null,this._isVPAID=!1,this._vpaidIframe=null,this._vpaidCreative=null,this._vastMediaLoadTimer=null,this._vpaidProgressTimer=null,this._requestId=null,this._handleLoadCreativeMessage=this.handleLoadCreativeMessage.bind(this),this._handleSlotClick=this.handleSlotClick.bind(this),this._handleVideoSlotError=this.handleVideoSlotError.bind(this),this._handleVideoSlotCanPlay=this.handleVideoSlotCanPlay.bind(this),this._handleVideoSlotVolumeChange=this.handleVideoSlotVolumeChange.bind(this),this._handleVideoSlotTimeUpdate=this.handleVideoSlotTimeUpdate.bind(this),this._handleVideoSlotLoadedMetaData=this.handleVideoSlotLoadedMetaData.bind(this),this._handleVideoSlotEnded=this.handleVideoSlotEnded.bind(this),this.MIN_VPAID_VERSION=2,this._hasLoaded=!1,this._hasError=!1,this._hasImpression=!1,this._hasStarted=!1,this._isDestroyed=!1};o.prototype.createOwnSlot=function(){this._ownSlot=document.createElement("div"),this._ownSlot.style.position="absolute",this._adContainer.appendChild(this._ownSlot),this.createVideoSlot(),this.createSlot()},o.prototype.removeSlot=function(){this._ownSlot.parentNode&&this._ownSlot.parentNode.removeChild(this._ownSlot)},o.prototype.showSlot=function(){""===this._videoSlot.src&&this.hideVideoSlot(),this._ownSlot.style.display="block"},o.prototype.hideSlot=function(){this._ownSlot.style.display="none"},o.prototype.resizeSlot=function(e,t){this._ownSlot.style.width=e+"px",this._ownSlot.style.height=t+"px"},o.prototype.createVideoSlot=function(){this._videoSlot=document.createElement("video"),this._videoSlot.setAttribute("webkit-playsinline",!0),this._videoSlot.setAttribute("playsinline",!0),this._videoSlot.style.width="100%",this._videoSlot.style.height="100%",this._videoSlot.style.backgroundColor="rgb(0, 0, 0)",this._videoSlot.style.display="none";const e=this,t=Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype,"src");Object.defineProperty(this._videoSlot,"src",{set:function(i){t.set.call(this,i),e.showHideVideoSlot()},get:t.get});const i=this._videoSlot.setAttribute;this._videoSlot.setAttribute=function(){const t=i.apply(this,[].slice.call(arguments));return"src"===arguments[0]&&e.showHideVideoSlot(),t},this._ownSlot.appendChild(this._videoSlot)},o.prototype.createSlot=function(){this._slot=document.createElement("div"),this._slot.style.position="absolute",this._slot.style.top="0px",this._slot.style.left="0px",this._slot.style.right="0px",this._slot.style.bottom="0px",this._ownSlot.appendChild(this._slot)},o.prototype.hideVideoSlot=function(){this._videoSlot.style.display="none"},o.prototype.showVideoSlot=function(){this._videoSlot.style.display="block"},o.prototype.showHideVideoSlot=function(){""===this._videoSlot.getAttribute("src")?this.hideVideoSlot():this.showVideoSlot()},o.prototype.stopVASTMediaLoadTimeout=function(){this._vastMediaLoadTimer&&(clearTimeout(this._vastMediaLoadTimer),this._vastMediaLoadTimer=null)},o.prototype.startVASTMediaLoadTimeout=function(){this.stopVASTMediaLoadTimeout(),this._vastMediaLoadTimer=setTimeout((()=>{this.onAdError(this.ERRORS.VAST_MEDIA_LOAD_TIMEOUT.formatMessage(Math.floor(this._options.loadVideoTimeout/1e3%60)))}),this._options.loadVideoTimeout)},o.prototype.updateVPAIDProgress=function(){this._attributes.remainingTime=this._isCreativeFunctionInvokable("getAdRemainingTime")?this._vpaidCreative.getAdRemainingTime():-1,isNaN(this._attributes.remainingTime)||1===this._attributes.remainingTime||(this._attributes.currentTime=this._attributes.duration-this._attributes.remainingTime,this._vastTracker.setProgress(this._attributes.currentTime))},o.prototype.startVPAIDProgress=function(){this.stopVPAIDProgress(),this._vpaidProgressTimer=setInterval((()=>{this._isVPAID&&this._vpaidCreative&&this._vastTracker?this.updateVPAIDProgress():this.stopVPAIDProgress()}),1e3)},o.prototype.stopVPAIDProgress=function(){this._vpaidProgressTimer&&(clearInterval(this._vpaidProgressTimer),this._vpaidProgressTimer=null)},o.prototype._callEvent=function(e){e in this._eventCallbacks&&this._eventCallbacks[e]()},o.prototype.addEventListener=function(e,t,i){const r=t.bind(i);this._eventCallbacks[e]=r},o.prototype.removeEventListener=function(e){this._eventCallbacks[e]=null},o.prototype.removeEventListeners=function(e){for(const t in e)e.hasOwnProperty(t)&&this.removeEventListener(t)},o.prototype.onAdsManagerLoaded=function(){this._callEvent(this.EVENTS.AdsManagerLoaded)},o.prototype.onAdLoaded=function(){this._hasLoaded=!0,this.stopVASTMediaLoadTimeout(),this.EVENTS.AdLoaded in this._eventCallbacks&&this._eventCallbacks[this.EVENTS.AdLoaded](new a(this._creative))},o.prototype.onAdDurationChange=function(){this._isVPAID&&this._vpaidCreative&&this._vastTracker&&(this._attributes.duration=this._isCreativeFunctionInvokable("getAdDuration")?this._vpaidCreative.getAdDuration():-1,-1!==this._attributes.duration&&this._vastTracker.setDuration(this._attributes.duration)),this._callEvent(this.EVENTS.AdDurationChange)},o.prototype.onAdSizeChange=function(){this._callEvent(this.EVENTS.AdSizeChange)},o.prototype.onAdStarted=function(){this._hasStarted=!0,this._callEvent(this.EVENTS.AdStarted)},o.prototype.onAdVideoStart=function(){this._isVPAID&&this._vpaidCreative&&this._vastTracker&&this.updateVPAIDProgress(),this._callEvent(this.EVENTS.AdVideoStart)},o.prototype.onAdStopped=function(){this._hasStarted?this._isAdPod&&0!=this._adPod.length?(this._nextQuartileIndex=0,this._hasImpression=!1,window.removeEventListener("message",this._handleLoadCreativeMessage),this._isVPAID&&(this.removeCallbacksForCreative(this._creativeEventCallbacks),this.removeCreativeAsset(),this._isVPAID=!1),this._removeHandlers(),this._videoSlot.pause(),this._videoSlot.removeAttribute("src"),this._videoSlot.load(),setTimeout((()=>{this._nextAd()}),75)):(this._callEvent(this.EVENTS.AdStopped),this._abort()):this.onAdError(this.ERRORS.VPAID_CREATIVE_ERROR)},o.prototype.onAdSkipped=function(){this._callEvent(this.EVENTS.AdSkipped),this._abort()},o.prototype.onAdVolumeChange=function(){this._callEvent(this.EVENTS.AdVolumeChange)},o.prototype.onAdImpression=function(){this._isVPAID&&this._vpaidCreative&&this._vastTracker&&(this._hasImpression||(this._attributes.duration=this._isCreativeFunctionInvokable("getAdDuration")?this._vpaidCreative.getAdDuration():-1,-1!==this._attributes.duration&&this._vastTracker.setDuration(this._attributes.duration),this._vastTracker.trackImpression(),this.startVPAIDProgress(),this._hasImpression=!0)),this._callEvent(this.EVENTS.AdImpression)},o.prototype.onAdClickThru=function(e,t,i){this._isVPAID&&this._vpaidCreative&&this._vastTracker&&this._vastTracker.click(),this.EVENTS.AdClickThru in this._eventCallbacks&&this._eventCallbacks[this.EVENTS.AdClickThru](e,t,i)},o.prototype.onAdVideoFirstQuartile=function(){this._isVPAID&&this._vpaidCreative&&this._vastTracker&&this.updateVPAIDProgress(),this._callEvent(this.EVENTS.AdVideoFirstQuartile)},o.prototype.onAdVideoMidpoint=function(){this._isVPAID&&this._vpaidCreative&&this._vastTracker&&this.updateVPAIDProgress(),this._callEvent(this.EVENTS.AdVideoMidpoint)},o.prototype.onAdVideoThirdQuartile=function(){this._isVPAID&&this._vpaidCreative&&this._vastTracker&&this.updateVPAIDProgress(),this._callEvent(this.EVENTS.AdVideoThirdQuartile)},o.prototype.onAdPaused=function(){this._vastTracker&&this._vastTracker.setPaused(!0),this._callEvent(this.EVENTS.AdPaused)},o.prototype.onAdPlaying=function(){this._vastTracker&&this._vastTracker.setPaused(!1),this._callEvent(this.EVENTS.AdPlaying)},o.prototype.onAdVideoComplete=function(){this._isVPAID&&this._vpaidCreative&&this._vastTracker&&this._vastTracker.complete(),this._callEvent(this.EVENTS.AdVideoComplete)},o.prototype.onAllAdsCompleted=function(){this._callEvent(this.EVENTS.AllAdsCompleted)},o.prototype.onAdError=function(e){this._hasError=!0,this.abort(),this.EVENTS.AdError in this._eventCallbacks&&this._eventCallbacks[this.EVENTS.AdError]("object"!=typeof e?new r(e):e)},o.prototype.onAdLog=function(e){this.EVENTS.AdLog in this._eventCallbacks&&this._eventCallbacks[this.EVENTS.AdLog](e)},o.prototype.processVASTResponse=function(e){const t=e.ads;0!=t.length?(t.length>1?(this._isAdPod=!0,this._adPod=t.sort((function(e,t){const i=e.sequence,r=t.sequence;return i===r?0:null===i?1:null===r||ir?1:0})),this._ad=this._adPod.shift()):this._ad=t[0],this._processAd()):this.onAdError(this.ERRORS.VAST_EMPTY_RESPONSE)},o.prototype.requestAds=function(t,i={}){if(this._isDestroyed)return;this._requestId=(new Date).getTime(),Object.assign(this._options,i);const r={timeout:this._options.vastLoadTimeout,withCredentials:this._options.withCredentials,wrapperLimit:this._options.wrapperLimit,resolveAll:this._options.resolveAll};if(this.abort(),t&&"string"==typeof t){let i=!1;try{new URL(t),i=!0}catch(e){}if(i)this._vastClient=new e.VASTClient,this._vastClient.get(t,r).then((e=>{this.processVASTResponse(e)})).catch((e=>{this.onAdError(e.message)}));else{const i=(new window.DOMParser).parseFromString(t,"text/xml");this._vastParser=new e.VASTParser,this._vastParser.parseVAST(i,r).then((e=>{this.processVASTResponse(e)})).catch((e=>{this.onAdError(e.message)}))}}else this.onAdError("VAST URL/XML is empty")},o.prototype.canPlayVideoType=function(e){return!("video/3gpp"!==e||!this.supportsThreeGPVideo())||(!("video/webm"!==e||!this.supportsWebmVideo())||(!("video/ogg"!==e||!this.supportsOggTheoraVideo())||!("video/mp4"!==e||!this.supportsH264BaselineVideo())))},o.prototype.supportsVideo=function(){return!!document.createElement("video").canPlayType},o.prototype.supportsH264BaselineVideo=function(){return!!this.supportsVideo()&&document.createElement("video").canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"')},o.prototype.supportsOggTheoraVideo=function(){return!!this.supportsVideo()&&document.createElement("video").canPlayType('video/ogg; codecs="theora, vorbis"')},o.prototype.supportsWebmVideo=function(){return!!this.supportsVideo()&&document.createElement("video").canPlayType('video/webm; codecs="vp8, vorbis"')},o.prototype.supportsThreeGPVideo=function(){return!!this.supportsVideo()&&document.createElement("video").canPlayType('video/3gpp; codecs="mp4v.20.8, samr"')},o.prototype.handshakeVersion=function(e){return this._vpaidCreative.handshakeVersion(e)},o.prototype._isCreativeFunctionInvokable=function(e){return!!this._vpaidCreative&&((e=this._vpaidCreative[e])&&"function"==typeof e)},o.prototype.checkVPAIDInterface=function(e){const t={passed:!0,missingInterfaces:""};for(let i=e.length-1;0<=i;i--)this._isCreativeFunctionInvokable(e[i])||(t.passed=!1,t.missingInterfaces+=e[i]+" ");return t},o.prototype.setCallbacksForCreative=function(e,t){for(const i in e)e.hasOwnProperty(i)&&this._vpaidCreative.subscribe(e[i],i,t)},o.prototype.removeCallbacksForCreative=function(e){if(null!==this._vpaidCreative)for(const t in e)e.hasOwnProperty(t)&&this._vpaidCreative.unsubscribe(t)},o.prototype.creativeAssetLoaded=function(){if(function(e){const t=e.checkVPAIDInterface("handshakeVersion initAd startAd stopAd subscribe unsubscribe getAdLinear".split(" "));return t.passed||e.onAdError("Missing interfaces in the VPAID creative: "+t.missingInterfaces),t.passed}(this)&&(()=>{const e=this.handshakeVersion(this.MIN_VPAID_VERSION.toFixed(1));return e?!(parseFloat(e)= "+this.MIN_VPAID_VERSION.toFixed(1)),!1):(this.onAdError("Cannot get VPAID version from the creative"),!1)})()){this._creativeEventCallbacks={AdStarted:this.onAdStarted,AdStopped:this.onAdStopped,AdSkipped:this.onAdSkipped,AdLoaded:this.onAdLoaded,AdSizeChange:this.onAdSizeChange,AdDurationChange:this.onAdDurationChange,AdVolumeChange:this.onAdVolumeChange,AdImpression:this.onAdImpression,AdClickThru:this.onAdClickThru,AdVideoStart:this.onAdVideoStart,AdVideoFirstQuartile:this.onAdVideoFirstQuartile,AdVideoMidpoint:this.onAdVideoMidpoint,AdVideoThirdQuartile:this.onAdVideoThirdQuartile,AdVideoComplete:this.onAdVideoComplete,AdPaused:this.onAdPaused,AdPlaying:this.onAdPlaying,AdError:this.onAdError,AdLog:this.onAdLog},this.setCallbacksForCreative(this._creativeEventCallbacks,this);const e=this._attributes.width,t=this._attributes.height,i={AdParameters:this._creative.adParameters},r={slot:this._slot,videoSlot:this._videoSlot,videoSlotCanAutoPlay:!0};this.startVASTMediaLoadTimeout();try{this._vpaidCreative.initAd(e,t,this._attributes.viewMode,this._attributes.desiredBitrate,i,r)}catch(e){this.onAdError(e)}}},o.prototype.handleLoadCreativeMessage=function(e){if(e&&e.data){const t=String(e.data).match(new RegExp("adm:"+this._requestId+"://(.*)"));if(t){const e=JSON.parse(t[1]);if("load"==e)try{let e=this._vpaidIframe.contentWindow.getVPAIDAd;e&&"function"==typeof e?(e=e(),void 0===e?this.onAdError("getVPAIDAd() returns undefined value"):null==e?this.onAdError("getVPAIDAd() returns null"):(this._vpaidCreative=e,this.creativeAssetLoaded())):this.onAdError("getVPAIDAd() is undefined")}catch(e){this.onAdError(e)}else"error"==e&&this.onAdError("Error load VPAID")}}},o.prototype.loadCreativeAsset=function(e){window.addEventListener("message",this._handleLoadCreativeMessage),this._vpaidIframe=document.createElement("iframe"),this._vpaidIframe.style.display="none",this._vpaidIframe.style.width="0px",this._vpaidIframe.style.height="0px",this._adContainer.appendChild(this._vpaidIframe),this._vpaidIframe.contentWindow.document.open(),this._vpaidIframe.contentWindow.document.write(`\n 73 | 74 | 75 | 76 |
77 |
78 |
79 |
80 |
81 |
82 | 83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /public/js/index.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | var playContentButton = document.getElementById('play-content-button'); 4 | var testAdButton = document.getElementById('test-ad-button'); 5 | 6 | var pauseAdButton = document.getElementById('pause-ad-button'); 7 | // var resumeAdButton = document.getElementById('resume-ad-button'); 8 | var stopAdButton = document.getElementById('stop-ad-button'); 9 | var skipAdButton = document.getElementById('skip-ad-button'); 10 | var resizeAdButton = document.getElementById('resize-ad-button'); 11 | var setAdVolume1Button = document.getElementById('set-ad-volume-1-button'); 12 | var setAdVolume0Button = document.getElementById('set-ad-volume-0-button'); 13 | 14 | function enableAdButtons() { 15 | console.log('enable ad buttons'); 16 | var buttons = document.getElementsByClassName('ad-button'); 17 | for(var button of buttons) { 18 | button.removeAttribute('disabled'); 19 | } 20 | } 21 | function disableAdButtons() { 22 | console.log('disable ad buttons'); 23 | var buttons = document.getElementsByClassName('ad-button'); 24 | for(var button of buttons) { 25 | button.setAttribute('disabled', true); 26 | } 27 | } 28 | 29 | var clearLogsButton = document.getElementById('clear-logs-button'); 30 | 31 | // Events list 32 | var eventsList = document.getElementById('events-list'); 33 | function appendEvent(text) { 34 | var today = new Date(); 35 | var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds() + ":" + today.getMilliseconds(); 36 | var eventItem = document.createElement('li'); 37 | eventItem.innerHTML = time + ' ' + text; 38 | eventsList.appendChild(eventItem); 39 | } 40 | function clearEvents() { 41 | eventsList.innerHTML = ''; 42 | } 43 | 44 | // Example 45 | var videoElement = document.getElementById('video-element'); 46 | 47 | var adContainer = document.getElementById('ad-container'); 48 | var adsManager = new adserve.AdsManager(adContainer); 49 | 50 | console.log('AdsManager version is', adsManager.getVersion()); 51 | 52 | var isAdPaused = false; 53 | 54 | // Subscribe for events 55 | adsManager.addEventListener('AdError', function(adError) { 56 | 57 | console.log('AdError', adError); 58 | console.log('AdError -> typeof', typeof adError); 59 | if(typeof adError === 'object') { 60 | console.log('AdError Message', adError.getMessage()); 61 | } 62 | 63 | appendEvent('AdError : ' + adError); 64 | 65 | if(adsManager) { 66 | // Removes ad assets loaded at runtime that need to be properly removed at the time of ad completion 67 | // and stops the ad and all tracking. 68 | adsManager.abort(); 69 | } 70 | 71 | isAdPaused = false; 72 | if(videoElement.paused) { 73 | videoElement.play(); 74 | } 75 | 76 | disableAdButtons(); 77 | }); 78 | adsManager.addEventListener('AdsManagerLoaded', function() { 79 | console.log('AdsManagerLoaded'); 80 | appendEvent('AdsManagerLoaded'); 81 | console.log('ads manager loaded'); 82 | 83 | var width = videoElement.clientWidth; 84 | var height = videoElement.clientHeight; 85 | var viewMode = 'normal'; // fullscreen 86 | 87 | try { 88 | adsManager.init(width, height, viewMode); 89 | } catch (adError) { 90 | // Play the video without ads, if an error occurs 91 | console.log("AdsManager could not initialize ad"); 92 | } 93 | 94 | }); 95 | adsManager.addEventListener('AdLoaded', function(adEvent) { 96 | console.log('AdLoaded > ad type is', adEvent.isLinear()); 97 | appendEvent('AdLoaded'); 98 | //if(adEvent.type === 'linear') { 99 | if(adEvent.isLinear()) { 100 | try { 101 | adsManager.start(); 102 | } catch (adError) { 103 | // Play the video without ads, if an error occurs 104 | console.log("AdsManager could not be started"); 105 | } 106 | } else { 107 | console.log('ADM > AdLoaded > ad is not linear'); 108 | } 109 | }); 110 | adsManager.addEventListener('AdStarted', function() { 111 | console.log('AdStarted'); 112 | appendEvent('AdStarted'); 113 | 114 | // Pause 115 | console.log('CONTENT_PAUSE_REQUESTED > is video not paused?', !videoElement.paused) 116 | if(!videoElement.paused) { 117 | videoElement.pause(); 118 | } 119 | 120 | enableAdButtons(); 121 | }); 122 | adsManager.addEventListener('AdDurationChange', function() { 123 | console.log('AdDurationChange'); 124 | console.log('getDuration >', adsManager.getDuration()); 125 | appendEvent('AdDurationChange'); 126 | }); 127 | adsManager.addEventListener('AdVolumeChange', function() { 128 | console.log('AdVolumeChange'); 129 | console.log('getVolume >', adsManager.getVolume()); 130 | appendEvent('AdVolumeChange'); 131 | }); 132 | adsManager.addEventListener('AdSizeChange', function() { 133 | console.log('AdSizeChange'); 134 | appendEvent('AdSizeChange'); 135 | }); 136 | adsManager.addEventListener('AdVideoStart', function() { 137 | console.log('AdVideoStart'); 138 | appendEvent('AdVideoStart'); 139 | }); 140 | adsManager.addEventListener('AdImpression', function() { 141 | console.log('AdImpression'); 142 | appendEvent('AdImpression'); 143 | }); 144 | adsManager.addEventListener('AdVideoFirstQuartile', function() { 145 | console.log('AdVideoFirstQuartile'); 146 | appendEvent('AdVideoFirstQuartile'); 147 | }); 148 | adsManager.addEventListener('AdVideoMidpoint', function() { 149 | console.log('AdVideoMidpoint'); 150 | appendEvent('AdVideoMidpoint'); 151 | }); 152 | adsManager.addEventListener('AdVideoThirdQuartile', function() { 153 | console.log('AdVideoThirdQuartile'); 154 | appendEvent('AdVideoThirdQuartile'); 155 | }); 156 | adsManager.addEventListener('AdPaused', function() { 157 | console.log('AdPaused'); 158 | isAdPaused = true; 159 | pauseAdButton.innerHTML = 'Resume Ad'; 160 | appendEvent('AdPaused'); 161 | }); 162 | adsManager.addEventListener('AdPlaying', function() { 163 | console.log('AdPlaying'); 164 | isAdPaused = false; 165 | pauseAdButton.innerHTML = 'Pause Ad'; 166 | appendEvent('AdPlaying'); 167 | }); 168 | adsManager.addEventListener('AdVideoComplete', function () { 169 | console.log('AdVideoComplete'); 170 | appendEvent('AdVideoComplete'); 171 | }); 172 | adsManager.addEventListener('AdStopped', function () { 173 | console.log('AdStopped'); 174 | appendEvent('AdStopped'); 175 | }); 176 | adsManager.addEventListener('AdSkipped', function() { 177 | console.log('AdSkipped'); 178 | appendEvent('AdSkipped'); 179 | }); 180 | adsManager.addEventListener('AdClickThru', function(url, id) { 181 | console.log('AdClickThru', url); 182 | appendEvent('AdClickThru'); 183 | }); 184 | adsManager.addEventListener('AllAdsCompleted', async function () { 185 | console.log('AllAdsCompleted'); 186 | appendEvent('AllAdsCompleted'); 187 | isAdPaused = false; 188 | 189 | console.log('CONTENT_RESUME_REQUESTED') 190 | // Resume player 191 | if(!videoElement.ended) { 192 | videoElement.play(); 193 | 194 | //console.log('set timeout of 5000, after ad complete and request ad again'); 195 | //setTimeout(requestAd, 5000); 196 | } 197 | 198 | disableAdButtons(); 199 | }); 200 | 201 | // Ad Request 202 | //var vastUrl = 'http://v.adserve.tv/test/sample.xml'; 203 | //var vastUrl = 'http://v.adserve.tv/test/wrapper-multiple-ads.xml'; 204 | //var vastUrl = 'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinearvpaid2js&correlator='; 205 | var vastUrl = 'https://v.adserve.tv/pg/vast-vpaid.xml'; 206 | //var vastUrl = 'https://vid.springserve.com/vast/184920?ima=$[sps_ima_mode]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&widgetid=$[widgetId]&lob=$[abc]&clipid=$[clipId]&key_custom1=^w=$[widgetId]^c=$[clipId]^i=$[clipPlayCounter]^ab=$[abc]^v=$[v]^p=$[publisherId]&key_custom2=^d=$[domain]^u=$[utm]^dv=$[device]^co=$[geo]^pl=$[playback_type]&gdpr=$[gdpr]&consent=$[cd]&viewability=$[v]&schain=$[schain]&us_privacy=$[us_privacy]&domain=$[domain]&key_custom3=$[cma1]'; 207 | //var vastUrl = 'http://v.adserve.tv/pg/vast.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; //'http://localhost:3100/ads/pg/vast.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; 208 | //var vastUrl = 'https://vid.springserve.com/vast-xml/247996?id=184920&a_cc=s.184920-d.247996-cv.1025&w=640&h=360&d=demo.anyclip.com&url=http%3A%2F%2Fdemo.anyclip.com%2FLuminousX%2FTestPage.html&ssid=5937c6fd-4be6-4781-b42e-e9a31c91eef9.1597672072856&uuid=4349b3fb-4108-493a-907d-c6ceca437a8f&url=http%3A%2F%2Fdemo.anyclip.com%2FLuminousX%2FTestPage.html&_rcc=en.20954_vp.20247&_vlurl=http%3A%2F%2Fwww.anyclip.com%2F'; 209 | //var vastUrl = 'https://vid.springserve.com/vast/184920?ima=1&w=640&h=360&url=http%3A%2F%2Fdemo.anyclip.com%2FLuminousX%2FTestPage.html&cb=129511830&widgetid=demo_efi&lob=&clipid=my2hs5dygnvueqsrob5dmy2rpbdge5tc&key_custom1=^w=demo_efi^c=my2hs5dygnvueqsrob5dmy2rpbdge5tc^i=1^ab=^v=1^p=lre_demo_page&key_custom2=^d=demo.anyclip.com^u=^dv=1^co=IL^pl=a&gdpr=&consent=&viewability=1&schain=1.0,1!anyclip.com,001w000001fC68UAAS,1,,,,&us_privacy=&domain=demo.anyclip.com'; 210 | //var vastUrl = 'https://vid.springserve.com/vast/412415?w=$[w]&h=$[h]&url=$[url]&cb=$[cb]&pid=$[pid]&cid=$[cid]&wid=$[wid]&ip=$[ip]&ua=$[ua]&dom=$[dom]&abtest=$[abc]'; 211 | //var vastUrl = 'https://vid.springserve.com/vast-xml/243952?id=412415&a_cc=s.412415-d.243952-cv.1011&url=%24%5Burl%5D&ua=%24%5Bua%5D&ssid=3a865307-ac69-42b7-9ea7-087889c9345c.1625055605015&uuid=db9cc521-a0db-4607-8b61-f381e99f89bb&url=%24%5Burl%5D&_rcc=en.22277_vp.22315&_vlurl=http%3A%2F%2Fanyclip.com'; 212 | //var vastUrl = 'http://v.adserve.tv/test/wrapper-a.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; //'http://localhost:3100/ads/test/wrapper-a.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; 213 | //var vastUrl = 'http://v.adserve.tv/test/empty-no-ad.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; //'http://localhost:3100/ads/test/empty-no-ad.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; 214 | //var vastUrl = 'http://v.adserve.tv/test/empty-no-creative.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; //'http://localhost:3100/ads/test/empty-no-creative.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; 215 | //var vastUrl = 'http://v.adserve.tv/test/inline-linear.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; //'http://localhost:3100/ads/test/inline-linear.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; 216 | //var vastUrl = 'http://v.adserve.tv/test/wrapper-ad-pod.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; //'http://localhost:3100/ads/test/wrapper-ad-pod.xml?ip=$[ip]&w=$[width]&h=$[height]&url=$[pageUrl]&cb=$[cb]&origin_url=$[originUrl]'; 217 | 218 | 219 | // TODO: 220 | /* 221 | videoElement.muted = true; 222 | videoElement.load(); 223 | videoElement.play(); 224 | */ 225 | 226 | window.addEventListener('resize', function(event) { 227 | console.log("window resized"); 228 | var width = videoElement.clientWidth; 229 | var height = videoElement.clientHeight; 230 | var viewMode = 'normal'; 231 | adsManager.resize(width, height, viewMode); 232 | }); 233 | 234 | /* 235 | // Request ads 236 | console.log('ad request'); 237 | 238 | // Test VAST XML instead of VAST URL 239 | var vastXML = ` 240 | 241 | 242 | `; 243 | //adsManager.requestAds(vastXML); 244 | 245 | adsManager.requestAds(vastUrl); 246 | */ 247 | 248 | /* 249 | setInterval(function() { 250 | console.log('ad request'); 251 | adsManager.requestAds(vastUrl); 252 | }, 10000); 253 | */ 254 | 255 | 256 | 257 | playContentButton.addEventListener('click', function(event) { 258 | console.log('play content'); 259 | 260 | videoElement.play(); 261 | requestAd(); 262 | /* 263 | var playPromise = videoElement.play(); 264 | if(playPromise !== undefined) { 265 | playPromise.then(_ => { 266 | // Automatic playback started! 267 | // Show playing UI. 268 | console.log('playback started'); 269 | //videoElement.pause(); 270 | //videoElement.load(); 271 | return requestAd(); 272 | }).catch(error => { 273 | // Auto-play was prevented 274 | // Show paused UI. 275 | console.log('prevented') 276 | }); 277 | } 278 | */ 279 | }, false); 280 | 281 | 282 | function requestAd() { 283 | 284 | console.log('request ad'); 285 | 286 | isAdPaused = false; 287 | pauseAdButton.innerHTML = 'Pause Ad'; 288 | 289 | // Clear events 290 | clearEvents(); 291 | 292 | var giveVastUrl = document.getElementById('vast-url-input').value; 293 | 294 | if(videoElement.paused) { 295 | videoElement.play(); 296 | } 297 | 298 | adsManager.requestAds(giveVastUrl, { muted: true }); 299 | } 300 | 301 | testAdButton.addEventListener('click', function() { 302 | console.log('test button click'); 303 | videoElement.muted = true; 304 | requestAd(); 305 | }, false); 306 | 307 | pauseAdButton.addEventListener('click', function(event) { 308 | if(!isAdPaused) { 309 | adsManager.pause(); 310 | } else { 311 | adsManager.resume(); 312 | } 313 | }, false); 314 | /* 315 | resumeAdButton.addEventListener('click', function() { 316 | adsManager.resume(); 317 | }, false); 318 | */ 319 | stopAdButton.addEventListener('click', function() { 320 | adsManager.stop(); 321 | }, false); 322 | 323 | skipAdButton.addEventListener('click', function() { 324 | adsManager.skip(); 325 | }, false); 326 | 327 | resizeAdButton.addEventListener('click', function() { 328 | var width = videoElement.clientWidth; 329 | var height = videoElement.clientHeight; 330 | var viewMode = 'normal'; 331 | adsManager.resize(width, height, viewMode); 332 | }, false); 333 | 334 | setAdVolume1Button.addEventListener('click', function() { 335 | adsManager.setVolume(1); 336 | }, false); 337 | 338 | setAdVolume0Button.addEventListener('click', function() { 339 | adsManager.setVolume(0); 340 | }, false); 341 | 342 | clearLogsButton.addEventListener('click', function() { 343 | // Clear events 344 | clearEvents(); 345 | }, false); 346 | 347 | })() 348 | -------------------------------------------------------------------------------- /spec/test.spec.js: -------------------------------------------------------------------------------- 1 | import AdsManager from '../src/ads-manager'; 2 | 3 | describe('AdsManager', function() { 4 | describe('when no ad container', () => { 5 | 6 | it('should throw', () => { 7 | expect(() => { 8 | const adContainer = document.createElement('div'); 9 | const adsManager = new AdsManager(); 10 | }).toThrow(Error); 11 | }) 12 | 13 | }) 14 | }); 15 | -------------------------------------------------------------------------------- /src/ad-error.js: -------------------------------------------------------------------------------- 1 | import { format } from './utils'; 2 | 3 | const AdError = function(message, errorCode, innerError) { 4 | this.message = message; 5 | this.errorCode = errorCode; 6 | this.innerError = innerError; 7 | }; 8 | AdError.prototype.getMessage = function() { 9 | return this.message; 10 | }; 11 | AdError.prototype.getErrorCode = function() { 12 | return this.errorCode; 13 | }; 14 | AdError.prototype.getInnerError = function() { 15 | return this.innerError instanceof Object ? this.innerError : null; 16 | }; 17 | AdError.prototype.setInnerError = function(innerError) { 18 | this.innerError = innerError 19 | } 20 | AdError.prototype.formatMessage = function(...values) { 21 | this.message = format(this.message, values); 22 | return this; 23 | }; 24 | AdError.prototype.toString = function() { 25 | return 'AdError ' + this.getErrorCode() + ': ' + this.getMessage() + (null != this.getInnerError() ? ' Caused by: ' + this.getInnerError() : ''); 26 | }; 27 | 28 | export default AdError 29 | -------------------------------------------------------------------------------- /src/ad.js: -------------------------------------------------------------------------------- 1 | const Ad = function(creative) { 2 | this.adId = creative.adId; 3 | this.duration = creative.duration; 4 | this.linear = creative.type === 'linear' ? true : false; 5 | }; 6 | Ad.prototype.getAdId = function() { 7 | return this.adId; 8 | }; 9 | Ad.prototype.getDuration = function() { 10 | return this.duration; 11 | }; 12 | Ad.prototype.getMediaUrl = function() { 13 | return null; 14 | }; 15 | Ad.prototype.isLinear = function() { 16 | return this.linear; 17 | }; 18 | 19 | export default Ad; 20 | -------------------------------------------------------------------------------- /src/ads-manager.js: -------------------------------------------------------------------------------- 1 | import { VASTClient, VASTParser, VASTTracker } from '@dailymotion/vast-client'; 2 | import AdError from './ad-error'; 3 | import Ad from './ad'; 4 | 5 | const AdsManager = function(adContainer) { 6 | 7 | if(!(adContainer && (adContainer instanceof HTMLElement 8 | || adContainer.getRootNode))) { 9 | throw new Error('ad container is not defined'); 10 | } 11 | 12 | // Ad Container 13 | this._adContainer = adContainer; 14 | 15 | // Own Slot 16 | this._ownSlot = null; 17 | // Video Slot 18 | this._videoSlot = null; 19 | // Slot 20 | this._slot = null; 21 | 22 | // Create Own Slot 23 | this.createOwnSlot(); 24 | 25 | // Events 26 | this.EVENTS = { 27 | AdsManagerLoaded: 'AdsManagerLoaded', // After success ad request, when vast xml is parsed and ready 28 | AdStarted: 'AdStarted', 29 | AdStopped: 'AdStopped', 30 | AdSkipped: 'AdSkipped', 31 | AdLoaded: 'AdLoaded', 32 | AdLinearChange: 'AdLinearChange', 33 | AdSizeChange: 'AdSizeChange', 34 | AdExpandedChange: 'AdExpandedChange', 35 | AdSkippableStateChange: 'AdSkippableStateChange', 36 | AdDurationChange: 'AdDurationChange', 37 | AdRemainingTimeChange: 'AdRemainingTimeChange', 38 | AdVolumeChange: 'AdVolumeChange', 39 | AdImpression: 'AdImpression', 40 | AdClickThru: 'AdClickThru', 41 | AdInteraction: 'AdInteraction', 42 | AdVideoStart: 'AdVideoStart', 43 | AdVideoFirstQuartile: 'AdVideoFirstQuartile', 44 | AdVideoMidpoint: 'AdVideoMidpoint', 45 | AdVideoThirdQuartile: 'AdVideoThirdQuartile', 46 | AdVideoComplete: 'AdVideoComplete', 47 | AdUserAcceptInvitation: 'AdUserAcceptInvitation', 48 | AdUserMinimize: 'AdUserMinimize', 49 | AdUserClose: 'AdUserClose', 50 | AdPaused: 'AdPaused', 51 | AdPlaying: 'AdPlaying', 52 | AdError: 'AdError', 53 | AdLog: 'AdLog', 54 | AllAdsCompleted: 'AllAdsCompleted' // After all ads completed, vast, vpaid, vmap 55 | }; 56 | this._eventCallbacks = {}; 57 | this._creativeEventCallbacks = {}; 58 | 59 | // Attributes 60 | this._attributes = { 61 | width: 300, 62 | height: 154, 63 | viewMode: 'normal', 64 | desiredBitrate: -1, // 268, 65 | duration: 10, 66 | remainingTime: 10, 67 | currentTime: 0, 68 | volume: 0, 69 | version: '!!#Version#!!' 70 | }; 71 | 72 | // Quartile Events 73 | this._quartileEvents = [ 74 | { event: 'AdImpression', value: 0 }, 75 | { event: 'AdVideoStart', value: 0 }, 76 | { event: 'AdVideoFirstQuartile', value: 25 }, 77 | { event: 'AdVideoMidpoint', value: 50 }, 78 | { event: 'AdVideoThirdQuartile', value: 75 }, 79 | { event: 'AdVideoComplete', value: 100 } 80 | ]; 81 | this._nextQuartileIndex = 0; 82 | this._defaultEventCallbacks = { 83 | 'AdImpression': this.onAdImpression.bind(this), 84 | 'AdVideoStart': this.onAdVideoStart.bind(this), 85 | 'AdVideoFirstQuartile': this.onAdVideoFirstQuartile.bind(this), 86 | 'AdVideoMidpoint': this.onAdVideoMidpoint.bind(this), 87 | 'AdVideoThirdQuartile': this.onAdVideoThirdQuartile.bind(this), 88 | 'AdVideoComplete': this.onAdVideoComplete.bind(this) 89 | }; 90 | 91 | // Options 92 | this._options = { 93 | autoplay: true, 94 | muted: true, 95 | vastLoadTimeout: 23000, 96 | loadVideoTimeout: 8000, 97 | withCredentials: false, 98 | wrapperLimit: 10, 99 | resolveAll: true 100 | }; 101 | // Error codes 102 | this.ERROR_CODES = { 103 | VAST_MALFORMED_RESPONSE:100, 104 | ADS_REQUEST_NETWORK_ERROR: 1012, 105 | FAILED_TO_REQUEST_ADS: 1005, 106 | UNKNOWN_AD_RESPONSE: 1010, 107 | VAST_ASSET_NOT_FOUND: 1007, 108 | VAST_EMPTY_RESPONSE: 1009, 109 | VAST_LINEAR_ASSET_MISMATCH: 403, 110 | VAST_LOAD_TIMEOUT: 301, 111 | VAST_MEDIA_LOAD_TIMEOUT: 402, 112 | VIDEO_PLAY_ERROR: 400, 113 | VPAID_ERROR: 901, 114 | }; 115 | // Error messages 116 | this.ERROR_MESSAGES = { 117 | VAST_MALFORMED_RESPONSE: 'VAST response was malformed and could not be parsed.', // 100 118 | ADS_REQUEST_ERROR: 'Unable to request ads from server. Cause: {0}.', // 1005 119 | ADS_REQUEST_NETWORK_ERROR: 'Unable to request ads from server due to network error.', // 1012 120 | FAILED_TO_REQUEST_ADS: 'The was a problem requesting ads from the server.', // 1005 121 | NO_ADS_FOUND: 'The response does not contain any valid ads.', // 1009 122 | UNKNOWN_AD_RESPONSE: 'The ad response was not understood and cannot be parsed.', // 1010 123 | VAST_ASSET_NOT_FOUND: 'No assets were found in the VAST ad response.', // 1007 124 | VAST_EMPTY_RESPONSE: 'The VAST response document is empty.', // 1009 125 | VAST_LINEAR_ASSET_MISMATCH: 'Linear assets were found in the VAST ad response, but none of them matched the player\'s capabilities.', // 403 126 | VAST_LOAD_TIMEOUT: 'Ad request reached a timeout.', // 301 127 | VAST_MEDIA_LOAD_TIMEOUT: 'VAST media file loading reached a timeout of {0} seconds.', // 402 128 | VIDEO_PLAY_ERROR: 'There was an error playing the video ad.', // 400 129 | VPAID_CREATIVE_ERROR: 'An unexpected error occurred within the VPAID creative. Refer to the inner error for more info.' // 901 TODO: 130 | }; 131 | // Errors 132 | this.ERRORS = { 133 | VAST_MALFORMED_RESPONSE: new AdError(this.ERROR_MESSAGES.VAST_MALFORMED_RESPONSE, this.ERROR_CODES.VAST_MALFORMED_RESPONSE), 134 | VAST_EMPTY_RESPONSE: new AdError(this.ERROR_MESSAGES.VAST_EMPTY_RESPONSE, this.ERROR_CODES.VAST_EMPTY_RESPONSE), 135 | VAST_ASSET_NOT_FOUND: new AdError(this.ERROR_MESSAGES.VAST_ASSET_NOT_FOUND, this.ERROR_CODES.VAST_ASSET_NOT_FOUND), 136 | VAST_LINEAR_ASSET_MISMATCH: new AdError(this.ERROR_MESSAGES.VAST_LINEAR_ASSET_MISMATCH, this.ERROR_CODES.VAST_LINEAR_ASSET_MISMATCH), 137 | VAST_LOAD_TIMEOUT: new AdError(this.ERROR_MESSAGES.VAST_LOAD_TIMEOUT, this.ERROR_CODES.VAST_LOAD_TIMEOUT), 138 | VAST_MEDIA_LOAD_TIMEOUT: new AdError(this.ERROR_MESSAGES.VAST_MEDIA_LOAD_TIMEOUT, this.ERROR_CODES.VAST_MEDIA_LOAD_TIMEOUT), 139 | VIDEO_PLAY_ERROR: new AdError(this.ERROR_MESSAGES.VIDEO_PLAY_ERROR, this.ERROR_CODES.VIDEO_PLAY_ERROR), 140 | VPAID_CREATIVE_ERROR: new AdError(this.ERROR_MESSAGES.VPAID_CREATIVE_ERROR, this.ERROR_CODES.VPAID_ERROR) 141 | }; 142 | 143 | this._vastClient = null; 144 | this._vastParser = null; 145 | this._vastTracker = null; 146 | 147 | this._ad = null; 148 | this._adPod = null; 149 | this._isAdPod = false; 150 | 151 | this._creative = null; 152 | this._mediaFiles = null; 153 | this._mediaFileIndex = 0; 154 | this._mediaFile = null; 155 | 156 | this._isVPAID = false; 157 | this._vpaidIframe = null; 158 | this._vpaidCreative = null; 159 | 160 | // Timers, Intervals 161 | this._vastMediaLoadTimer = null; 162 | this._vpaidProgressTimer = null; 163 | 164 | // Request ID 165 | this._requestId = null; 166 | 167 | // Handlers 168 | this._handleLoadCreativeMessage = this.handleLoadCreativeMessage.bind(this); 169 | // Slot handlers 170 | this._handleSlotClick = this.handleSlotClick.bind(this); 171 | // Video slot handlers 172 | this._handleVideoSlotError = this.handleVideoSlotError.bind(this); 173 | this._handleVideoSlotCanPlay = this.handleVideoSlotCanPlay.bind(this); 174 | this._handleVideoSlotVolumeChange = this.handleVideoSlotVolumeChange.bind(this); 175 | this._handleVideoSlotTimeUpdate = this.handleVideoSlotTimeUpdate.bind(this); 176 | this._handleVideoSlotLoadedMetaData = this.handleVideoSlotLoadedMetaData.bind(this); 177 | this._handleVideoSlotEnded = this.handleVideoSlotEnded.bind(this); 178 | 179 | this.MIN_VPAID_VERSION = 2; 180 | 181 | this._hasLoaded = false; 182 | this._hasError = false; 183 | this._hasImpression = false; 184 | this._hasStarted = false; 185 | 186 | this._isDestroyed = false; 187 | }; 188 | AdsManager.prototype.createOwnSlot = function() { 189 | console.log('create slot......'); 190 | this._ownSlot = document.createElement('div'); 191 | this._ownSlot.style.position = 'absolute'; 192 | //this._slot.style.display = 'none'; 193 | this._adContainer.appendChild(this._ownSlot); 194 | this.createVideoSlot(); 195 | this.createSlot(); 196 | }; 197 | AdsManager.prototype.removeSlot = function() { 198 | this._ownSlot.parentNode && this._ownSlot.parentNode.removeChild(this._ownSlot); 199 | }; 200 | AdsManager.prototype.showSlot = function() { 201 | // Check if video slot has src, if no then hide video slot 202 | if(this._videoSlot.src === '') { 203 | this.hideVideoSlot(); 204 | } 205 | // Show slot 206 | this._ownSlot.style.display = 'block'; 207 | }; 208 | AdsManager.prototype.hideSlot = function() { 209 | // Hide slot 210 | this._ownSlot.style.display = 'none'; 211 | }; 212 | AdsManager.prototype.resizeSlot = function(width, height) { 213 | this._ownSlot.style.width = width + 'px'; 214 | this._ownSlot.style.height = height + 'px'; 215 | }; 216 | AdsManager.prototype.createVideoSlot = function() { 217 | this._videoSlot = document.createElement('video'); 218 | this._videoSlot.setAttribute('webkit-playsinline', true); 219 | this._videoSlot.setAttribute('playsinline', true); 220 | //this._videoSlot.setAttribute('preload', 'none'); 221 | this._videoSlot.style.width = '100%'; 222 | this._videoSlot.style.height = '100%'; 223 | this._videoSlot.style.backgroundColor = 'rgb(0, 0, 0)'; 224 | this._videoSlot.style.display = 'none'; 225 | 226 | const that = this; 227 | 228 | // Overwrite getter/setter of src 229 | const _src = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'src'); 230 | Object.defineProperty(this._videoSlot, 'src', { 231 | set: function(value) { 232 | _src.set.call(this, value); 233 | console.log('video src changed', value); 234 | that.showHideVideoSlot(); 235 | }, 236 | get: _src.get 237 | }); 238 | // Override setAttribute function 239 | const _setAttribute = this._videoSlot.setAttribute; 240 | this._videoSlot.setAttribute = function() { 241 | const value = _setAttribute.apply(this, [].slice.call(arguments)) 242 | if(arguments[0] === 'src') { 243 | console.log('video setAttribute src', arguments[1]); 244 | that.showHideVideoSlot(); 245 | } 246 | return value; 247 | } 248 | 249 | //this._adContainer.appendChild(this._videoSlot); 250 | this._ownSlot.appendChild(this._videoSlot); 251 | }; 252 | AdsManager.prototype.createSlot = function() { 253 | this._slot = document.createElement('div'); 254 | this._slot.style.position = 'absolute'; 255 | this._slot.style.top = '0px'; 256 | this._slot.style.left = '0px'; 257 | this._slot.style.right = '0px'; 258 | this._slot.style.bottom = '0px'; 259 | this._ownSlot.appendChild(this._slot); 260 | }; 261 | AdsManager.prototype.hideVideoSlot = function() { 262 | console.log('hide video slot'); 263 | this._videoSlot.style.display = 'none'; 264 | }; 265 | AdsManager.prototype.showVideoSlot = function() { 266 | console.log('show video slot'); 267 | this._videoSlot.style.display = 'block'; 268 | }; 269 | AdsManager.prototype.showHideVideoSlot = function() { 270 | if(this._videoSlot.getAttribute('src') === '') { 271 | this.hideVideoSlot(); 272 | } else { 273 | this.showVideoSlot(); 274 | } 275 | }; 276 | AdsManager.prototype.stopVASTMediaLoadTimeout = function() { 277 | if(this._vastMediaLoadTimer) { 278 | clearTimeout(this._vastMediaLoadTimer); 279 | this._vastMediaLoadTimer = null; 280 | } 281 | }; 282 | AdsManager.prototype.startVASTMediaLoadTimeout = function() { 283 | this.stopVASTMediaLoadTimeout(); 284 | this._vastMediaLoadTimer = setTimeout(() => { 285 | this.onAdError(this.ERRORS.VAST_MEDIA_LOAD_TIMEOUT.formatMessage(Math.floor((this._options.loadVideoTimeout / 1000) % 60))); 286 | }, this._options.loadVideoTimeout); 287 | }; 288 | AdsManager.prototype.updateVPAIDProgress = function() { 289 | // Check remaining time 290 | this._attributes.remainingTime = this._isCreativeFunctionInvokable('getAdRemainingTime') ? this._vpaidCreative.getAdRemainingTime() : -1; 291 | if(!isNaN(this._attributes.remainingTime) && this._attributes.remainingTime !== 1) { 292 | this._attributes.currentTime = this._attributes.duration - this._attributes.remainingTime; 293 | // Track progress 294 | this._vastTracker.setProgress(this._attributes.currentTime); 295 | } 296 | }; 297 | AdsManager.prototype.startVPAIDProgress = function() { 298 | this.stopVPAIDProgress(); 299 | this._vpaidProgressTimer = setInterval(() => { 300 | if(this._isVPAID && this._vpaidCreative && this._vastTracker) { 301 | this.updateVPAIDProgress(); 302 | } else { 303 | this.stopVPAIDProgress(); 304 | } 305 | }, 1000); 306 | }; 307 | AdsManager.prototype.stopVPAIDProgress = function() { 308 | if(this._vpaidProgressTimer) { 309 | clearInterval(this._vpaidProgressTimer); 310 | this._vpaidProgressTimer = null; 311 | } 312 | }; 313 | AdsManager.prototype._callEvent = function(eventName) { 314 | if(eventName in this._eventCallbacks) { 315 | this._eventCallbacks[eventName](); 316 | } 317 | }; 318 | AdsManager.prototype.addEventListener = function(eventName, callback, context) { 319 | const givenCallback = callback.bind(context); 320 | this._eventCallbacks[eventName] = givenCallback; 321 | }; 322 | AdsManager.prototype.removeEventListener = function(eventName) { 323 | this._eventCallbacks[eventName] = null; 324 | }; 325 | AdsManager.prototype.removeEventListeners = function(eventCallbacks) { 326 | for (const eventName in eventCallbacks) { 327 | eventCallbacks.hasOwnProperty(eventName) && this.removeEventListener(eventName); 328 | } 329 | }; 330 | AdsManager.prototype.onAdsManagerLoaded = function() { 331 | this._callEvent(this.EVENTS.AdsManagerLoaded); 332 | }; 333 | AdsManager.prototype.onAdLoaded = function() { 334 | this._hasLoaded = true; 335 | this.stopVASTMediaLoadTimeout(); 336 | if (this.EVENTS.AdLoaded in this._eventCallbacks) { 337 | this._eventCallbacks[this.EVENTS.AdLoaded](new Ad(this._creative)); 338 | } 339 | }; 340 | AdsManager.prototype.onAdDurationChange = function() { 341 | if(this._isVPAID && this._vpaidCreative && this._vastTracker) { 342 | this._attributes.duration = this._isCreativeFunctionInvokable('getAdDuration') ? this._vpaidCreative.getAdDuration() : -1; 343 | if(this._attributes.duration !== -1) { 344 | this._vastTracker.setDuration(this._attributes.duration); 345 | } 346 | } 347 | this._callEvent(this.EVENTS.AdDurationChange); 348 | }; 349 | AdsManager.prototype.onAdSizeChange = function() { 350 | this._callEvent(this.EVENTS.AdSizeChange); 351 | }; 352 | AdsManager.prototype.onAdStarted = function() { 353 | this._hasStarted = true; 354 | this._callEvent(this.EVENTS.AdStarted); 355 | }; 356 | AdsManager.prototype.onAdVideoStart = function() { 357 | if(this._isVPAID && this._vpaidCreative && this._vastTracker) { 358 | this.updateVPAIDProgress(); 359 | } 360 | this._callEvent(this.EVENTS.AdVideoStart); 361 | }; 362 | AdsManager.prototype.onAdStopped = function() { 363 | if(!this._hasStarted) { 364 | this.onAdError(this.ERRORS.VPAID_CREATIVE_ERROR); 365 | } else { 366 | if(this._isAdPod && this._adPod.length != 0) { 367 | 368 | this._nextQuartileIndex = 0; 369 | this._hasImpression = false; 370 | 371 | // Removes ad assets loaded at runtime that need to be properly removed at the time of ad completion 372 | // and stops the ad and all tracking. 373 | window.removeEventListener('message', this._handleLoadCreativeMessage); 374 | 375 | if(this._isVPAID) { 376 | // Unsubscribe for VPAID events 377 | this.removeCallbacksForCreative(this._creativeEventCallbacks); 378 | this.removeCreativeAsset(); 379 | this._isVPAID = false; 380 | } 381 | 382 | // Remove handlers from slot and videoSlot 383 | this._removeHandlers(); 384 | // Pause video slot, and remove src 385 | this._videoSlot.pause(); 386 | this._videoSlot.removeAttribute('src'); // empty source 387 | this._videoSlot.load(); 388 | 389 | setTimeout(() => { 390 | this._nextAd(); 391 | },75); 392 | 393 | } else { 394 | this._callEvent(this.EVENTS.AdStopped); 395 | // abort the ad, unsubscribe and reset to a default state 396 | this._abort(); 397 | } 398 | } 399 | }; 400 | AdsManager.prototype.onAdSkipped = function() { 401 | this._callEvent(this.EVENTS.AdSkipped); 402 | // abort the ad, unsubscribe and reset to a default state 403 | this._abort(); 404 | }; 405 | AdsManager.prototype.onAdVolumeChange = function() { 406 | this._callEvent(this.EVENTS.AdVolumeChange); 407 | }; 408 | AdsManager.prototype.onAdImpression = function() { 409 | console.log('is vpaid', this._isVPAID); 410 | if(this._isVPAID && this._vpaidCreative && this._vastTracker) { 411 | if (!this._hasImpression) { 412 | // Check duration 413 | this._attributes.duration = this._isCreativeFunctionInvokable('getAdDuration') ? this._vpaidCreative.getAdDuration() : -1; 414 | if(this._attributes.duration !== -1) { 415 | this._vastTracker.setDuration(this._attributes.duration); 416 | } 417 | /* 418 | // Check remaining time 419 | this._attributes.remainingTime = this._isCreativeFunctionInvokable("getAdRemainingTime") ? this._vpaidCreative.getAdRemainingTime() : -1; 420 | console.log('update tracker with new remainingTime', this._attributes.remainingTime); 421 | console.log('update tracker with new duration', this._attributes.duration); 422 | */ 423 | // Track impression 424 | this._vastTracker.trackImpression(); 425 | 426 | // Start VPAID process 427 | this.startVPAIDProgress(); 428 | 429 | this._hasImpression = true; 430 | } 431 | } 432 | this._callEvent(this.EVENTS.AdImpression); 433 | }; 434 | AdsManager.prototype.onAdClickThru = function(url, id, playerHandles) { 435 | if(this._isVPAID && this._vpaidCreative && this._vastTracker) { 436 | this._vastTracker.click(); 437 | } 438 | if (this.EVENTS.AdClickThru in this._eventCallbacks) { 439 | this._eventCallbacks[this.EVENTS.AdClickThru](url, id, playerHandles); 440 | } 441 | }; 442 | AdsManager.prototype.onAdVideoFirstQuartile = function() { 443 | if(this._isVPAID && this._vpaidCreative && this._vastTracker) { 444 | this.updateVPAIDProgress(); 445 | } 446 | this._callEvent(this.EVENTS.AdVideoFirstQuartile); 447 | }; 448 | AdsManager.prototype.onAdVideoMidpoint = function() { 449 | if(this._isVPAID && this._vpaidCreative && this._vastTracker) { 450 | this.updateVPAIDProgress(); 451 | } 452 | this._callEvent(this.EVENTS.AdVideoMidpoint); 453 | }; 454 | AdsManager.prototype.onAdVideoThirdQuartile = function() { 455 | if(this._isVPAID && this._vpaidCreative && this._vastTracker) { 456 | this.updateVPAIDProgress(); 457 | } 458 | this._callEvent(this.EVENTS.AdVideoThirdQuartile); 459 | }; 460 | AdsManager.prototype.onAdPaused = function() { 461 | if(this._vastTracker) { 462 | this._vastTracker.setPaused(true); 463 | } 464 | this._callEvent(this.EVENTS.AdPaused); 465 | }; 466 | AdsManager.prototype.onAdPlaying = function() { 467 | if(this._vastTracker) { 468 | this._vastTracker.setPaused(false); 469 | } 470 | this._callEvent(this.EVENTS.AdPlaying); 471 | }; 472 | AdsManager.prototype.onAdVideoComplete = function() { 473 | if(this._isVPAID && this._vpaidCreative && this._vastTracker) { 474 | this._vastTracker.complete(); 475 | } 476 | this._callEvent(this.EVENTS.AdVideoComplete); 477 | }; 478 | AdsManager.prototype.onAllAdsCompleted = function() { 479 | this._callEvent(this.EVENTS.AllAdsCompleted); 480 | }; 481 | AdsManager.prototype.onAdError = function(message) { 482 | 483 | this._hasError = true; 484 | /* 485 | // Stop and clear timeouts, intervals 486 | this.stopVASTMediaLoadTimeout(); 487 | this.stopVPAIDProgress(); 488 | */ 489 | this.abort(); 490 | 491 | if (this.EVENTS.AdError in this._eventCallbacks) { 492 | this._eventCallbacks[this.EVENTS.AdError](typeof message !== 'object' ? new AdError(message) : message); 493 | } 494 | }; 495 | AdsManager.prototype.onAdLog = function(message) { 496 | if (this.EVENTS.AdLog in this._eventCallbacks) { 497 | this._eventCallbacks[this.EVENTS.AdLog](message); 498 | } 499 | }; 500 | AdsManager.prototype.processVASTResponse = function(res) { 501 | 502 | const ads = res.ads; 503 | if(ads.length != 0) { 504 | 505 | if(ads.length > 1) { 506 | // Ad pod 507 | this._isAdPod = true; 508 | console.log('ads', ads); 509 | // Filter by sequence 510 | this._adPod = ads.sort(function(a, b) { 511 | const aSequence = a.sequence; 512 | const bSequence = b.sequence; 513 | if (aSequence === bSequence) { 514 | return 0; 515 | } else if (aSequence === null) { 516 | return 1; 517 | } else if (bSequence === null) { 518 | return -1; 519 | } 520 | return (aSequence < bSequence) ? -1 : (aSequence > bSequence) ? 1 : 0; 521 | }); 522 | 523 | // Shift from adPod array 524 | this._ad = this._adPod.shift(); 525 | } else { 526 | // Ad 527 | this._ad = ads[0]; 528 | } 529 | 530 | // Process ad 531 | this._processAd(); 532 | 533 | } else { 534 | // The VAST response document is empty. 535 | this.onAdError(this.ERRORS.VAST_EMPTY_RESPONSE); 536 | } 537 | }; 538 | AdsManager.prototype.requestAds = function(vastUrl, options = {}) { 539 | 540 | if(this._isDestroyed) { 541 | return; 542 | } 543 | 544 | // Generate request Id 545 | this._requestId = new Date().getTime(); 546 | 547 | // Assign options 548 | Object.assign(this._options, options); 549 | 550 | // VAST options 551 | // timeout: Number - A custom timeout for the requests (default 120000 ms) 552 | // withCredentials: Boolean - A boolean to enable the withCredentials options for the XHR URLHandler (default false) 553 | // wrapperLimit: Number - A number of Wrapper responses that can be received with no InLine response (default 10) 554 | // resolveAll: Boolean - Allows you to parse all the ads contained in the VAST or to parse them ad by ad or adPod by adPod (default true) 555 | // allowMultipleAds: Boolean - A Boolean value that identifies whether multiple ads are allowed in the requested VAST response. This will override any value of allowMultipleAds attribute set in the VAST 556 | // followAdditionalWrappers: Boolean - a Boolean value that identifies whether subsequent Wrappers after a requested VAST response is allowed. This will override any value of followAdditionalWrappers attribute set in the VAST 557 | const vastOptions = { 558 | timeout: this._options.vastLoadTimeout, 559 | withCredentials: this._options.withCredentials, 560 | wrapperLimit: this._options.wrapperLimit, 561 | resolveAll: this._options.resolveAll, 562 | //allowMultipleAds: true, 563 | //followAdditionalWrappers: true, 564 | }; 565 | 566 | // Abort 567 | this.abort(); 568 | 569 | // Check if vastUrl exists 570 | if(vastUrl && typeof vastUrl === 'string') { 571 | 572 | let isURL = false; 573 | try { 574 | new URL(vastUrl); 575 | isURL = true; 576 | } catch (e) {} 577 | 578 | if (isURL) { 579 | // use VAST URL 580 | this._vastClient = new VASTClient(); 581 | this._vastClient 582 | .get(vastUrl, vastOptions) 583 | .then(res => { 584 | console.log('RES', res); 585 | this.processVASTResponse(res); 586 | }) 587 | .catch(err => { 588 | this.onAdError(err.message); 589 | }); 590 | } else { 591 | // use VAST XML 592 | const vastXml = (new window.DOMParser()).parseFromString(vastUrl, 'text/xml'); 593 | this._vastParser = new VASTParser(); 594 | this._vastParser 595 | .parseVAST(vastXml, vastOptions) 596 | .then(res => { 597 | console.log('RES', res); 598 | this.processVASTResponse(res); 599 | }) 600 | .catch(err => { 601 | this.onAdError(err.message); 602 | }); 603 | } 604 | } else { 605 | this.onAdError('VAST URL/XML is empty'); 606 | } 607 | }; 608 | AdsManager.prototype.canPlayVideoType = function(mimeType) { 609 | if(mimeType === 'video/3gpp' && this.supportsThreeGPVideo()) { 610 | return true; 611 | } else if(mimeType === 'video/webm' && this.supportsWebmVideo()) { 612 | return true; 613 | } else if(mimeType === 'video/ogg' && this.supportsOggTheoraVideo()) { 614 | return true; 615 | } else if(mimeType === 'video/mp4' && this.supportsH264BaselineVideo()) { 616 | return true; 617 | } 618 | return false; 619 | }; 620 | AdsManager.prototype.supportsVideo = function() { 621 | return !!document.createElement('video').canPlayType; 622 | }; 623 | AdsManager.prototype.supportsH264BaselineVideo = function() { 624 | if(!this.supportsVideo()) return false; 625 | return document.createElement('video').canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); 626 | }; 627 | AdsManager.prototype.supportsOggTheoraVideo = function() { 628 | if(!this.supportsVideo()) return false; 629 | return document.createElement('video').canPlayType('video/ogg; codecs="theora, vorbis"'); 630 | }; 631 | AdsManager.prototype.supportsWebmVideo = function() { 632 | if(!this.supportsVideo()) return false; 633 | return document.createElement('video').canPlayType('video/webm; codecs="vp8, vorbis"'); 634 | }; 635 | AdsManager.prototype.supportsThreeGPVideo = function() { 636 | if(!this.supportsVideo()) return false; 637 | return document.createElement('video').canPlayType('video/3gpp; codecs="mp4v.20.8, samr"'); 638 | }; 639 | AdsManager.prototype.handshakeVersion = function(version) { 640 | return this._vpaidCreative.handshakeVersion(version); 641 | }; 642 | AdsManager.prototype._isCreativeFunctionInvokable = function(a) { 643 | return this._vpaidCreative ? (a = this._vpaidCreative[a]) && typeof a === 'function' : false; 644 | }; 645 | AdsManager.prototype.checkVPAIDInterface = function(a) { 646 | const b = { passed: true, missingInterfaces: ''}; 647 | for (let d = a.length - 1; 0 <= d; d--) 648 | this._isCreativeFunctionInvokable(a[d]) || (b.passed = false, b.missingInterfaces += a[d] + ' '); 649 | return b; 650 | }; 651 | AdsManager.prototype.setCallbacksForCreative = function(eventCallbacks, context) { 652 | for (const event in eventCallbacks) eventCallbacks.hasOwnProperty(event) && this._vpaidCreative.subscribe(eventCallbacks[event], event, context) 653 | }; 654 | AdsManager.prototype.removeCallbacksForCreative = function(eventCallbacks) { 655 | if(this._vpaidCreative !== null) { 656 | for (const event in eventCallbacks) { 657 | eventCallbacks.hasOwnProperty(event) && this._vpaidCreative.unsubscribe(event); // && this._vpaidCreative.unsubscribe(eventCallbacks[event], event); 658 | } 659 | } 660 | }; 661 | AdsManager.prototype.creativeAssetLoaded = function() { 662 | const checkVPAIDMinVersion = () => { 663 | const c = this.handshakeVersion(this.MIN_VPAID_VERSION.toFixed(1)); 664 | return c ? parseFloat(c) < this.MIN_VPAID_VERSION ? (this.onAdError('Only support creatives with VPAID version >= ' + this.MIN_VPAID_VERSION.toFixed(1)), !1) : !0 : (this.onAdError('Cannot get VPAID version from the creative'), !1) 665 | }; 666 | if (function(that) { 667 | const c = that.checkVPAIDInterface('handshakeVersion initAd startAd stopAd subscribe unsubscribe getAdLinear'.split(' ')); 668 | c.passed || that.onAdError('Missing interfaces in the VPAID creative: ' + c.missingInterfaces); 669 | return c.passed 670 | }(this) && checkVPAIDMinVersion()) { 671 | 672 | // VPAID events 673 | this._creativeEventCallbacks = { 674 | AdStarted: this.onAdStarted, 675 | AdStopped: this.onAdStopped, 676 | AdSkipped: this.onAdSkipped, 677 | AdLoaded: this.onAdLoaded, 678 | //AdLinearChange: this.onAdLinearChange, 679 | AdSizeChange: this.onAdSizeChange, 680 | //AdExpandedChange: this.onAdExpandedChange, 681 | AdDurationChange: this.onAdDurationChange, 682 | AdVolumeChange: this.onAdVolumeChange, 683 | AdImpression: this.onAdImpression, 684 | AdClickThru: this.onAdClickThru, 685 | //AdInteraction: this.onAdInteraction, 686 | AdVideoStart: this.onAdVideoStart, 687 | AdVideoFirstQuartile: this.onAdVideoFirstQuartile, 688 | AdVideoMidpoint: this.onAdVideoMidpoint, 689 | AdVideoThirdQuartile: this.onAdVideoThirdQuartile, 690 | AdVideoComplete: this.onAdVideoComplete, 691 | //AdUserAcceptInvitation: this.onAdUserAcceptInvitation, 692 | //AdUserMinimize: this.onAdUserMinimize, 693 | //AdUserClose: this.onAdUserClose, 694 | AdPaused: this.onAdPaused, 695 | AdPlaying: this.onAdPlaying, // onAdResumed 696 | AdError: this.onAdError, 697 | AdLog: this.onAdLog 698 | } 699 | 700 | // Subscribe for VPAID events 701 | this.setCallbacksForCreative(this._creativeEventCallbacks, this); 702 | 703 | // Prepare for iniAd 704 | const width = this._attributes.width; 705 | const height = this._attributes.height; 706 | const creativeData = { 707 | AdParameters: this._creative.adParameters 708 | }; 709 | console.log('creativeData', creativeData); 710 | const environmentVars = { 711 | slot: this._slot, 712 | videoSlot: this._videoSlot, 713 | videoSlotCanAutoPlay: true 714 | }; 715 | // iniAd(width, height, viewMode, desiredBitrate, creativeData, environmentVars) 716 | // Start loadVideoTimeout 717 | this.startVASTMediaLoadTimeout(); 718 | try { 719 | this._vpaidCreative.initAd(width, height, this._attributes.viewMode, this._attributes.desiredBitrate, creativeData, environmentVars); 720 | } catch(err) { 721 | this.onAdError(err); 722 | } 723 | } 724 | }; 725 | AdsManager.prototype.handleLoadCreativeMessage = function(msg) { 726 | if (msg && msg.data) { 727 | const match = String(msg.data).match(new RegExp('adm:' + this._requestId + '://(.*)')); 728 | if (match) { 729 | console.log('vpaid creative message', match); 730 | const value = JSON.parse(match[1]); 731 | if(value == 'load') { 732 | console.log('vpaid message load', this._requestId); 733 | try { 734 | let VPAIDAd = this._vpaidIframe.contentWindow.getVPAIDAd; 735 | if (VPAIDAd && typeof VPAIDAd === 'function') { 736 | VPAIDAd = VPAIDAd(); 737 | console.log('vpaid', typeof VPAIDAd); 738 | typeof VPAIDAd === 'undefined' 739 | ? this.onAdError('getVPAIDAd() returns undefined value') 740 | : VPAIDAd == null 741 | ? this.onAdError('getVPAIDAd() returns null') 742 | : ((this._vpaidCreative = VPAIDAd), 743 | this.creativeAssetLoaded()); 744 | } else { 745 | this.onAdError('getVPAIDAd() is undefined'); 746 | } 747 | } catch (e) { 748 | this.onAdError(e); 749 | } 750 | } else if (value == 'error') { 751 | this.onAdError('Error load VPAID'); 752 | } 753 | } 754 | } 755 | }; 756 | AdsManager.prototype.loadCreativeAsset = function(fileURL) { 757 | 758 | console.log('vpaid creative asset', fileURL); 759 | window.addEventListener('message', this._handleLoadCreativeMessage); 760 | 761 | // Create iframe 762 | this._vpaidIframe = document.createElement('iframe'); 763 | this._vpaidIframe.style.display = 'none'; 764 | this._vpaidIframe.style.width = '0px'; 765 | this._vpaidIframe.style.height = '0px'; 766 | 767 | /* 768 | // avoid document.write() 769 | this._vpaidIframe.srcdoc = ` 775 | 777 | `; 778 | */ 779 | 780 | // Append iframe 781 | this._adContainer.appendChild(this._vpaidIframe); 782 | 783 | // Open iframe, write and close 784 | this._vpaidIframe.contentWindow.document.open(); 785 | this._vpaidIframe.contentWindow.document.write(` 786 |