diff --git a/.circleci/config.yml b/.circleci/config.yml index 16bdd5b317e..5ea5e87218c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,49 +2,96 @@ # # Check https://circleci.com/docs/2.0/language-javascript/ for more details # + +aliases: + - &environment + docker: + # specify the version you desire here + - image: circleci/node:12.16.1 + + # Specify service dependencies here if necessary + # CircleCI maintains a library of pre-built images + # documented at https://circleci.com/docs/2.0/circleci-images/ + # - image: circleci/mongo:3.4.4 + working_directory: ~/Prebid.js + + - &restore_dep_cache + keys: + - v1-dependencies-{{ checksum "package.json" }} + # fallback to using the latest cache if no exact match is found + - v1-dependencies- + + - &save_dep_cache + paths: + - node_modules + key: v1-dependencies-{{ checksum "package.json" }} + + - &install + name: Install gulp cli + command: sudo npm install -g gulp-cli + + - &run_unit_test + name: BrowserStack testing + command: gulp test --browserstack --nolintfix + + - &run_endtoend_test + name: BrowserStack End to end testing + command: echo "127.0.0.1 test.localhost" | sudo tee -a /etc/hosts && gulp e2e-test --host=test.localhost + + # Download and run BrowserStack local + - &setup_browserstack + name : Download BrowserStack Local binary and start it. + command : | + # Download the browserstack binary file + wget "https://www.browserstack.com/browserstack-local/BrowserStackLocal-linux-x64.zip" + # Unzip it + unzip BrowserStackLocal-linux-x64.zip + # Run the file with user's access key + ./BrowserStackLocal ${BROWSERSTACK_ACCESS_KEY} & + + - &unit_test_steps + - checkout + - restore_cache: *restore_dep_cache + - run: npm install + - save_cache: *save_dep_cache + - run: *install + - run: *setup_browserstack + - run: *run_unit_test + + - &endtoend_test_steps + - checkout + - restore_cache: *restore_dep_cache + - run: npm install + - save_cache: *save_dep_cache + - run: *install + - run: *setup_browserstack + - run: *run_endtoend_test + version: 2 jobs: build: - docker: - # specify the version you desire here - - image: circleci/node:7.10 + <<: *environment + steps: *unit_test_steps - # Specify service dependencies here if necessary - # CircleCI maintains a library of pre-built images - # documented at https://circleci.com/docs/2.0/circleci-images/ - # - image: circleci/mongo:3.4.4 - - working_directory: ~/Prebid.js - - steps: - - checkout - - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "package.json" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - - - run: npm install - - - save_cache: - paths: - - node_modules - key: v1-dependencies-{{ checksum "package.json" }} - - - run: sudo npm install -g gulp-cli - # Download and run BrowserStack local - - run: - name : Download BrowserStack Local binary and start it. - command : | - # Download the browserstack binary file - wget "https://www.browserstack.com/browserstack-local/BrowserStackLocal-linux-x64.zip" - # Unzip it - unzip BrowserStackLocal-linux-x64.zip - # Run the file with user's access key - ./BrowserStackLocal ${BROWSERSTACK_ACCESS_KEY} & - # run tests! - - run: - name: BrowserStack testing - command: gulp test --browserstack --nolintfix + e2etest: + <<: *environment + steps: *endtoend_test_steps + +workflows: + version: 2 + commit: + jobs: + - build + nightly: + triggers: + - schedule: + cron: "0 0 * * *" + filters: + branches: + only: + - master + jobs: + - e2etest + +experimental: + pipelines: true \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 02ff81614c7..c64ab379c52 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,6 @@ + +const allowedModules = require("./allowedModules"); + module.exports = { "env": { "browser": true, @@ -11,6 +14,10 @@ module.exports = { } }, "extends": "standard", + "plugins": [ + "prebid", + "import" + ], "globals": { "$$PREBID_GLOBAL$$": false }, @@ -21,6 +28,7 @@ module.exports = { "comma-dangle": "off", "semi": "off", "space-before-function-paren": "off", + "import/extensions": ["error", "ignorePackages"], // Exceptions below this line are temporary, so that eslint can be added into the CI process. // Violations of these styles should be fixed, and the exceptions removed over time. @@ -29,7 +37,14 @@ module.exports = { "eqeqeq": "off", "no-return-assign": "off", "no-throw-literal": "off", - "no-undef": "off", + "no-undef": 2, "no-useless-escape": "off", - } + "no-console": "error" + }, + "overrides": Object.keys(allowedModules).map((key) => ({ + "files": key + "/**/*.js", + "rules": { + "prebid/validate-imports": ["error", allowedModules[key]] + } + })) }; diff --git a/.gitignore b/.gitignore index 88e849a35ad..c0452b7b3d0 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ build/coverage/ .idea/ # if you remove the above rule, at least ignore the following: +# VS Code +.vscode/ + # User-specific stuff: # .idea/workspace.xml # .idea/tasks.xml diff --git a/.nvmrc b/.nvmrc index 4fedf1d20e1..66df3b7ab2d 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -7.0 +12.16.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b82b249fa36..016f4055216 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ commit your changes, and [open a pull request](https://help.github.com/articles/ master branch. Pull requests must have 80% code coverage before beign considered for merge. -Additional details about the process can be found [here](./pr_review.md). +Additional details about the process can be found [here](./PR_REVIEW.md). ## Issues [prebid.org](http://prebid.org/) contains documentation that may help answer questions you have about using Prebid.js. @@ -48,8 +48,10 @@ When you are adding code to Prebid.js, or modifying code that isn't covered by a - _Assert_: check that the expected results have occurred - e.g., use Chai assertions to check that the expected output is equal to the actual output - Test the public interface, not the internal implementation -- If you need to check `adloader.loadScript` in a test, use a `stub` rather than a `spy`. `spy`s trigger a network call which can result in a `script error` and cause unrelated unit tests to fail. `stub`s will let you gather information about the `adloader.loadScript` call without affecting external resources +- If you need to check `adloader.loadExternalScript` in a test, use a `stub` rather than a `spy`. `spy`s trigger a network call which can result in a `script error` and cause unrelated unit tests to fail. `stub`s will let you gather information about the `adloader.loadExternalScript` call without affecting external resources +- If your test makes ajax requests, use the global xhr stub in `test/mocks/xhr`. Do not use your own `sinon.useFakeXMLHttpRequest()` or `sinon.createFakeServer()`. - When writing tests you may use ES2015 syntax if desired +- If your test relies on `Window` or `global` object, do not mutate that object directly. Instead, create a separate copy of that object and perform operations on that new copy. ### Test Examples Prebid.js already has many tests. Read them to see how Prebid.js is tested, and for inspiration: diff --git a/PR_REVIEW.md b/PR_REVIEW.md index d5799472377..dac50593d6e 100644 --- a/PR_REVIEW.md +++ b/PR_REVIEW.md @@ -14,6 +14,16 @@ For modules and core platform updates, the initial reviewer should request an ad - Review for obvious errors or bad coding practice / use best judgement here. - If the change is a new feature / change to core prebid.js - review the change with a Tech Lead on the project and make sure they agree with the nature of change. - If the change results in needing updates to docs (such as public API change, module interface etc), add a label for "needs docs" and inform the submitter they must submit a docs PR to update the appropriate area of Prebid.org **before the PR can merge**. Help them with finding where the docs are located on prebid.org if needed. + - Below are some examples of bidder specific updates that should require docs update (in their dev-docs/bidders/bidder.md file): + - If they support the GDPR consentManagement module and TCF1, add `gdpr_supported: true` + - If they support the GDPR consentManagement module and TCF2, add `tcf2_supported: true` + - If they support the US Privacy consentManagementUsp module, add `usp_supported: true` + - If they support one or more userId modules, add `userId: (list of supported vendors)` + - If they support video and/or native mediaTypes add `media_types: video, native`. Note that display is added by default. If you don't support display, add "no-display" as the first entry, e.g. `media_types: no-display, native` + - If they support COPPA, add `coppa_supported: true` + - If they support SChain, add `schain_supported: true` + - If their bidder doesn't work well with safeframed creatives, add `safeframes_ok: false`. This will alert publishers to not use safeframed creatives when creating the ad server entries for their bidder. + - If they're a member of Prebid.org, add `prebid_member: true` - If all above is good, add a `LGTM` comment and request 1 additional core member to review. - Once there is 2 `LGTM` on the PR, merge to master - Ask the submitter to add a PR for documentation if applicable. @@ -24,7 +34,7 @@ For modules and core platform updates, the initial reviewer should request an ad - Follow steps above for general review process. In addition, please verify the following: - Verify that bidder has submitted valid bid params and that bids are being received. - Verify that bidder is not manipulating the prebid.js auction in any way or doing things that go against the principles of the project. If unsure check with the Tech Lead. -- Verify that the bidder is being as efficient as possible, ideally not loading an external library, however if they do load a library it should be cached. +- Verify that the bidder is being as efficient as possible, ideally not loading an external library, however if they do load a library it should be cached. - Verify that code re-use is being done properly and that changes introduced by a bidder don't impact other bidders. - If the adapter being submitted is an alias type, check with the bidder contact that is being aliased to make sure it's allowed. - If the adapter is triggering any user syncs make sure they are using the user sync module in the Prebid.js core. @@ -39,11 +49,16 @@ For modules and core platform updates, the initial reviewer should request an ad ## Ticket Coordinator -Each week, Prebid Org assigns one person to keep an eye on incoming issues and PRs. That person should: +Each week, Prebid Org assigns one person to keep an eye on incoming issues and PRs. Every Monday morning a reminder is +sent to the prebid-js slack channel with a link to the spreadsheet. If you're on rotation, please check that list each +Monday to see if you're on-duty. + +When on-duty: - Review issues and PRs at least once per weekday for new items. Encourage a 48 "SLA" on PRs/issues assigned. Aim for touchpoint once every 48/hours. -- For PRs: assign PRs to individuals on the PR review list. Try to be equitable -- not all PRs are created equally. Use the "Assigned" field and add the "Needs Review" label. +- For PRs: assign PRs to individuals on the **PR review list**. Try to be equitable -- not all PRs are created equally. Use the "Assigned" field and add the "Needs Review" label. - For Issues: try to address questions and troubleshooting requests on your own, assigning them to others as needed. Please add labels as appropriate (I.E. bug, question, backlog etc). - Issues that are questions or troubleshooting requests may be closed if the originator doesn't respond within a week to requests for confirmation or details. - Issues that are bug reports should be left open and assigned to someone in PR rotation to confirm or deny the bug status. -- It's polite to check with others before assigning them large tasks. -- If possible, check in on older items and see if they can be unstuck. +- It's polite to check with others before assigning them extra-large tasks. +- If possible, check in on older PRs and Issues and see if they can be unstuck. +- Perform the weekly Prebid.js release per instructions at https://github.com/prebid/Prebid.js/blob/master/RELEASE_SCHEDULE.md . This generally takes place on Tues or Weds. diff --git a/README.md b/README.md index 21e02ebee7f..0dd5b25a50f 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ module.exports = { // override the regular exclusion from above (for being inside node_modules). { test: /.js$/, - include: new RegExp(`\\${path.sep}prebid\.js`), + include: new RegExp(`\\${path.sep}prebid\\.js`), use: { loader: 'babel-loader', // presets and plugins for Prebid.js must be manually specified separate from your other babel rule. @@ -66,7 +66,7 @@ module.exports = { } ``` -Or for Babel 6 and/or Node v8.6.0 and less: +Or for Babel 6: ```javascript // you must manually install and specify the presets and plugins yourself options: { @@ -112,9 +112,9 @@ prebid.requestBids({ $ cd Prebid.js $ npm install -*Note:* You need to have `NodeJS` 6.x or greater installed. +*Note:* You need to have `NodeJS` 12.16.1 or greater installed. -*Note:* In the 1.24.0 release of Prebid.js we have transitioned to using gulp 4.0 from using gulp 3.9.1. To compily with gulp's recommended setup for 4.0, you'll need to have `gulp-cli` installed globally prior to running the general `npm install`. This shouldn't impact any other projects you may work on that use an earlier version of gulp in it's setup. +*Note:* In the 1.24.0 release of Prebid.js we have transitioned to using gulp 4.0 from using gulp 3.9.1. To comply with gulp's recommended setup for 4.0, you'll need to have `gulp-cli` installed globally prior to running the general `npm install`. This shouldn't impact any other projects you may work on that use an earlier version of gulp in its setup. If you have a previous version of `gulp` installed globally, you'll need to remove it before installing `gulp-cli`. You can check if this is installed by running `gulp -v` and seeing the version that's listed in the `CLI` field of the output. If you have the `gulp` package installed globally, it's likely the same version that you'll see in the `Local` field. If you already have `gulp-cli` installed, it should be a lower major version (it's at version `2.0.1` at the time of the transition). diff --git a/allowedModules.js b/allowedModules.js new file mode 100644 index 00000000000..2a521f781f9 --- /dev/null +++ b/allowedModules.js @@ -0,0 +1,27 @@ + +const sharedWhiteList = [ + 'core-js-pure/features/array/find', // no ie11 + 'core-js-pure/features/array/includes', // no ie11 + 'core-js-pure/features/set', // ie11 supports Set but not Set#values + 'core-js-pure/features/string/includes', // no ie11 + 'core-js-pure/features/number/is-integer', // no ie11, + 'core-js-pure/features/array/from' // no ie11 +]; + +module.exports = { + 'modules': [ + ...sharedWhiteList, + 'criteo-direct-rsa-validate', + 'jsencrypt', + 'crypto-js', + 'live-connect' // Maintained by LiveIntent : https://github.com/liveintent-berlin/live-connect/ + ], + 'src': [ + ...sharedWhiteList, + 'fun-hooks/no-eval', + 'just-clone', + 'dlv', + 'dset', + 'deep-equal' + ] +}; diff --git a/browsers.json b/browsers.json index 8604e44a7b8..91e0548d78a 100644 --- a/browsers.json +++ b/browsers.json @@ -1,17 +1,17 @@ { - "bs_edge_16_windows_10": { + "bs_edge_17_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "edge", - "browser_version": "16.0", + "browser_version": "17.0", "device": null, "os": "Windows" }, - "bs_edge_17_windows_10": { + "bs_edge_18_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "edge", - "browser_version": "17.0", + "browser_version": "18.0", "device": null, "os": "Windows" }, @@ -23,43 +23,43 @@ "device": null, "os": "Windows" }, - "bs_chrome_72_windows_10": { + "bs_chrome_80_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "chrome", - "browser_version": "72.0", + "browser_version": "80.0", "device": null, "os": "Windows" }, - "bs_chrome_71_windows_10": { + "bs_chrome_79_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "chrome", - "browser_version": "71.0", + "browser_version": "79.0", "device": null, "os": "Windows" }, - "bs_firefox_65_windows_10": { + "bs_firefox_73_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "firefox", - "browser_version": "65.0", + "browser_version": "73.0", "device": null, "os": "Windows" }, - "bs_firefox_64_windows_10": { + "bs_firefox_72_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "firefox", - "browser_version": "64.0", + "browser_version": "72.0", "device": null, "os": "Windows" }, - "bs_safari_11_mac_high_sierra": { + "bs_safari_11_mac_catalina": { "base": "BrowserStack", - "os_version": "High Sierra", + "os_version": "Catalina", "browser": "safari", - "browser_version": "11.1", + "browser_version": "13.0", "device": null, "os": "OS X" }, @@ -71,4 +71,4 @@ "device": null, "os": "OS X" } -} \ No newline at end of file +} diff --git a/gulpHelpers.js b/gulpHelpers.js index f20a2673ade..bcaf3736f15 100644 --- a/gulpHelpers.js +++ b/gulpHelpers.js @@ -6,6 +6,7 @@ const MANIFEST = 'package.json'; const through = require('through2'); const _ = require('lodash'); const gutil = require('gulp-util'); +const submodules = require('./modules/.submodules.json'); const MODULE_PATH = './modules'; const BUILD_PATH = './build/dist'; @@ -39,7 +40,9 @@ module.exports = { .replace(/\/>/g, '\\/>'); }, getArgModules() { - var modules = (argv.modules || '').split(',').filter(module => !!module); + var modules = (argv.modules || '') + .split(',') + .filter(module => !!module); try { if (modules.length === 1 && path.extname(modules[0]).toLowerCase() === '.json') { @@ -56,6 +59,16 @@ module.exports = { }); } + // we need to forcefuly include the parentModule if the subModule is present in modules list and parentModule is not present in modules list + Object.keys(submodules).forEach(parentModule => { + if ( + !modules.includes(parentModule) && + modules.some(module => submodules[parentModule].includes(module)) + ) { + modules.unshift(parentModule); + } + }); + return modules; }, getModules: _.memoize(function(externalModules) { @@ -71,7 +84,9 @@ module.exports = { if (fs.lstatSync(modulePath).isDirectory()) { modulePath = path.join(modulePath, 'index.js') } - memo[modulePath] = moduleName; + if (fs.existsSync(modulePath)) { + memo[modulePath] = moduleName; + } return memo; }, {}); } catch (err) { @@ -79,7 +94,10 @@ module.exports = { } return Object.assign(externalModules.reduce((memo, module) => { try { - var modulePath = require.resolve(module); + // prefer internal project modules before looking at project dependencies + var modulePath = require.resolve(module, {paths: ['./modules']}); + if (modulePath === '') modulePath = require.resolve(module); + memo[modulePath] = module; } catch (err) { // do something diff --git a/gulpfile.js b/gulpfile.js index a89f570e496..58e294bc559 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ 'use strict'; var _ = require('lodash'); @@ -32,6 +33,9 @@ var prebid = require('./package.json'); var dateString = 'Updated : ' + (new Date()).toISOString().substring(0, 10); var banner = '/* <%= prebid.name %> v<%= prebid.version %>\n' + dateString + ' */\n'; var port = 9999; +const FAKE_SERVER_HOST = argv.host ? argv.host : 'localhost'; +const FAKE_SERVER_PORT = 4444; +const { spawn } = require('child_process'); // these modules must be explicitly listed in --modules to be included in the build, won't be part of "all" modules var explicitModules = [ @@ -64,11 +68,11 @@ function lint(done) { if (argv.nolint) { return done(); } - const isFixed = function(file) { + const isFixed = function (file) { return file.eslint != null && file.eslint.fixed; } - return gulp.src(['src/**/*.js', 'modules/**/*.js', 'test/**/*.js'], {base: './'}) - .pipe(gulpif(argv.nolintfix, eslint(), eslint({fix: true}))) + return gulp.src(['src/**/*.js', 'modules/**/*.js', 'test/**/*.js'], { base: './' }) + .pipe(gulpif(argv.nolintfix, eslint(), eslint({ fix: true }))) .pipe(eslint.format('stylish')) .pipe(eslint.failAfterError()) .pipe(gulpif(isFixed, gulp.dest('./'))); @@ -81,7 +85,7 @@ function viewCoverage(done) { connect.server({ port: coveragePort, - root: 'build/coverage/karma_html', + root: 'build/coverage/lcov-report', livereload: false }); opens('http://' + mylocalhost + ':' + coveragePort); @@ -157,7 +161,7 @@ function nodeBundle(modules) { .on('error', (err) => { reject(err); }) - .pipe(through.obj(function(file, enc, done) { + .pipe(through.obj(function (file, enc, done) { resolve(file.contents.toString(enc)); done(); })); @@ -196,7 +200,7 @@ function bundle(dev, moduleArr) { return gulp.src( entries ) - .pipe(gulpif(dev, sourcemaps.init({loadMaps: true}))) + .pipe(gulpif(dev, sourcemaps.init({ loadMaps: true }))) .pipe(concat(outputFileName)) .pipe(gulpif(!argv.manualEnable, footer('\n<%= global %>.processQueue();', { global: prebid.globalVarName @@ -205,18 +209,6 @@ function bundle(dev, moduleArr) { .pipe(gulpif(dev, sourcemaps.write('.'))); } -// Workaround for incompatibility between Karma & gulp callbacks. -// See https://github.com/karma-runner/gulp-karma/issues/18 for some related discussion. -function newKarmaCallback(done) { - return function (exitCode) { - if (exitCode) { - done(new Error('Karma tests failed with exit code ' + exitCode)); - } else { - done(); - } - } -} - // Run the unit tests. // // By default, this runs in headless chrome. @@ -226,16 +218,49 @@ function newKarmaCallback(done) { // If --browserstack is given, it will run the full suite of currently supported browsers. // If --browsers is given, browsers can be chosen explicitly. e.g. --browsers=chrome,firefox,ie9 // If --notest is given, it will immediately skip the test task (useful for developing changes with `gulp serve --notest`) + function test(done) { if (argv.notest) { done(); } else if (argv.e2e) { let wdioCmd = path.join(__dirname, 'node_modules/.bin/wdio'); let wdioConf = path.join(__dirname, 'wdio.conf.js'); - let wdioOpts = [ - wdioConf - ]; - return execa(wdioCmd, wdioOpts, { stdio: 'inherit' }); + let wdioOpts; + + if (argv.file) { + wdioOpts = [ + wdioConf, + `--spec`, + `${argv.file}` + ] + } else { + wdioOpts = [ + wdioConf + ]; + } + + // run fake-server + const fakeServer = spawn('node', ['./test/fake-server/index.js', `--port=${FAKE_SERVER_PORT}`]); + fakeServer.stdout.on('data', (data) => { + console.log(`stdout: ${data}`); + }); + fakeServer.stderr.on('data', (data) => { + console.log(`stderr: ${data}`); + }); + + execa(wdioCmd, wdioOpts, { stdio: 'inherit' }) + .then(stdout => { + // kill fake server + fakeServer.kill('SIGINT'); + done(); + process.exit(0); + }) + .catch(err => { + // kill fake server + fakeServer.kill('SIGINT'); + done(new Error(`Tests failed with error: ${err}`)); + process.exit(1); + }); } else { var karmaConf = karmaConfMaker(false, argv.browserstack, argv.watch, argv.file); @@ -248,6 +273,22 @@ function test(done) { } } +function newKarmaCallback(done) { + return function (exitCode) { + if (exitCode) { + done(new Error('Karma tests failed with exit code ' + exitCode)); + if (argv.browserstack) { + process.exit(exitCode); + } + } else { + done(); + if (argv.browserstack) { + process.exit(exitCode); + } + } + } +} + // If --file "" is given, the task will only run tests in the specified file. function testCoverage(done) { new KarmaServer(karmaConfMaker(true, false, false, argv.file), newKarmaCallback(done)).start(); @@ -256,7 +297,7 @@ function testCoverage(done) { function coveralls() { // 2nd arg is a dependency: 'test' must be finished // first send results of istanbul's test coverage to coveralls.io. return gulp.src('gulpfile.js', { read: false }) // You have to give it a file, but you don't - // have to read it. + // have to read it. .pipe(shell('cat build/coverage/lcov.info | node_modules/coveralls/bin/coveralls.js')); } @@ -286,6 +327,28 @@ function setupE2e(done) { done(); } +function injectFakeServerEndpoint() { + return gulp.src(['build/dist/*.js']) + .pipe(replace('https://ib.adnxs.com/ut/v3/prebid', `http://${FAKE_SERVER_HOST}:${FAKE_SERVER_PORT}`)) + .pipe(gulp.dest('build/dist')); +} + +function injectFakeServerEndpointDev() { + return gulp.src(['build/dev/*.js']) + .pipe(replace('https://ib.adnxs.com/ut/v3/prebid', `http://${FAKE_SERVER_HOST}:${FAKE_SERVER_PORT}`)) + .pipe(gulp.dest('build/dev')); +} + +function startFakeServer() { + const fakeServer = spawn('node', ['./test/fake-server/index.js', `--port=${FAKE_SERVER_PORT}`]); + fakeServer.stdout.on('data', (data) => { + console.log(`stdout: ${data}`); + }); + fakeServer.stderr.on('data', (data) => { + console.log(`stderr: ${data}`); + }); +} + // support tasks gulp.task(lint); gulp.task(watch); @@ -309,9 +372,11 @@ gulp.task('build', gulp.series(clean, 'build-bundle-prod')); gulp.task('build-postbid', gulp.series(escapePostbidConfig, buildPostbid)); gulp.task('serve', gulp.series(clean, lint, gulp.parallel('build-bundle-dev', watch, test))); +gulp.task('serve-fake', gulp.series(clean, gulp.parallel('build-bundle-dev', watch), injectFakeServerEndpointDev, test, startFakeServer)); + gulp.task('default', gulp.series(clean, makeWebpackPkg)); -gulp.task('e2e-test', gulp.series(clean, setupE2e, gulp.parallel('build-bundle-dev', watch), test)) +gulp.task('e2e-test', gulp.series(clean, setupE2e, gulp.parallel('build-bundle-prod', watch), injectFakeServerEndpoint, test)); // other tasks gulp.task(bundleToStdout); gulp.task('bundle', gulpBundle.bind(null, false)); // used for just concatenating pre-built files with no build step diff --git a/integrationExamples/gpt/advanced_size_mapping.html b/integrationExamples/gpt/advanced_size_mapping.html new file mode 100644 index 00000000000..4f1ba085c77 --- /dev/null +++ b/integrationExamples/gpt/advanced_size_mapping.html @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+
+ +
+ + + diff --git a/integrationExamples/gpt/audienceNetwork_dfp.html b/integrationExamples/gpt/audienceNetwork_dfp.html deleted file mode 100644 index b30df31b276..00000000000 --- a/integrationExamples/gpt/audienceNetwork_dfp.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - -

Prebid.js Test

-
- -
-
-

Audience Network quick start

-
    -
  1. Create a new App at https://developers.facebook.com/apps
  2. -
  3. Add the Audience Network product to it
  4. -
  5. Create a new Placement to generate your placementId
  6. -
  7. To test, ensure the User-Agent request header represents a mobile device
  8. -
-
- - diff --git a/integrationExamples/gpt/audigentSegments_example.html b/integrationExamples/gpt/audigentSegments_example.html new file mode 100644 index 00000000000..7739b558327 --- /dev/null +++ b/integrationExamples/gpt/audigentSegments_example.html @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + +

Audigent Segments Prebid

+ +
+ +
+TDID: +
+
+ +Audigent Segments: +
+
+ + diff --git a/integrationExamples/gpt/cmp_files/purposes.json b/integrationExamples/gpt/cmp_files/purposes.json new file mode 100644 index 00000000000..04219e92ce4 --- /dev/null +++ b/integrationExamples/gpt/cmp_files/purposes.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "purposes": [ + { + "id": 25, + "name": "Custom Purpose 1", + "description": "Here's a description of the first purpose" + }, + { + "id": 26, + "name": "Custom Purpose 2", + "description": "Here's a description of the second purpose" + }, + { + "id": 27, + "name": "Custom Purpose 3", + "description": "Here's a description of the third purpose" + }, + { + "id": 28, + "name": "Custom Purpose 4", + "description": "Here's a description of the fourth purpose" + } + ] +} diff --git a/integrationExamples/gpt/digitrust_Full.html b/integrationExamples/gpt/digitrust_Full.html new file mode 100644 index 00000000000..fc7704776f4 --- /dev/null +++ b/integrationExamples/gpt/digitrust_Full.html @@ -0,0 +1,222 @@ + + + Full DigiTrust Prebid Sample + + + + + + + + + + + + + +

DigiTrust Prebid Full Sample

+ + +

+ This sample shows the simplest integration path for using DigiTrust ID with Prebid. + You can use DigiTrust ID without integrating the entire DigiTrust suite. +

+ +
+ +
+ +
+ + + + diff --git a/integrationExamples/gpt/digitrust_Simple.html b/integrationExamples/gpt/digitrust_Simple.html new file mode 100644 index 00000000000..2581c6ce7cc --- /dev/null +++ b/integrationExamples/gpt/digitrust_Simple.html @@ -0,0 +1,230 @@ + + + Simple DigiTrust Prebid - No Framework + + + + + + + + + + + + + + +

DigiTrust Prebid Sample - No Framework

+ +

+ This sample shows the simplest integration path for using DigiTrust ID with Prebid. + You can use DigiTrust ID without integrating the entire DigiTrust suite. +

+
+ +
+ +
+ + diff --git a/integrationExamples/gpt/digitrust_cmp_test.html b/integrationExamples/gpt/digitrust_cmp_test.html new file mode 100644 index 00000000000..6f0a70188f3 --- /dev/null +++ b/integrationExamples/gpt/digitrust_cmp_test.html @@ -0,0 +1,192 @@ + + + CMP Simple DigiTrust Prebid - No Framework + + + + + + + + + + + + + +

DigiTrust Prebid Sample - No Framework

+ +

+ This sample tests cmp behavior with simple integration path for using DigiTrust ID with Prebid. + You can use DigiTrust ID without integrating the entire DigiTrust suite. +

+
+ +
+ +
+ + + diff --git a/integrationExamples/gpt/gdpr_hello_world.html b/integrationExamples/gpt/gdpr_hello_world.html index 84efb5b7596..de0630178f1 100644 --- a/integrationExamples/gpt/gdpr_hello_world.html +++ b/integrationExamples/gpt/gdpr_hello_world.html @@ -1,5 +1,7 @@ + + - - - + setTimeout(function() { + sendAdserverRequest(); + console.log('timeout in main pbjs fired'); + }, FAILSAFE_TIMEOUT); + - \ No newline at end of file + diff --git a/integrationExamples/gpt/gpt_aliasingBidder.html b/integrationExamples/gpt/gpt_aliasingBidder.html deleted file mode 100644 index 693be76e82e..00000000000 --- a/integrationExamples/gpt/gpt_aliasingBidder.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - - -

Prebid.js Test

- -
- -
- - -
- -
- - - - - - - diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html old mode 100644 new mode 100755 index e1cdaa0dc29..47ba5b8f18a --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -8,94 +8,84 @@ --> - - + + - - - + + - - - - + + - - - -

Prebid.js Test

-
Div-1
-
- + + + +

Prebid.js Test

+
Div-1
+
+ -
- - \ No newline at end of file + +
+ + \ No newline at end of file diff --git a/integrationExamples/gpt/hello_world_emoteev.html b/integrationExamples/gpt/hello_world_emoteev.html deleted file mode 100644 index 5a33e2d9701..00000000000 --- a/integrationExamples/gpt/hello_world_emoteev.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - -

Basic Prebid.js Example

-
Div-1
-
- -
- - - diff --git a/integrationExamples/gpt/inskin_example.html b/integrationExamples/gpt/inskin_example.html new file mode 100644 index 00000000000..197a5b1ffe1 --- /dev/null +++ b/integrationExamples/gpt/inskin_example.html @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+
+ +
+ + diff --git a/integrationExamples/gpt/load_pbjs_before_dfp_example.html b/integrationExamples/gpt/load_pbjs_before_dfp_example.html deleted file mode 100644 index cb17b8c3348..00000000000 --- a/integrationExamples/gpt/load_pbjs_before_dfp_example.html +++ /dev/null @@ -1,265 +0,0 @@ - - - - - - -

Prebid.js Test

-
- -
-
- -
- - diff --git a/integrationExamples/gpt/load_pbjs_dfp_concurrently.html b/integrationExamples/gpt/load_pbjs_dfp_concurrently.html deleted file mode 100644 index 0d6270ba7a5..00000000000 --- a/integrationExamples/gpt/load_pbjs_dfp_concurrently.html +++ /dev/null @@ -1,282 +0,0 @@ - - - - - - -

Prebid.js Test

-
- -
-
- -
- - diff --git a/integrationExamples/gpt/pbjs_example_gpt.html b/integrationExamples/gpt/pbjs_example_gpt.html deleted file mode 100644 index 3a32eb5dbd6..00000000000 --- a/integrationExamples/gpt/pbjs_example_gpt.html +++ /dev/null @@ -1,633 +0,0 @@ - - - -Prebid.js integration example - - - - -

Prebid.js Test

- -
- -
- - -
- -
- - - - - - - diff --git a/integrationExamples/gpt/pbjs_innity_gpt.html b/integrationExamples/gpt/pbjs_innity_gpt.html deleted file mode 100644 index 7882d44791d..00000000000 --- a/integrationExamples/gpt/pbjs_innity_gpt.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -

Prebid.js Test

-
Div-1
-
- -
- - \ No newline at end of file diff --git a/integrationExamples/gpt/pbjs_partial_refresh_gpt.html b/integrationExamples/gpt/pbjs_partial_refresh_gpt.html deleted file mode 100644 index 09009a24d76..00000000000 --- a/integrationExamples/gpt/pbjs_partial_refresh_gpt.html +++ /dev/null @@ -1,296 +0,0 @@ - - - - - - - - - - - - - -

Prebid.js Test

- -
Div-1, 300x250 or 300x600
- - - -
- -
- - -
Div-2, 728x90 or 970x90
- - - - -
- -
- - - - - diff --git a/integrationExamples/gpt/pbjs_yieldbot_gpt.html b/integrationExamples/gpt/pbjs_yieldbot_gpt.html deleted file mode 100644 index 986eed8fc5e..00000000000 --- a/integrationExamples/gpt/pbjs_yieldbot_gpt.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - -

Prebid.js Yieldbot Adapter Basic Example

- Use the links below to enable and disable Yieldbot test bids.
-
- Note: -
- The "Enable - Yieldbot Test Bids" link below will set a cookie to force Yieldbot bid requests to return static test creative: the cookie expires in 24 hrs. -
- -
    -
  1. Enable - Yieldbot Test Bids
  2. -
  3. Disable - Yieldbot Test Bids
  4. -
-
Div-0, 728x90
- -
- -
-
Div-1, 300x250 or 300x600
- -
- -
-
Div-2, 300x250 or 300x600
- The bid for the 300x250 | 300x600 slot is shown under Div-1 above. - - -
- -
- - diff --git a/integrationExamples/gpt/pollux_example.html b/integrationExamples/gpt/pollux_example.html deleted file mode 100644 index 56eedbf2a9c..00000000000 --- a/integrationExamples/gpt/pollux_example.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - - test - - - -
- -
- -
-
- -
- -
- - \ No newline at end of file diff --git a/integrationExamples/gpt/prebidServer_example.html b/integrationExamples/gpt/prebidServer_example.html index f13c93963c6..7761178efa8 100644 --- a/integrationExamples/gpt/prebidServer_example.html +++ b/integrationExamples/gpt/prebidServer_example.html @@ -36,12 +36,16 @@ pbjs.que.push(function() { var adUnits = [{ code: 'div-gpt-ad-1460505748561-0', - sizes: [[300, 250]], + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, bids: [ { bidder: 'appnexus', params: { - placementId: '13144370' + placementId: 13144370 } } ] diff --git a/integrationExamples/gpt/prebidServer_native_example.html b/integrationExamples/gpt/prebidServer_native_example.html new file mode 100644 index 00000000000..16c7d38a427 --- /dev/null +++ b/integrationExamples/gpt/prebidServer_native_example.html @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + +

Prebid Native

+
+

No response

+ +
+ +
+
+ +
+

No response

+ +
+ + + + diff --git a/integrationExamples/gpt/proxistore_example.html b/integrationExamples/gpt/proxistore_example.html new file mode 100644 index 00000000000..acd95baef2a --- /dev/null +++ b/integrationExamples/gpt/proxistore_example.html @@ -0,0 +1,118 @@ + + + + + + + + + + + + + +

Prebid.js Test

+ +
Div-1
+ +
+ +
+ + + \ No newline at end of file diff --git a/integrationExamples/gpt/revcontent_example.html b/integrationExamples/gpt/revcontent_example.html new file mode 100644 index 00000000000..d7a44df3014 --- /dev/null +++ b/integrationExamples/gpt/revcontent_example.html @@ -0,0 +1,109 @@ + + + + + + + + + + + +

Basic Prebid.js Example

+
Div-1
+
+ +
+ + + \ No newline at end of file diff --git a/integrationExamples/gpt/unruly_example.html b/integrationExamples/gpt/unruly_example.html deleted file mode 100644 index 038951b9eb8..00000000000 --- a/integrationExamples/gpt/unruly_example.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - test - - - -
- -
- - - diff --git a/integrationExamples/gpt/userId_example.html b/integrationExamples/gpt/userId_example.html index d64e22e44c7..3bb8ce2df66 100644 --- a/integrationExamples/gpt/userId_example.html +++ b/integrationExamples/gpt/userId_example.html @@ -140,7 +140,24 @@ name: "unifiedid", expires: 30 }, - + }, { + name: "id5Id", + params: { + partner: 173 //Set your real ID5 partner ID here for production, please ask for one at http://id5.io/prebid + }, + storage: { + type: "cookie", + name: "id5id", + expires: 90, + refreshInSeconds: 8*3600 // Refresh frequency of cookies, defaulting to 'expires' + }, + + }, { + name: "parrableId", + params: { + // change to Parrable Partner Client ID(s) you received from the Parrable Partners you are using + partner: '30182847-e426-4ff9-b2b5-9ca1324ea09b' + } }, { name: "pubCommonId", storage: { @@ -152,8 +169,19 @@ // foo: '9879878907987', // bar:'93939' // } + }, { + name: 'identityLink', + params: { + pid: '14' // Set your real identityLink placement ID here + }, + storage: { + type: 'cookie', + name: 'idl_env', + expires: 30 + } }], - syncDelay: 5000 + syncDelay: 5000, + auctionDelay: 1000 } }); pbjs.addAdUnits(adUnits); diff --git a/integrationExamples/gpt/x-domain/creative.html b/integrationExamples/gpt/x-domain/creative.html index 3b0058f2ee8..fce46bb380f 100644 --- a/integrationExamples/gpt/x-domain/creative.html +++ b/integrationExamples/gpt/x-domain/creative.html @@ -2,10 +2,10 @@ // this script can be returned by an ad server delivering a cross domain iframe, into which the // creative will be rendered, e.g. DFP delivering a SafeFrame +let windowLocation = window.location; var urlParser = document.createElement('a'); urlParser.href = '%%PATTERN:url%%'; var publisherDomain = urlParser.protocol + '//' + urlParser.hostname; -var adServerDomain = urlParser.protocol + '//tpc.googlesyndication.com'; function renderAd(ev) { var key = ev.message ? 'message' : 'data'; @@ -57,8 +57,7 @@ function requestAdFromPrebid() { var message = JSON.stringify({ message: 'Prebid Request', - adId: '%%PATTERN:hb_adid%%', - adServerDomain: adServerDomain + adId: '%%PATTERN:hb_adid%%' }); window.parent.postMessage(message, publisherDomain); } diff --git a/integrationExamples/longform/basic_w_bidderSettings.html b/integrationExamples/longform/basic_w_bidderSettings.html new file mode 100644 index 00000000000..fb87ea5d990 --- /dev/null +++ b/integrationExamples/longform/basic_w_bidderSettings.html @@ -0,0 +1,148 @@ + + + + + Prebid Freewheel Integration Demo + + + + + + + + + + + + + + + + + + + +

Prebid Freewheel Test Page

+

requireExactDuration = false

+
+
+ +
+
+
+
+

+ +

+
+
+
+ // bids +
+
+
+
+
+

+ +

+
+
+
+ // bids +
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/integrationExamples/longform/basic_w_custom_adserver_translation.html b/integrationExamples/longform/basic_w_custom_adserver_translation.html index 995ea822da4..2dbb89506b5 100644 --- a/integrationExamples/longform/basic_w_custom_adserver_translation.html +++ b/integrationExamples/longform/basic_w_custom_adserver_translation.html @@ -5,7 +5,11 @@ Prebid Freewheel Integration Demo - + + + + - + + + + + + + + + + + + + + + + +

Prebid Freewheel Test Page

+

requireExactDuration = false

+
+
+ +
+
+
+
+

+ +

+
+
+
+ // bids +
+
+
+
+
+

+ +

+
+
+
+ // bids +
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/integrationExamples/longform/basic_w_requireExactDuration.html b/integrationExamples/longform/basic_w_requireExactDuration.html index 016b51d09c4..46b91887cfb 100644 --- a/integrationExamples/longform/basic_w_requireExactDuration.html +++ b/integrationExamples/longform/basic_w_requireExactDuration.html @@ -5,7 +5,11 @@ Prebid Freewheel Integration Demo - + + + + - + - + + - + + + + - + + + +
+ + + `; +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid(bid) { + return ( + getMediaTypeFromBid(bid) === BANNER && + !!bid.params.placeId && + !!bid.params.imageUrl && + !!bid.params.placement && + (bid.params.placement === 'inImage') + ); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests(validBidRequests, bidderRequest) { + const payload = { + url: bidderRequest.refererInfo.referer, + cmp: !!bidderRequest.gdprConsent, + bidRequests: buildBidRequests(validBidRequests) + }; + + if (payload.cmp) { + const gdprApplies = bidderRequest.gdprConsent.gdprApplies; + if (gdprApplies !== undefined) payload['ga'] = gdprApplies; + payload['cs'] = bidderRequest.gdprConsent.consentString; + } + + const payloadString = JSON.stringify(payload); + return { + method: 'POST', + url: SSP_ENDPOINT, + data: payloadString, + options: { + contentType: 'application/json' + } + } + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse) { + const serverBody = serverResponse.body; + if (serverBody && utils.isArray(serverBody)) { + return utils._map(serverBody, function(bid) { + return buildBid(bid); + }); + } else { + return []; + } + } + +} +registerBidder(spec); diff --git a/modules/astraoneBidAdapter.md b/modules/astraoneBidAdapter.md new file mode 100644 index 00000000000..a7eaeeef5a4 --- /dev/null +++ b/modules/astraoneBidAdapter.md @@ -0,0 +1,198 @@ +# Overview + + +**Module Name**: AstraOne Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: prebid@astraone.io + +# Description + +You can use this adapter to get a bid from AstraOne. +Please reach out to your AstraOne account team before using this plugin to get placeId. +The code below returns a demo ad. + +About us: https://astraone.io + +# Test Parameters +```js +var adUnits = [{ + code: 'test-div', + mediaTypes: { + banner: { + sizes: [1, 1] + } + }, + bids: [{ + bidder: "astraone", + params: { + placement: "inImage", + placeId: "5af45ad34d506ee7acad0c26", + imageUrl: "https://creative.astraone.io/files/default_image-1-600x400.jpg" + } + }] +}]; +``` + +# Example page + +```html + + + + + Prebid.js Banner Example + + + + + + +

Prebid.js InImage Banner Test

+ +
+ + +
+ + + +``` +# Example page with GPT + +```html + + + + + Prebid.js Banner Example + + + + + + +

Prebid.js Banner Ad Unit Test

+ +
+ + + +
+ + +``` diff --git a/modules/atomxBidAdapter.js b/modules/atomxBidAdapter.js index f36419902a1..e9f15218c4c 100644 --- a/modules/atomxBidAdapter.js +++ b/modules/atomxBidAdapter.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'atomx'; @@ -60,7 +60,7 @@ export const spec = { return validBidRequests.map(bidRequest => { return { method: 'GET', - url: location.protocol + '//p.ato.mx/placement', + url: 'https://p.ato.mx/placement', data: { v: 12, id: bidRequest.params.id, diff --git a/modules/atsAnalyticsAdapter.js b/modules/atsAnalyticsAdapter.js new file mode 100644 index 00000000000..7bf2ca75c17 --- /dev/null +++ b/modules/atsAnalyticsAdapter.js @@ -0,0 +1,153 @@ +import adapter from '../src/AnalyticsAdapter.js'; +import CONSTANTS from '../src/constants.json'; +import adaptermanager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; +import {ajax} from '../src/ajax.js'; + +const analyticsType = 'endpoint'; + +let handlerRequest = []; +let handlerResponse = []; +let host = ''; + +function bidRequestedHandler(args) { + let requests; + requests = args.bids.map(function(bid) { + return { + has_envelope: bid.userId ? !!bid.userId.idl_env : false, + bidder: bid.bidder, + bid_id: bid.bidId, + auction_id: args.auctionId, + user_browser: (browserIsFirefox() || browserIsEdge() || browserIsChrome() || browserIsSafari()), + user_platform: navigator.platform, + auction_start: new Date(args.auctionStart).toJSON(), + domain: window.location.hostname, + pid: atsAnalyticsAdapter.context.pid, + }; + }); + return requests; +} + +function bidResponseHandler(args) { + return { + bid_id: args.requestId, + response_time_stamp: new Date(args.responseTimestamp).toJSON(), + currency: args.currency, + cpm: args.cpm, + net_revenue: args.netRevenue + }; +} + +export function browserIsFirefox() { + if (typeof InstallTrigger !== 'undefined') { + return 'Firefox'; + } else { + return false; + } +} + +export function browserIsIE() { + return !!document.documentMode; +} + +export function browserIsEdge() { + if (!browserIsIE() && !!window.StyleMedia) { + return 'Edge'; + } else { + return false; + } +} + +export function browserIsChrome() { + if ((!!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime)) || (/Android/i.test(navigator.userAgent) && !!window.chrome)) { + return 'Chrome'; + } else { + return false; + } +} + +export function browserIsSafari() { + if (navigator.vendor.indexOf('Apple')) { + return 'Safari' + } else { + return false; + } +} + +function callHandler(evtype, args) { + if (evtype === CONSTANTS.EVENTS.BID_REQUESTED) { + handlerRequest = handlerRequest.concat(bidRequestedHandler(args)); + } else if (evtype === CONSTANTS.EVENTS.BID_RESPONSE) { + handlerResponse.push(bidResponseHandler(args)); + } + if (evtype === CONSTANTS.EVENTS.AUCTION_END) { + if (handlerRequest.length) { + let events = []; + if (handlerResponse.length) { + events = handlerRequest.filter(request => handlerResponse.filter(function(response) { + if (request.bid_id === response.bid_id) { + Object.assign(request, response); + } + })); + } else { + events = handlerRequest; + } + atsAnalyticsAdapter.context.events = events; + } + } +} + +let atsAnalyticsAdapter = Object.assign(adapter( + { + host, + analyticsType + }), +{ + track({eventType, args}) { + if (typeof args !== 'undefined') { + callHandler(eventType, args); + } + if (eventType === CONSTANTS.EVENTS.AUCTION_END) { + // send data to ats analytic endpoint + try { + let dataToSend = {'Data': atsAnalyticsAdapter.context.events}; + let strJSON = JSON.stringify(dataToSend); + ajax(atsAnalyticsAdapter.context.host, function () { + }, strJSON, {method: 'POST', contentType: 'application/json'}); + } catch (err) { + } + } + } +}); + +// save the base class function +atsAnalyticsAdapter.originEnableAnalytics = atsAnalyticsAdapter.enableAnalytics; + +// override enableAnalytics so we can get access to the config passed in from the page +atsAnalyticsAdapter.enableAnalytics = function (config) { + if (!config.options.pid) { + utils.logError('Publisher ID (pid) option is not defined. Analytics won\'t work'); + return; + } + + if (!config.options.host) { + utils.logError('Host option is not defined. Analytics won\'t work'); + return; + } + + host = config.options.host; + atsAnalyticsAdapter.context = { + events: [], + host: config.options.host, + pid: config.options.pid + }; + let initOptions = config.options; + atsAnalyticsAdapter.originEnableAnalytics(initOptions); // call the base class function +}; + +adaptermanager.registerAnalyticsAdapter({ + adapter: atsAnalyticsAdapter, + code: 'atsAnalytics' +}); + +export default atsAnalyticsAdapter; diff --git a/modules/atsAnalyticsAdapter.md b/modules/atsAnalyticsAdapter.md new file mode 100644 index 00000000000..560ad237aa0 --- /dev/null +++ b/modules/atsAnalyticsAdapter.md @@ -0,0 +1,23 @@ +# Overview + +``` +Module Name: Ats Analytics Adapter +Module Type: Analytics Adapter +Maintainer: marko.matic@liveramp.com +``` + +# Description + +Analytics adapter for Authenticated Traffic Solution(ATS), provided by LiveRamp. + +# Test Parameters + +``` +{ + provider: 'atsAnalytics', + options: { + pid: '999', // publisher ID + host: 'https://example.com' // host is provided to publisher + } +} +``` diff --git a/modules/audienceNetworkBidAdapter.js b/modules/audienceNetworkBidAdapter.js index b4cf93363f6..816a6abd0e8 100644 --- a/modules/audienceNetworkBidAdapter.js +++ b/modules/audienceNetworkBidAdapter.js @@ -1,11 +1,10 @@ /** * @file AudienceNetwork adapter. */ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { formatQS } from '../src/url'; -import { generateUUID, getTopWindowUrl, convertTypes } from '../src/utils'; -import findIndex from 'core-js/library/fn/array/find-index'; -import includes from 'core-js/library/fn/array/includes'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { generateUUID, deepAccess, convertTypes, formatQS } from '../src/utils.js'; +import findIndex from 'core-js-pure/features/array/find-index.js'; +import includes from 'core-js-pure/features/array/includes.js'; const code = 'audienceNetwork'; const currency = 'USD'; @@ -168,12 +167,6 @@ const createAdHtml = (placementId, format, bidId) => { `; }; -/** - * Get the current window location URL correctly encoded for use in a URL query string. - * @returns {String} URI-encoded URL - */ -const getTopWindowUrlEncoded = () => encodeURIComponent(getTopWindowUrl()); - /** * Convert each bid request to a single URL to fetch those bids. * @param {Array} bids - list of bids @@ -186,7 +179,7 @@ const getTopWindowUrlEncoded = () => encodeURIComponent(getTopWindowUrl()); * @param {Array} bids[].sizes[] - Size arrays [h,w]: should include one of [300, 250], [320, 50] * @returns {Array} List of URLs to fetch, plus formats and sizes for later use with interpretResponse */ -const buildRequests = bids => { +const buildRequests = (bids, bidderRequest) => { // Build lists of placementids, adformats, sizes and SDK versions const placementids = []; const adformats = []; @@ -210,10 +203,9 @@ const buildRequests = bids => { requestIds.push(bid.bidId); }) ); - // Build URL const testmode = isTestmode(); - const pageurl = getTopWindowUrlEncoded(); + const pageurl = encodeURIComponent(deepAccess(bidderRequest, 'refererInfo.canonicalUrl') || deepAccess(bidderRequest, 'refererInfo.referer')); const platform = findPlatform(platforms); const cb = generateUUID(); const search = { @@ -233,7 +225,7 @@ const buildRequests = bids => { } const data = formatQS(search); - return [{ adformats, data, method, requestIds, sizes, url }]; + return [{ adformats, data, method, requestIds, sizes, url, pageurl }]; }; /** @@ -245,7 +237,7 @@ const buildRequests = bids => { * @param {Array} bidRequest.sizes - list of sizes fot the original bid requests * @returns {Array} A list of bid response objects */ -const interpretResponse = ({ body }, { adformats, requestIds, sizes }) => { +const interpretResponse = ({ body }, { adformats, requestIds, sizes, pageurl }) => { const { bids = {} } = body; return Object.keys(bids) // extract Array of bid responses @@ -284,7 +276,6 @@ const interpretResponse = ({ body }, { adformats, requestIds, sizes }) => { }; // Video attributes if (isVideo(format)) { - const pageurl = getTopWindowUrlEncoded(); bidResponse.mediaType = 'video'; bidResponse.vastUrl = `https://an.facebook.com/v1/instream/vast.xml?placementid=${creativeId}&pageurl=${pageurl}&playerwidth=${width}&playerheight=${height}&bidid=${fbBidid}`; bidResponse.ttl = videoTtl; diff --git a/modules/audiencerunBidAdapter.js b/modules/audiencerunBidAdapter.js new file mode 100644 index 00000000000..b90471ee21a --- /dev/null +++ b/modules/audiencerunBidAdapter.js @@ -0,0 +1,142 @@ +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'audiencerun'; +const ENDPOINT_URL = 'https://d.audiencerun.com/prebid'; + +export const spec = { + version: '1.0.0', + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + + /** + * Determines whether or not the given bid request is valid. + * + * @param {object} bid The bid to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + let isValid = true; + if (!utils.deepAccess(bid, 'params.zoneId')) { + utils.logError('AudienceRun zoneId parameter is required. Bid aborted.'); + isValid = false; + } + return isValid; + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server. + * @param {*} bidderRequest + * @return {ServerRequest} Info describing the request to the server. + */ + buildRequests: function(bidRequests, bidderRequest) { + const bids = bidRequests.map(bid => { + const sizes = utils.deepAccess(bid, 'mediaTypes.banner.sizes', []); + return { + zoneId: utils.getValue(bid.params, 'zoneId'), + sizes: sizes.map(size => ({ + w: size[0], + h: size[1] + })), + bidfloor: bid.params.bidfloor || 0.0, + bidId: bid.bidId, + bidderRequestId: utils.getBidIdParameter('bidderRequestId', bid), + adUnitCode: utils.getBidIdParameter('adUnitCode', bid), + auctionId: utils.getBidIdParameter('auctionId', bid), + transactionId: utils.getBidIdParameter('transactionId', bid) + }; + }); + + const payload = { + libVersion: this.version, + referer: bidderRequest.refererInfo ? bidderRequest.refererInfo.referer || null : null, + currencyCode: config.getConfig('currency.adServerCurrency'), + timeout: config.getConfig('bidderTimeout'), + bids + }; + + if (bidderRequest && bidderRequest.gdprConsent) { + payload.gdpr = { + consent: bidderRequest.gdprConsent.consentString, + applies: bidderRequest.gdprConsent.gdprApplies + }; + } else { + payload.gdpr = { + consent: '' + } + } + + return { + method: 'POST', + url: ENDPOINT_URL, + data: JSON.stringify(payload), + options: { + withCredentials: true + } + }; + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, bidRequest) { + const bids = []; + utils._each(serverResponse.body.bid, function (bidObject) { + if (!bidObject.cpm || bidObject.cpm === null || !bidObject.adm) { + return; + } + + const bid = {}; + + bid.ad = bidObject.adm; + bid.mediaType = BANNER; + + // Common properties + bid.requestId = bidObject.bidId; + bid.adId = bidObject.zoneId; + bid.cpm = parseFloat(bidObject.cpm); + bid.creativeId = bidObject.crid; + bid.currency = bidObject.currency ? bidObject.currency.toUpperCase() : 'USD'; + + bid.height = bidObject.h; + bid.width = bidObject.w; + bid.netRevenue = bidObject.isNet ? bidObject.isNet : false; + bid.ttl = 300; + + bids.push(bid); + }); + return bids; + }, + + /** + * Register the user sync pixels which should be dropped after the auction. + * + * @param {SyncOptions} syncOptions Which user syncs are allowed? + * @param {ServerResponse[]} serverResponses List of server's responses. + * @return {UserSync[]} The user syncs which should be dropped. + */ + getUserSyncs: function(syncOptions, serverResponses) { + if (!serverResponses || !serverResponses.length) return []; + + const syncs = []; + serverResponses.forEach(response => { + response.body.bid.forEach(bidObject => { + syncs.push({ + type: 'iframe', + url: bidObject.syncUrl + }); + }); + }); + + return syncs; + } +}; + +registerBidder(spec); diff --git a/modules/audiencerunBidAdapter.md b/modules/audiencerunBidAdapter.md new file mode 100644 index 00000000000..3704922fdd5 --- /dev/null +++ b/modules/audiencerunBidAdapter.md @@ -0,0 +1,48 @@ +# Overview + +**Module Name**: AudienceRun Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: prebid@audiencerun.com + +# Description + +Module that connects to AudienceRun demand sources + +Use `audiencerun` as bidder. + +`zoneId` is required and must be 10 alphanumeric characters. + +## AdUnits configuration example +``` + var adUnits = [{ + code: 'ad-slot-300x600', + mediaTypes: { + banner: { + sizes: [ + [300, 600] + ], + } + }, + bids: [{ + bidder: 'audiencerun', + params: { + zoneId: 'xtov2mgij0' + } + }] + },{ + code: 'ad-slot-728x90', + mediaTypes: { + banner: { + sizes: [ + [728, 90] + ], + } + }, + bids: [{ + bidder: 'audiencerun', + params: { + zoneId: 'u4q6z6u97b' + } + }] + }]; +``` diff --git a/modules/audigentRtdProvider.js b/modules/audigentRtdProvider.js new file mode 100644 index 00000000000..0f32c84962f --- /dev/null +++ b/modules/audigentRtdProvider.js @@ -0,0 +1,141 @@ +/** + * This module adds audigent provider to the real time data module + * The {@link module:modules/realTimeData} module is required + * The module will fetch segments from audigent server + * @module modules/audigentRtdProvider + * @requires module:modules/realTimeData + */ + +/** + * @typedef {Object} ModuleParams + * @property {string} siteKey + * @property {string} pubKey + * @property {string} url + * @property {?string} keyName + * @property {number} auctionDelay + */ + +import {config} from '../src/config.js'; +import {getGlobal} from '../src/prebidGlobal.js'; +import * as utils from '../src/utils.js'; +import {submodule} from '../src/hook.js'; +import {ajax} from '../src/ajax.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const storage = getStorageManager(); + +/** @type {string} */ +const MODULE_NAME = 'realTimeData'; + +/** @type {ModuleParams} */ +let _moduleParams = {}; + +/** + * XMLHttpRequest to get data form audigent server + * @param {string} url server url with query params + */ + +export function setData(data) { + storage.setDataInLocalStorage('__adgntseg', JSON.stringify(data)); +} + +function getSegments(adUnits, onDone) { + try { + let jsonData = storage.getDataFromLocalStorage('__adgntseg'); + if (jsonData) { + let data = JSON.parse(jsonData); + if (data.audigent_segments) { + let dataToReturn = adUnits.reduce((rp, cau) => { + const adUnitCode = cau && cau.code; + if (!adUnitCode) { return rp } + rp[adUnitCode] = data; + return rp; + }, {}); + + onDone(dataToReturn); + return; + } + } + getSegmentsAsync(adUnits, onDone); + } catch (e) { + getSegmentsAsync(adUnits, onDone); + } +} + +function getSegmentsAsync(adUnits, onDone) { + const userIds = (getGlobal()).getUserIds(); + let tdid = null; + + if (userIds && userIds['tdid']) { + tdid = userIds['tdid']; + } else { + onDone({}); + } + + const url = `https://seg.ad.gt/api/v1/rtb_segments?tdid=${tdid}`; + + ajax(url, { + success: function (response, req) { + if (req.status === 200) { + try { + const data = JSON.parse(response); + if (data && data.audigent_segments) { + setData(data); + let dataToReturn = adUnits.reduce((rp, cau) => { + const adUnitCode = cau && cau.code; + if (!adUnitCode) { return rp } + rp[adUnitCode] = data; + return rp; + }, {}); + + onDone(dataToReturn); + } else { + onDone({}); + } + } catch (err) { + utils.logError('unable to parse audigent segment data'); + onDone({}) + } + } else if (req.status === 204) { + // unrecognized site key + onDone({}); + } + }, + error: function () { + onDone({}); + utils.logError('unable to get audigent segment data'); + } + } + ); +} + +/** @type {RtdSubmodule} */ +export const audigentSubmodule = { + /** + * used to link submodule with realTimeData + * @type {string} + */ + name: 'audigent', + /** + * get data and send back to realTimeData module + * @function + * @param {adUnit[]} adUnits + * @param {function} onDone + */ + getData: getSegments +}; + +export function init(config) { + const confListener = config.getConfig(MODULE_NAME, ({realTimeData}) => { + try { + _moduleParams = realTimeData.dataProviders && realTimeData.dataProviders.filter(pr => pr.name && pr.name.toLowerCase() === 'audigent')[0].params; + _moduleParams.auctionDelay = realTimeData.auctionDelay; + } catch (e) { + _moduleParams = {}; + } + confListener(); + }); +} + +submodule('realTimeData', audigentSubmodule); +init(config); diff --git a/modules/audigentRtdProvider.md b/modules/audigentRtdProvider.md new file mode 100644 index 00000000000..47bcbbbf951 --- /dev/null +++ b/modules/audigentRtdProvider.md @@ -0,0 +1,52 @@ +Audigent is a next-generation data management platform and a first-of-a-kind +"data agency" containing some of the most exclusive content-consuming audiences +across desktop, mobile and social platforms. + +This real-time data module provides first-party Audigent segments that can be +attached to bid request objects destined for different SSPs in order to optimize +targeting. Audigent maintains a large database of first-party Tradedesk Unified +ID to third party segment mappings that can now be queried at bid-time. + +Usage: + +Compile the audigent RTD module into your Prebid build: + +`gulp build --modules=userId,unifiedIdSystem,rtdModule,audigentRtdProvider,rubiconBidAdapter` + +Audigent segments will then be attached to each bid request objects in +`bid.realTimeData.audigent_segments` + +The format of the segments is a per-SSP mapping: + +``` +{ + 'appnexus': ['anseg1', 'anseg2'], + 'google': ['gseg1', 'gseg2'] +} +``` + +If a given SSP's API backend supports segment fields, they can then be +attached prior to the bid request being sent: + +``` +pbjs.requestBids({bidsBackHandler: addAudigentSegments}); + +function addAudigentSegments() { + for (i = 0; i < adUnits.length; i++) { + let adUnit = adUnits[i]; + for (j = 0; j < adUnit.bids.length; j++) { + adUnit.bids[j].userId.lipb.segments = adUnit.bids[j].realTimeData.audigent_segments['rubicon']; + } + } +} +``` + +To view an example of the segments returned by Audigent's backends: + +`gulp serve --modules=userId,unifiedIdSystem,rtdModule,audigentRtdProvider,rubiconBidAdapter` + +and then point your browser at: + +`http://localhost:9999/integrationExamples/gpt/audigentSegments_example.html` + + diff --git a/modules/automatadBidAdapter.js b/modules/automatadBidAdapter.js new file mode 100644 index 00000000000..95d225cb5f7 --- /dev/null +++ b/modules/automatadBidAdapter.js @@ -0,0 +1,125 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js' +import * as utils from '../src/utils.js' +import {BANNER} from '../src/mediaTypes.js' +import {ajax} from '../src/ajax.js' + +const BIDDER = 'automatad' + +const ENDPOINT_URL = 'https://rtb2.automatad.com/ortb2' + +const DEFAULT_BID_TTL = 30 +const DEFAULT_CURRENCY = 'USD' +const DEFAULT_NET_REVENUE = true + +export const spec = { + code: BIDDER, + aliases: ['atd'], + supportedMediaTypes: [BANNER], + + isBidRequestValid: function (bid) { + // will receive request bid. check if have necessary params for bidding + return (bid && bid.hasOwnProperty('params') && bid.params.hasOwnProperty('siteId') && bid.params.hasOwnProperty('placementId') && bid.hasOwnProperty('mediaTypes') && bid.mediaTypes.hasOwnProperty('banner')) + }, + + buildRequests: function (validBidRequests, bidderRequest) { + if (!validBidRequests || !bidderRequest) { + return + } + + const siteId = validBidRequests[0].params.siteId + const placementId = validBidRequests[0].params.placementId + + const impressions = validBidRequests.map(bidRequest => ({ + id: bidRequest.bidId, + banner: { + format: bidRequest.sizes.map(sizeArr => ({ + w: sizeArr[0], + h: sizeArr[1], + })) + }, + })) + + // params from bid request + const openrtbRequest = { + id: validBidRequests[0].auctionId, + imp: impressions, + site: { + id: siteId, + placement: placementId, + domain: window.location.hostname, + page: window.location.href, + ref: bidderRequest.refererInfo ? bidderRequest.refererInfo.referer || null : null, + }, + } + + const payloadString = JSON.stringify(openrtbRequest) + return { + method: 'POST', + url: ENDPOINT_URL + '/resp', + data: payloadString, + options: { + contentType: 'application/json', + withCredentials: false, + crossOrigin: true, + }, + } + }, + + interpretResponse: function (serverResponse, request) { + const bidResponses = [] + const response = (serverResponse || {}).body + + if (response && response.seatbid && response.seatbid.length === 1 && response.seatbid[0].bid && response.seatbid[0].bid.length) { + response.seatbid[0].bid.forEach(bid => { + bidResponses.push({ + requestId: bid.impid, + cpm: bid.price, + ad: bid.adm, + adDomain: bid.adomain[0], + currency: DEFAULT_CURRENCY, + ttl: DEFAULT_BID_TTL, + creativeId: bid.crid, + width: bid.w, + height: bid.h, + netRevenue: DEFAULT_NET_REVENUE, + nurl: bid.nurl, + }) + }) + } else { + utils.logInfo('automatad :: no valid responses to interpret') + } + + return bidResponses + }, + getUserSyncs: function(syncOptions, serverResponse) { + return [{ + type: 'iframe', + url: 'https://rtb2.automatad.com/ortb2/async_usersync' + }] + }, + onBidWon: function(bid) { + if (!bid.nurl) { return } + const winCpm = (bid.hasOwnProperty('originalCpm')) ? bid.originalCpm : bid.cpm + const winCurr = (bid.hasOwnProperty('originalCurrency') && bid.hasOwnProperty('originalCpm')) ? bid.originalCurrency : bid.currency + const winUrl = bid.nurl.replace( + /\$\{AUCTION_PRICE\}/, + winCpm + ).replace( + /\$\{AUCTION_IMP_ID\}/, + bid.requestId + ).replace( + /\$\{AUCTION_CURRENCY\}/, + winCurr + ).replace( + /\$\{AUCTION_ID\}/, + bid.auctionId + ) + spec.ajaxCall(winUrl, null) + return true + }, + ajaxCall: function(endpoint, data) { + ajax(endpoint, data) + }, + +} +registerBidder(spec) diff --git a/modules/automatadBidAdapter.md b/modules/automatadBidAdapter.md new file mode 100644 index 00000000000..56a4b53c067 --- /dev/null +++ b/modules/automatadBidAdapter.md @@ -0,0 +1,34 @@ +# Overview + +``` +Module Name: Automatad Bid Adapter +Module Type: Bidder Adapter +Maintainer: tech@automatad.com +``` + +# Description + +Connects to automatad exchange for bids. + +automatad bid adapter supports Banner ads. + +# Test Parameters +``` +var adUnits = [ + { + code: 'banner-ad-div', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]] + } + }, + bids: [{ + bidder: 'automatad', + params: { + siteId: 'someValue', + placementId: 'someValue' + } + }] + } +]; +``` diff --git a/modules/avocetBidAdapter.js b/modules/avocetBidAdapter.js new file mode 100644 index 00000000000..1163ac830ba --- /dev/null +++ b/modules/avocetBidAdapter.js @@ -0,0 +1,141 @@ +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'avct'; +const DEFAULT_BASE_URL = 'https://ads.avct.cloud'; +const DEFAULT_PREBID_PATH = '/prebid'; + +function getPrebidURL() { + let host = config.getConfig('avct.baseUrl'); + if (host && typeof host === 'string') { + return `${host}${getPrebidPath()}`; + } + return `${DEFAULT_BASE_URL}${getPrebidPath()}`; +} + +function getPrebidPath() { + let prebidPath = config.getConfig('avct.prebidPath'); + if (prebidPath && typeof prebidPath === 'string') { + return prebidPath; + } + return DEFAULT_PREBID_PATH; +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid with params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + return ( + !!bid.params && + !!bid.params.placement && + typeof bid.params.placement === 'string' && + bid.params.placement.length === 24 + ); + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function (bidRequests, bidderRequest) { + // Get currency from config + const currency = config.getConfig('currency.adServerCurrency'); + + // Publisher domain from config + const publisherDomain = config.getConfig('publisherDomain'); + + // First-party data from config + const fpd = config.getConfig('fpd'); + + // GDPR status and TCF consent string + let tcfConsentString; + let gdprApplies = false; + if (bidderRequest.gdprConsent) { + tcfConsentString = bidderRequest.gdprConsent.consentString; + gdprApplies = !!bidderRequest.gdprConsent.gdprApplies; + } + + // US privacy string + let usPrivacyString; + if (bidderRequest.uspConsent) { + usPrivacyString = bidderRequest.uspConsent; + } + + // Supply chain + let schain; + if (bidderRequest.schain) { + schain = bidderRequest.schain; + } + + // ID5 identifier + let id5id; + if (bidRequests[0].userId && bidRequests[0].userId.id5id) { + id5id = bidRequests[0].userId.id5id; + } + + // Build the avocet ext object + const ext = { + currency, + tcfConsentString, + gdprApplies, + usPrivacyString, + schain, + publisherDomain, + fpd, + id5id, + }; + + // Extract properties from bidderRequest + const { + auctionId, + auctionStart, + bidderCode, + bidderRequestId, + refererInfo, + timeout, + } = bidderRequest; + + // Construct payload + const payload = JSON.stringify({ + auctionId, + auctionStart, + bidderCode, + bidderRequestId, + refererInfo, + timeout, + bids: bidRequests, + ext, + }); + + return { + method: 'POST', + url: getPrebidURL(), + data: payload, + }; + }, + interpretResponse: function (serverResponse, bidRequest) { + if ( + !serverResponse || + !serverResponse.body || + typeof serverResponse.body !== 'object' + ) { + return []; + } + if (Array.isArray(serverResponse.body)) { + return serverResponse.body; + } + if (Array.isArray(serverResponse.body.responses)) { + return serverResponse.body.responses; + } + return []; + }, +}; +registerBidder(spec); diff --git a/modules/avocetBidAdapter.md b/modules/avocetBidAdapter.md new file mode 100644 index 00000000000..95cb29303f2 --- /dev/null +++ b/modules/avocetBidAdapter.md @@ -0,0 +1,40 @@ +# Overview + +``` +Module Name: Avocet Bidder Adapter +Module Type: Bidder Adapter +Maintainer: developers@avocet.io +``` + +# Description + +Module that connects to the Avocet advertising platform. + +# Parameters + +| Name | Scope | Description | Example | +| :------------ | :------- | :---------------------------------- | :------------------------- | +| `placement` | required | A Placement ID from Avocet. | "5ebd27607781b9af3ccc3332" | + + +# Test Parameters +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[300, 250]], // a display size + } + }, + bids: [ + { + bidder: "avct", + params: { + placement: "5ebd27607781b9af3ccc3332" + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/modules/beachfrontBidAdapter.js b/modules/beachfrontBidAdapter.js index 552413f4878..12e78c684ad 100644 --- a/modules/beachfrontBidAdapter.js +++ b/modules/beachfrontBidAdapter.js @@ -1,21 +1,20 @@ -import * as utils from '../src/utils'; -import { parse as parseUrl } from '../src/url'; -import { config } from '../src/config'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { Renderer } from '../src/Renderer'; -import { VIDEO, BANNER } from '../src/mediaTypes'; -import find from 'core-js/library/fn/array/find'; -import includes from 'core-js/library/fn/array/includes'; - -const ADAPTER_VERSION = '1.4'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; +import find from 'core-js-pure/features/array/find.js'; +import includes from 'core-js-pure/features/array/includes.js'; + +const ADAPTER_VERSION = '1.11'; const ADAPTER_NAME = 'BFIO_PREBID'; const OUTSTREAM = 'outstream'; -export const VIDEO_ENDPOINT = '//reachms.bfmio.com/bid.json?exchange_id='; -export const BANNER_ENDPOINT = '//display.bfmio.com/prebid_display'; -export const OUTSTREAM_SRC = '//player-cdn.beachfrontmedia.com/playerapi/loader/outstream.js'; +export const VIDEO_ENDPOINT = 'https://reachms.bfmio.com/bid.json?exchange_id='; +export const BANNER_ENDPOINT = 'https://display.bfmio.com/prebid_display'; +export const OUTSTREAM_SRC = 'https://player-cdn.beachfrontmedia.com/playerapi/loader/outstream.js'; -export const VIDEO_TARGETING = ['mimes', 'playbackmethod', 'maxduration']; +export const VIDEO_TARGETING = ['mimes', 'playbackmethod', 'maxduration', 'placement']; export const DEFAULT_MIMES = ['video/mp4', 'application/javascript']; let appId = ''; @@ -68,10 +67,11 @@ export const spec = { requestId: bidRequest.bidId, bidderCode: spec.code, vastUrl: response.url, + vastXml: response.vast, cpm: response.bidPrice, width: firstSize.w, height: firstSize.h, - creativeId: response.cmpId, + creativeId: response.crid || response.cmpId, renderer: context === OUTSTREAM ? createRenderer(bidRequest) : null, mediaType: VIDEO, currency: 'USD', @@ -104,9 +104,9 @@ export const spec = { } }, - getUserSyncs(syncOptions, serverResponses = [], gdprConsent = {}) { + getUserSyncs(syncOptions, serverResponses = [], gdprConsent = {}, uspConsent = '') { let syncs = []; - let { gdprApplies, consentString } = gdprConsent; + let { gdprApplies, consentString = '' } = gdprConsent; let bannerResponse = find(serverResponses, (res) => utils.isArray(res.body)); if (bannerResponse) { @@ -123,12 +123,12 @@ export const spec = { } else if (syncOptions.iframeEnabled) { syncs.push({ type: 'iframe', - url: `//sync.bfmio.com/sync_iframe?ifg=1&id=${appId}&gdpr=${gdprApplies ? 1 : 0}&gc=${consentString || ''}&gce=1` + url: `https://sync.bfmio.com/sync_iframe?ifg=1&id=${appId}&gdpr=${gdprApplies ? 1 : 0}&gc=${consentString}&gce=1&us_privacy=${uspConsent}` }); } else if (syncOptions.pixelEnabled) { syncs.push({ type: 'image', - url: `//sync.bfmio.com/syncb?pid=144&id=${appId}&gdpr=${gdprApplies ? 1 : 0}&gc=${consentString || ''}&gce=1` + url: `https://sync.bfmio.com/syncb?pid=144&id=${appId}&gdpr=${gdprApplies ? 1 : 0}&gc=${consentString}&gce=1&us_privacy=${uspConsent}` }); } @@ -143,21 +143,21 @@ function createRenderer(bidRequest) { loaded: false }); - renderer.setRender(outstreamRender); - - return renderer; -} - -function outstreamRender(bid) { - bid.renderer.push(() => { - window.Beachfront.Player(bid.adUnitCode, { - ad_tag_url: bid.vastUrl, - width: bid.width, - height: bid.height, - expand_in_view: false, - collapse_on_complete: true + renderer.setRender(bid => { + bid.renderer.push(() => { + window.Beachfront.Player(bid.adUnitCode, { + adTagUrl: bid.vastUrl, + width: bid.width, + height: bid.height, + expandInView: getPlayerBidParam(bidRequest, 'expandInView', false), + collapseOnComplete: getPlayerBidParam(bidRequest, 'collapseOnComplete', true), + progressColor: getPlayerBidParam(bidRequest, 'progressColor'), + adPosterColor: getPlayerBidParam(bidRequest, 'adPosterColor') + }); }); }); + + return renderer; } function getFirstSize(sizes) { @@ -231,6 +231,11 @@ function getBannerBidParam(bid, key) { return utils.deepAccess(bid, 'params.banner.' + key) || utils.deepAccess(bid, 'params.' + key); } +function getPlayerBidParam(bid, key, defaultValue) { + let param = utils.deepAccess(bid, 'params.player.' + key); + return param === undefined ? defaultValue : param; +} + function isVideoBidValid(bid) { return isVideoBid(bid) && getVideoBidParam(bid, 'appId') && getVideoBidParam(bid, 'bidfloor'); } @@ -241,7 +246,7 @@ function isBannerBidValid(bid) { function getTopWindowLocation(bidderRequest) { let url = bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer; - return parseUrl(config.getConfig('pageUrl') || url, { decodeSearchAsString: true }); + return utils.parseUrl(config.getConfig('pageUrl') || url, { decodeSearchAsString: true }); } function getTopWindowReferrer() { @@ -267,6 +272,7 @@ function createVideoRequestData(bid, bidderRequest) { let video = getVideoTargetingParams(bid); let appId = getVideoBidParam(bid, 'appId'); let bidfloor = getVideoBidParam(bid, 'bidfloor'); + let tagid = getVideoBidParam(bid, 'tagid'); let topLocation = getTopWindowLocation(bidderRequest); let payload = { isPrebid: true, @@ -280,7 +286,10 @@ function createVideoRequestData(bid, bidderRequest) { mimes: DEFAULT_MIMES }, video), bidfloor: bidfloor, - secure: topLocation.protocol === 'https:' ? 1 : 0 + tagid: tagid, + secure: topLocation.protocol.indexOf('https') === 0 ? 1 : 0, + displaymanager: ADAPTER_NAME, + displaymanagerver: ADAPTER_VERSION }], site: { page: topLocation.href, @@ -303,6 +312,10 @@ function createVideoRequestData(bid, bidderRequest) { cur: ['USD'] }; + if (bidderRequest && bidderRequest.uspConsent) { + payload.regs.ext.us_privacy = bidderRequest.uspConsent; + } + if (bidderRequest && bidderRequest.gdprConsent) { let { gdprApplies, consentString } = bidderRequest.gdprConsent; payload.regs.ext.gdpr = gdprApplies ? 1 : 0; @@ -321,6 +334,11 @@ function createVideoRequestData(bid, bidderRequest) { }]; } + let connection = navigator.connection || navigator.webkitConnection; + if (connection && connection.effectiveType) { + payload.device.connectiontype = connection.effectiveType; + } + return payload; } @@ -350,6 +368,10 @@ function createBannerRequestData(bids, bidderRequest) { adapterName: ADAPTER_NAME }; + if (bidderRequest && bidderRequest.uspConsent) { + payload.usPrivacy = bidderRequest.uspConsent; + } + if (bidderRequest && bidderRequest.gdprConsent) { let { gdprApplies, consentString } = bidderRequest.gdprConsent; payload.gdpr = gdprApplies ? 1 : 0; diff --git a/modules/beachfrontBidAdapter.md b/modules/beachfrontBidAdapter.md index fb14db59710..0a6b8b73da4 100644 --- a/modules/beachfrontBidAdapter.md +++ b/modules/beachfrontBidAdapter.md @@ -86,3 +86,36 @@ Module that connects to Beachfront's demand sources } ]; ``` + +# Outstream Player Params Example +```javascript + var adUnits = [ + { + code: 'test-video-outstream', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [ 640, 360 ] + } + }, + bids: [ + { + bidder: 'beachfront', + params: { + video: { + bidfloor: 0.01, + appId: '11bc5dd5-7421-4dd8-c926-40fa653bec76', + mimes: [ 'video/mp4', 'application/javascript' ] + }, + player: { + progressColor: '#50A8FA', + adPosterColor: '#FFF', + expandInView: false, + collapseOnComplete: true + } + } + } + ] + } + ]; +``` diff --git a/modules/betweenBidAdapter.js b/modules/betweenBidAdapter.js index 9da6b4dbe29..72bf592ff77 100644 --- a/modules/betweenBidAdapter.js +++ b/modules/betweenBidAdapter.js @@ -1,5 +1,5 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; - +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { getAdUnitSizes, parseSizesInput } from '../src/utils.js'; const BIDDER_CODE = 'between'; export const spec = { @@ -13,7 +13,7 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function(bid) { - return !!(bid.params.w && bid.params.h && bid.params.s); + return Boolean(bid.params.s); }, /** * Make a server request from the list of BidRequests. @@ -21,17 +21,18 @@ export const spec = { * @param {validBidRequests[]} - an array of bids * @return ServerRequest Info describing the request to the server. */ - buildRequests: function(validBidRequests) { + buildRequests: function(validBidRequests, bidderRequest) { let requests = []; + const gdprConsent = bidderRequest && bidderRequest.gdprConsent; + validBidRequests.forEach(i => { let params = { + sizes: parseSizesInput(getAdUnitSizes(i)).join('%2C'), jst: 'hb', ord: Math.random() * 10000000000000000, tz: getTz(), fl: getFl(), rr: getRr(), - w: i.params.w, - h: i.params.h, s: i.params.s, bidid: i.bidId, transactionid: i.transactionId, @@ -54,6 +55,16 @@ export const spec = { params['pubside_macro[' + key + ']'] = encodeURIComponent(i.params.pubdata[key]); } } + + if (gdprConsent) { + if (typeof gdprConsent.gdprApplies !== 'undefined') { + params.gdprApplies = !!gdprConsent.gdprApplies; + } + if (typeof gdprConsent.consentString !== 'undefined') { + params.consentString = gdprConsent.consentString; + } + } + requests.push({method: 'GET', url: 'https://ads.betweendigital.com/adjson', data: params}) }) return requests; @@ -96,7 +107,7 @@ export const spec = { if (syncOptions.iframeEnabled) { syncs.push({ type: 'iframe', - url: '//acdn.adnxs.com/ib/static/usersync/v3/async_usersync.html' + url: 'https://acdn.adnxs.com/ib/static/usersync/v3/async_usersync.html' }); } if (syncOptions.pixelEnabled && serverResponses.length > 0) { @@ -108,11 +119,11 @@ export const spec = { // syncs.push({ // type: 'iframe', - // url: '//acdn.adnxs.com/ib/static/usersync/v3/async_usersync.html' + // url: 'https://acdn.adnxs.com/ib/static/usersync/v3/async_usersync.html' // }); syncs.push({ type: 'iframe', - url: '//ads.betweendigital.com/sspmatch-iframe' + url: 'https://ads.betweendigital.com/sspmatch-iframe' }); return syncs; } diff --git a/modules/betweenBidAdapter.md b/modules/betweenBidAdapter.md index 426d0aa2ed7..4371a8709d8 100644 --- a/modules/betweenBidAdapter.md +++ b/modules/betweenBidAdapter.md @@ -8,89 +8,147 @@ Maintainer: info@betweendigital.com You can use this adapter to get a bid from betweendigital. -About us : http://betweendigital.com +About us : [betweenx.com](https://betweenx.com) +More detailed instructions you can be found on [this page](https://cdn.betweendigital.com/prebid_instructions/index.html) . # Test Parameters + +> The parameters are used as an example: +> s: 3649326 — Between section id; code: ad_slot — id of an iframe element showing prebid ads + ```javascript - var adUnits = [ - { - code: 'test-div', - bids: [ - { - bidder: "between", - params: { - w: 200, - h: 400, - s: 111 - } - } - ] - } - ]; +var adUnits = [ + { + code: "ad_slot", + mediaTypes: { + banner: { + sizes: [[240, 400]], + }, + }, + bids: [ + { + bidder: "between", + params: { + s: 3649326, + }, + }, + ], + }, +]; ``` -Where: +### Multisizes -* s - the section id -* code - the id of the iframe tag to which the ads will be rendered +If you specify several sizes in the AdUnits settings in the **mediaTypes.banner.sizes** field, our SSP server will hold an auction with each size and respond with a bid with the maximum CPM. -# Example page +For example, your ad-slot supports three sizes: 970x250, 728x90 and 468x60. Then the AdUnits code will look like this: -```html - - - - +```javascript +{ + bidder: 'between', + params: { + s: BETWEEN_SECTION_ID, + cur: 'USD' + } +} +``` + +### GDPR +Also, we support GDPR. To find out how to use GDPR in Prebid you can visit [this page](http://prebid.org/dev-docs/modules/consentManagement.html) - + + + + }); + -

Prebid.js BetweenBidAdapter Test

- +

Prebid.js BetweenBidAdapter Test

+ - -``` \ No newline at end of file + +``` diff --git a/modules/bidfluenceBidAdapter.js b/modules/bidfluenceBidAdapter.js index 4a9c4433ee0..f8a1f9ac92f 100644 --- a/modules/bidfluenceBidAdapter.js +++ b/modules/bidfluenceBidAdapter.js @@ -1,5 +1,8 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const storage = getStorageManager(); const BIDDER_CODE = 'bidfluence'; function stdTimezoneOffset(t) { @@ -46,7 +49,7 @@ export const spec = { var payload = { v: '2.0', azr: true, - ck: utils.cookiesAreEnabled(), + ck: storage.cookiesAreEnabled(), re: refInfo ? refInfo.referer : '', st: refInfo ? refInfo.stack : [], tz: getBdfTz(new Date()), @@ -81,7 +84,7 @@ export const spec = { const payloadString = JSON.stringify(payload); return { method: 'POST', - url: `//bdf${payload.bids[0].pid}.bidfluence.com/Prebid`, + url: `https://bdf${payload.bids[0].pid}.bidfluence.com/Prebid`, data: payloadString, options: { contentType: 'text/plain' } }; diff --git a/modules/bidglassBidAdapter.js b/modules/bidglassBidAdapter.js new file mode 100644 index 00000000000..6db35f184ca --- /dev/null +++ b/modules/bidglassBidAdapter.js @@ -0,0 +1,134 @@ +import * as utils from '../src/utils.js'; +// import {config} from 'src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'bidglass'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['bg'], // short code + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bid) { + return !!(bid.params.adUnitId && !isNaN(parseFloat(bid.params.adUnitId)) && isFinite(bid.params.adUnitId)); + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests, bidderRequest) { + /* + Sample array entry for validBidRequests[]: + [{ + "bidder": "bidglass", + "bidId": "51ef8751f9aead", + "params": { + "adUnitId": 11, + ... + }, + "adUnitCode": "div-gpt-ad-1460505748561-0", + "transactionId": "d7b773de-ceaa-484d-89ca-d9f51b8d61ec", + "sizes": [[320,50],[300,250],[300,600]], + "bidderRequestId": "418b37f85e772c", + "auctionId": "18fd8b8b0bd757", + "bidRequestsCount": 1 + }] + */ + + let imps = []; + let getReferer = function() { + return window === window.top ? window.location.href : window.parent === window.top ? document.referrer : null; + }; + let getOrigins = function() { + var ori = ['https://' + window.location.hostname]; + + if (window.location.ancestorOrigins) { + for (var i = 0; i < window.location.ancestorOrigins.length; i++) { + ori.push(window.location.ancestorOrigins[i]); + } + } else if (window !== window.top) { + // Derive the parent origin + var parts = document.referrer.split('/'); + + ori.push('https://' + parts[2]); + + if (window.parent !== window.top) { + // Additional unknown origins exist + ori.push('null'); + } + } + + return ori; + }; + + utils._each(validBidRequests, function(bid) { + bid.sizes = ((utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0])) ? bid.sizes : [bid.sizes]); + bid.sizes = bid.sizes.filter(size => utils.isArray(size)); + + // Stuff to send: [bid id, sizes, adUnitId] + imps.push({ + bidId: bid.bidId, + sizes: bid.sizes, + adUnitId: utils.getBidIdParameter('adUnitId', bid.params) + }); + }); + + // Stuff to send: page URL + const bidReq = { + reqId: utils.getUniqueIdentifierStr(), + imps: imps, + ref: getReferer(), + ori: getOrigins() + }; + + let url = 'https://bid.glass/ad/hb.php?' + + `src=$$REPO_AND_VERSION$$`; + + return { + method: 'POST', + url: url, + data: JSON.stringify(bidReq), + options: { + contentType: 'text/plain', + withCredentials: false + } + } + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse) { + const bidResponses = []; + + utils._each(serverResponse.body.bidResponses, function(bid) { + bidResponses.push({ + requestId: bid.requestId, + cpm: parseFloat(bid.cpm), + width: parseInt(bid.width, 10), + height: parseInt(bid.height, 10), + creativeId: bid.creativeId, + dealId: bid.dealId || null, + currency: bid.currency || 'USD', + mediaType: bid.mediaType || 'banner', + netRevenue: true, + ttl: bid.ttl || 10, + ad: bid.ad + }); + }); + + return bidResponses; + } + +} + +registerBidder(spec); diff --git a/modules/bidglassBidAdapter.md b/modules/bidglassBidAdapter.md new file mode 100644 index 00000000000..5384a095314 --- /dev/null +++ b/modules/bidglassBidAdapter.md @@ -0,0 +1,34 @@ +# Overview + +``` +Module Name: Bid Glass Bid Adapter +Module Type: Bidder Adapter +Maintainer: dliebner@gmail.com +``` + +# Description + +Connects to Bid Glass and allows bids on ad units to compete within prebid. + +# Sample Ad Unit: For Publishers +``` +var adUnits = [{ + code: 'bg-test-rectangle', + sizes: [[300, 250]], + bids: [{ + bidder: 'bidglass', + params: { + adUnitId: '-1' + } + }] +},{ + code: 'bg-test-leaderboard', + sizes: [[728, 90]], + bids: [{ + bidder: 'bidglass', + params: { + adUnitId: '-1' + } + }] +}] +``` \ No newline at end of file diff --git a/modules/bidlabBidAdapter.js b/modules/bidlabBidAdapter.js new file mode 100644 index 00000000000..8f501505a6d --- /dev/null +++ b/modules/bidlabBidAdapter.js @@ -0,0 +1,112 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; + +const BIDDER_CODE = 'bidlab'; +const AD_URL = 'https://service.bidlab.ai/?c=o&m=multi'; +const URL_SYNC = 'https://service.bidlab.ai/?c=o&m=sync'; +const NO_SYNC = true; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || + !bid.ttl || !bid.currency) { + return false; + } + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + case VIDEO: + return Boolean(bid.vastUrl); + case NATIVE: + return Boolean(bid.native && bid.native.title && bid.native.image && bid.native.impressionTrackers); + default: + return false; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + noSync: NO_SYNC, + + isBidRequestValid: (bid) => { + return Boolean(bid.bidId && bid.params && !isNaN(parseInt(bid.params.placementId))); + }, + + buildRequests: (validBidRequests = [], bidderRequest) => { + let winTop = window; + let location; + try { + location = new URL(bidderRequest.refererInfo.referer) + winTop = window.top; + } catch (e) { + location = winTop.location; + utils.logMessage(e); + }; + let placements = []; + let request = { + 'deviceWidth': winTop.screen.width, + 'deviceHeight': winTop.screen.height, + 'language': (navigator && navigator.language) ? navigator.language.split('-')[0] : '', + 'secure': 1, + 'host': location.host, + 'page': location.pathname, + 'placements': placements + }; + request.language.indexOf('-') != -1 && (request.language = request.language.split('-')[0]) + if (bidderRequest) { + if (bidderRequest.uspConsent) { + request.ccpa = bidderRequest.uspConsent; + } + if (bidderRequest.gdprConsent) { + request.gdpr = bidderRequest.gdprConsent + } + } + const len = validBidRequests.length; + + for (let i = 0; i < len; i++) { + let bid = validBidRequests[i]; + let traff = bid.params.traffic || BANNER + + placements.push({ + placementId: bid.params.placementId, + bidId: bid.bidId, + sizes: bid.mediaTypes && bid.mediaTypes[traff] && bid.mediaTypes[traff].sizes ? bid.mediaTypes[traff].sizes : [], + traffic: traff + }); + if (bid.schain) { + placements.schain = bid.schain; + } + } + return { + method: 'POST', + url: AD_URL, + data: request + }; + }, + + interpretResponse: (serverResponse) => { + let response = []; + for (let i = 0; i < serverResponse.body.length; i++) { + let resItem = serverResponse.body[i]; + if (isBidResponseValid(resItem)) { + response.push(resItem); + } + } + return response; + }, + + getUserSyncs: (syncOptions, serverResponses) => { + if (NO_SYNC) { + return false + } else { + return [{ + type: 'image', + url: URL_SYNC + }]; + } + } + +}; + +registerBidder(spec); diff --git a/modules/bidlabBidAdapter.md b/modules/bidlabBidAdapter.md new file mode 100644 index 00000000000..3e5fe3128ed --- /dev/null +++ b/modules/bidlabBidAdapter.md @@ -0,0 +1,53 @@ +# Overview + +``` +Module Name: bidlab Bidder Adapter +Module Type: bidlab Bidder Adapter +``` + +# Description + +Module that connects to bidlab demand sources + +# Test Parameters +``` + var adUnits = [ + // Will return static test banner + { + code: 'placementId_0', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: 'bidlab', + params: { + placementId: 0, + traffic: 'banner' + } + } + ] + }, + // Will return test vast xml. All video params are stored under placement in publishers UI + { + code: 'placementId_0', + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'instream' + } + }, + bids: [ + { + bidder: 'bidlab', + params: { + placementId: 0, + traffic: 'video' + } + } + ] + } + ]; +``` diff --git a/modules/bidphysicsBidAdapter.js b/modules/bidphysicsBidAdapter.js index 260a473c631..b6b5690ede5 100644 --- a/modules/bidphysicsBidAdapter.js +++ b/modules/bidphysicsBidAdapter.js @@ -1,8 +1,8 @@ -import {registerBidder} from 'src/adapters/bidderFactory'; -import * as utils from '../src/utils'; -import {BANNER} from '../src/mediaTypes'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; +import {BANNER} from '../src/mediaTypes.js'; -const ENDPOINT_URL = '//exchange.bidphysics.com/auction'; +const ENDPOINT_URL = 'https://exchange.bidphysics.com/auction'; const DEFAULT_BID_TTL = 30; const DEFAULT_CURRENCY = 'USD'; @@ -10,7 +10,7 @@ const DEFAULT_NET_REVENUE = true; export const spec = { code: 'bidphysics', - aliases: ['yieldlift', 'padsquad'], + aliases: ['yieldlift'], supportedMediaTypes: [BANNER], isBidRequestValid: function (bid) { diff --git a/modules/bizzclickBidAdapter.js b/modules/bizzclickBidAdapter.js deleted file mode 100644 index a9b202b4c97..00000000000 --- a/modules/bizzclickBidAdapter.js +++ /dev/null @@ -1,105 +0,0 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; -import * as utils from '../src/utils'; - -const BIDDER_CODE = 'bizzclick'; -const URL = '//supply.bizzclick.com/?c=o&m=multi'; -const URL_SYNC = '//supply.bizzclick.com/?c=o&m=cookie'; - -function isBidResponseValid(bid) { - if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) { - return false; - } - switch (bid.mediaType) { - case BANNER: - return Boolean(bid.width && bid.height && bid.ad); - case VIDEO: - return Boolean(bid.vastUrl); - case NATIVE: - return Boolean(bid.native); - } - return false; -} - -export const spec = { - code: BIDDER_CODE, - supportedMediaTypes: [BANNER, VIDEO, NATIVE], - /** - * Determines whether or not the given bid request is valid. - * - * @param {object} bid The bid to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ - isBidRequestValid: (bid) => { - return Boolean(bid.bidId && bid.params && !isNaN(bid.params.placementId) && bid.params.type); - }, - - /** - * Make a server request from the list of BidRequests. - * - * @param {BidRequest[]} validBidRequests A non-empty list of valid bid requests that should be sent to the Server. - * @return ServerRequest Info describing the request to the server. - */ - buildRequests: (validBidRequests) => { - let winTop = window; - try { - window.top.location.toString(); - winTop = window.top; - } catch (e) { - utils.logMessage(e); - }; - const location = utils.getTopWindowLocation(); - const placements = []; - const len = validBidRequests.length; - for (let i = 0; i < len; i++) { - const bid = validBidRequests[i]; - const placement = { - placementId: bid.params.placementId, - bidId: bid.bidId, - sizes: bid.sizes, - type: bid.params.type - }; - placements.push(placement); - } - return { - method: 'POST', - url: URL, - data: { - 'deviceWidth': winTop.screen.width, - 'deviceHeight': winTop.screen.height, - 'secure': (location.protocol === 'https:') ? 1 : 0, - 'host': location.host, - 'page': location.pathname, - 'placements': placements - } - }; - }, - - /** - * Unpack the response from the server into a list of bids. - * - * @param {*} serverResponse A successful response from the server. - * @return {Bid[]} An array of bids which were nested inside the server. - */ - interpretResponse: (bidResponses) => { - const res = []; - bidResponses = bidResponses.body; - const len = bidResponses.length; - for (let i = 0; i < len; i++) { - const bid = bidResponses[i]; - if (isBidResponseValid(bid)) { - res.push(bid); - } - } - return res; - }, - - getUserSyncs: () => { - return [{ - type: 'image', - url: URL_SYNC - }]; - } -}; - -registerBidder(spec); diff --git a/modules/bluebillywigBidAdapter.js b/modules/bluebillywigBidAdapter.js new file mode 100644 index 00000000000..4d40d931e1d --- /dev/null +++ b/modules/bluebillywigBidAdapter.js @@ -0,0 +1,390 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { VIDEO } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; +import { Renderer } from '../src/Renderer.js'; +import { createEidsArray } from './userId/eids.js'; + +const DEV_MODE = window.location.search.match(/bbpbs_debug=true/); + +// Blue Billywig Constants +const BB_CONSTANTS = { + BIDDER_CODE: 'bluebillywig', + AUCTION_URL: '$$URL_STARTpbs.bluebillywig.com/openrtb2/auction?pub=$$PUBLICATION', + SYNC_URL: '$$URL_STARTpbs.bluebillywig.com/static/cookie-sync.html?pub=$$PUBLICATION', + RENDERER_URL: 'https://$$PUBLICATION.bbvms.com/r/$$RENDERER.js', + DEFAULT_TIMEOUT: 5000, + DEFAULT_TTL: 300, + DEFAULT_WIDTH: 768, + DEFAULT_HEIGHT: 432, + DEFAULT_NET_REVENUE: true +}; + +// Aliasing +const getConfig = config.getConfig; + +// Helper Functions +export const BB_HELPERS = { + addSiteAppDevice: function(request, pageUrl) { + if (!request) return; + + if (typeof getConfig('app') === 'object') request.app = getConfig('app'); + else { + request.site = {}; + if (typeof getConfig('site') === 'object') request.site = getConfig('site'); + if (pageUrl) request.site.page = pageUrl; + } + + if (typeof getConfig('device') === 'object') request.device = getConfig('device'); + if (!request.device) request.device = {}; + if (!request.device.w) request.device.w = window.innerWidth; + if (!request.device.h) request.device.h = window.innerHeight; + }, + addSchain: function(request, validBidRequests) { + if (!request) return; + + const schain = utils.deepAccess(validBidRequests, '0.schain'); + if (schain) request.source.ext = { schain: schain }; + }, + addCurrency: function(request) { + if (!request) return; + + const adServerCur = getConfig('currency.adServerCurrency'); + if (adServerCur && typeof adServerCur === 'string') request.cur = [adServerCur]; + else if (Array.isArray(adServerCur) && adServerCur.length) request.cur = [adServerCur[0]]; + }, + addUserIds: function(request, validBidRequests) { + if (!request) return; + + const bidUserId = utils.deepAccess(validBidRequests, '0.userId'); + const eids = createEidsArray(bidUserId); + + if (eids.length) { + utils.deepSetValue(request, 'user.ext.eids', eids); + } + }, + addDigiTrust: function(request, bidRequests) { + const digiTrust = BB_HELPERS.getDigiTrustParams(bidRequests && bidRequests[0]); + if (digiTrust) utils.deepSetValue(request, 'user.ext.digitrust', digiTrust); + }, + substituteUrl: function (url, publication, renderer) { + return url.replace('$$URL_START', (DEV_MODE) ? 'https://dev.' : 'https://').replace('$$PUBLICATION', publication).replace('$$RENDERER', renderer); + }, + getAuctionUrl: function(publication) { + return BB_HELPERS.substituteUrl(BB_CONSTANTS.AUCTION_URL, publication); + }, + getSyncUrl: function(publication) { + return BB_HELPERS.substituteUrl(BB_CONSTANTS.SYNC_URL, publication); + }, + getRendererUrl: function(publication, renderer) { + return BB_HELPERS.substituteUrl(BB_CONSTANTS.RENDERER_URL, publication, renderer); + }, + getDigiTrustParams: function(bidRequest) { + const digiTrustId = BB_HELPERS.getDigiTrustId(bidRequest); + + if (!digiTrustId || (digiTrustId.privacy && digiTrustId.privacy.optout)) return null; + return { + id: digiTrustId.id, + keyv: digiTrustId.keyv + } + }, + getDigiTrustId: function(bidRequest) { + const bidRequestDigiTrust = utils.deepAccess(bidRequest, 'userId.digitrustid.data'); + if (bidRequestDigiTrust) return bidRequestDigiTrust; + + const digiTrustUser = getConfig('digiTrustId'); + return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || null; + }, + transformRTBToPrebidProps: function(bid, serverResponse) { + bid.cpm = bid.price; delete bid.price; + bid.bidId = bid.impid; + bid.requestId = bid.impid; delete bid.impid; + bid.width = bid.w || BB_CONSTANTS.DEFAULT_WIDTH; + bid.height = bid.h || BB_CONSTANTS.DEFAULT_HEIGHT; + if (bid.adm) { + bid.ad = bid.adm; + bid.vastXml = bid.adm; + delete bid.adm; + } + if (bid.nurl && !bid.adm) { // ad markup is on win notice url, and adm is ommited according to OpenRTB 2.5 + bid.vastUrl = bid.nurl; + delete bid.nurl; + } + bid.netRevenue = BB_CONSTANTS.DEFAULT_NET_REVENUE; + bid.creativeId = bid.crid; delete bid.crid; + bid.currency = serverResponse.cur; + bid.ttl = BB_CONSTANTS.DEFAULT_TTL; + }, +}; + +// Renderer Functions +const BB_RENDERER = { + bootstrapPlayer: function(bid) { + const config = { + code: bid.adUnitCode, + }; + + if (bid.vastXml) config.vastXml = bid.vastXml; + else if (bid.vastUrl) config.vastUrl = bid.vastUrl; + + if (!bid.vastXml && !bid.vastUrl) { + utils.logWarn(`${BB_CONSTANTS.BIDDER_CODE}: No vastXml or vastUrl on bid, bailing...`); + return; + } + + const rendererId = BB_RENDERER.getRendererId(bid.publicationName, bid.rendererCode); + + const ele = document.getElementById(bid.adUnitCode); // NB convention + + let renderer; + + for (let rendererIndex = 0; rendererIndex < window.bluebillywig.renderers.length; rendererIndex++) { + if (window.bluebillywig.renderers[rendererIndex]._id === rendererId) { + renderer = window.bluebillywig.renderers[rendererIndex]; + break; + } + } + + if (renderer) renderer.bootstrap(config, ele); + else utils.logWarn(`${BB_CONSTANTS.BIDDER_CODE}: Couldn't find a renderer with ${rendererId}`); + }, + newRenderer: function(rendererUrl, adUnitCode) { + const renderer = Renderer.install({ + url: rendererUrl, + loaded: false, + adUnitCode + }); + + try { + renderer.setRender(BB_RENDERER.outstreamRender); + } catch (err) { + utils.logWarn(`${BB_CONSTANTS.BIDDER_CODE}: Error tying to setRender on renderer`, err); + } + + return renderer; + }, + outstreamRender: function(bid) { + bid.renderer.push(function() { BB_RENDERER.bootstrapPlayer(bid) }); + }, + getRendererId: function(pub, renderer) { + return `${pub}-${renderer}`; // NB convention! + } +}; + +// Spec Functions +// These functions are used to construct the core spec for the adapter +export const spec = { + code: BB_CONSTANTS.BIDDER_CODE, + supportedMediaTypes: [VIDEO], + syncStore: { bidders: [], }, + isBidRequestValid(bid) { + const publicationNameRegex = /^\w+\.?\w+$/; + const rendererRegex = /^[\w+_]+$/; + + if (!bid.params) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no params set on bid. Rejecting bid: `, bid); + return false; + } + + if (!bid.params.hasOwnProperty('publicationName') || typeof bid.params.publicationName !== 'string') { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no publicationName specified in bid params, or it's not a string. Rejecting bid: `, bid); + return false; + } else if (!publicationNameRegex.test(bid.params.publicationName)) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: publicationName must be in format 'publication' or 'publication.environment'. Rejecting bid: `, bid); + return false; + } + + if ((!bid.params.hasOwnProperty('rendererCode') || typeof bid.params.rendererCode !== 'string')) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no rendererCode was specified in bid params. Rejecting bid: `, bid); + return false; + } else if (!rendererRegex.test(bid.params.rendererCode)) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: rendererCode must be alphanumeric, including underscores. Rejecting bid: `, bid); + return false; + } + + if (!bid.params.accountId) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no accountId specified in bid params. Rejecting bid: `, bid); + return false; + } + + if (bid.params.hasOwnProperty('connections')) { + if (!Array.isArray(bid.params.connections)) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: connections is not of type array. Rejecting bid: `, bid); + return false; + } else { + for (let connectionIndex = 0; connectionIndex < bid.params.connections.length; connectionIndex++) { + const connection = bid.params.connections[connectionIndex]; + if (!bid.params.hasOwnProperty(connection)) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: connection specified in params.connections, but not configured in params. Rejecting bid: `, bid); + return false; + } + } + } + } else { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no connections specified in bid. Rejecting bid: `, bid); + return false; + } + + if (bid.hasOwnProperty('mediaTypes') && bid.mediaTypes.hasOwnProperty(VIDEO)) { + if (!bid.mediaTypes[VIDEO].hasOwnProperty('context')) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no context specified in bid. Rejecting bid: `, bid); + return false; + } + + if (bid.mediaTypes[VIDEO].context !== 'outstream') { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: video.context is invalid, must be "outstream". Rejecting bid: `, bid); + return false; + } + } else { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: mediaTypes or mediaTypes.video is not specified. Rejecting bid: `, bid); + return false; + } + + return true; + }, + buildRequests(validBidRequests, bidderRequest) { + const imps = []; + + for (let validBidRequestIndex = 0; validBidRequestIndex < validBidRequests.length; validBidRequestIndex++) { + const validBidRequest = validBidRequests[validBidRequestIndex]; + const _this = this; + + const ext = validBidRequest.params.connections.reduce(function(extBuilder, connection) { + extBuilder[connection] = validBidRequest.params[connection]; + + if (_this.syncStore.bidders.indexOf(connection) === -1) _this.syncStore.bidders.push(connection); + + return extBuilder; + }, {}); + + imps.push({ id: validBidRequest.bidId, ext, secure: window.location.protocol === 'https' ? 1 : 0, video: utils.deepAccess(validBidRequest, 'mediaTypes.video') }); + } + + const request = { + id: bidderRequest.auctionId, + source: {tid: bidderRequest.auctionId}, + tmax: BB_CONSTANTS.DEFAULT_TIMEOUT, + imp: imps, + test: DEV_MODE ? 1 : 0, + ext: { + prebid: { + targeting: { includewinners: true, includebidderkeys: false } + } + } + }; + + // handle privacy settings for GDPR/CCPA/COPPA + if (bidderRequest.gdprConsent) { + let gdprApplies = 0; + if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; + utils.deepSetValue(request, 'regs.ext.gdpr', gdprApplies); + utils.deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + + if (bidderRequest.uspConsent) { + utils.deepSetValue(request, 'regs.ext.us_privacy', bidderRequest.uspConsent); + this.syncStore.uspConsent = bidderRequest.uspConsent; + } + + if (getConfig('coppa') == true) utils.deepSetValue(request, 'regs.coppa', 1); + + // Enrich the request with any external data we may have + BB_HELPERS.addSiteAppDevice(request, bidderRequest.refererInfo && bidderRequest.refererInfo.referer); + BB_HELPERS.addSchain(request, validBidRequests); + BB_HELPERS.addCurrency(request); + BB_HELPERS.addUserIds(request, validBidRequests); + BB_HELPERS.addDigiTrust(request, validBidRequests); + + return { + method: 'POST', + url: BB_HELPERS.getAuctionUrl(validBidRequests[0].params.publicationName), + data: JSON.stringify(request), + bidderRequest: bidderRequest + }; + }, + interpretResponse(serverResponse, request) { + serverResponse = serverResponse.body || {}; + + if (!serverResponse.hasOwnProperty('seatbid') || !Array.isArray(serverResponse.seatbid)) { + return []; + } + + const bids = []; + + for (let seatbidIndex = 0; seatbidIndex < serverResponse.seatbid.length; seatbidIndex++) { + const seatbid = serverResponse.seatbid[seatbidIndex]; + if (!seatbid.bid || !Array.isArray(seatbid.bid)) continue; + for (let bidIndex = 0; bidIndex < seatbid.bid.length; bidIndex++) { + const bid = seatbid.bid[bidIndex]; + BB_HELPERS.transformRTBToPrebidProps(bid, serverResponse); + + let bidParams; + for (let bidderRequestBidsIndex = 0; bidderRequestBidsIndex < request.bidderRequest.bids.length; bidderRequestBidsIndex++) { + if (request.bidderRequest.bids[bidderRequestBidsIndex].bidId === bid.bidId) { + bidParams = request.bidderRequest.bids[bidderRequestBidsIndex].params; + } + } + + if (bidParams) { + bid.publicationName = bidParams.publicationName; + bid.rendererCode = bidParams.rendererCode; + bid.accountId = bidParams.accountId; + } + + const rendererUrl = BB_HELPERS.getRendererUrl(bid.publicationName, bid.rendererCode); + + bid.renderer = BB_RENDERER.newRenderer(rendererUrl, bid.adUnitCode); + + bids.push(bid); + } + } + + return bids; + }, + getUserSyncs(syncOptions, serverResponses, gdpr) { + if (!serverResponses || !serverResponses.length) return []; + if (!syncOptions.iframeEnabled) return []; + + const queryString = []; + let accountId; + let publication; + + const serverResponse = serverResponses[0]; + if (!serverResponse.body || !serverResponse.body.seatbid) return []; + + for (let seatbidIndex = 0; seatbidIndex < serverResponse.body.seatbid.length; seatbidIndex++) { + const seatbid = serverResponse.body.seatbid[seatbidIndex]; + for (let bidIndex = 0; bidIndex < seatbid.bid.length; bidIndex++) { + const bid = seatbid.bid[bidIndex]; + accountId = bid.accountId || null; + publication = bid.publicationName || null; + + if (publication && accountId) break; + } + if (publication && accountId) break; + } + + if (!publication || !accountId) return []; + + if (gdpr.gdprApplies) queryString.push(`gdpr=${gdpr.gdprApplies ? 1 : 0}`); + if (gdpr.gdprApplies && gdpr.consentString) queryString.push(`gdpr_consent=${gdpr.consentString}`); + + if (this.syncStore.uspConsent) queryString.push(`usp_consent=${this.syncStore.uspConsent}`); + + queryString.push(`accountId=${accountId}`); + queryString.push(`bidders=${btoa(JSON.stringify(this.syncStore.bidders))}`); + queryString.push(`cb=${Date.now()}-${Math.random().toString().replace('.', '')}`); + + if (DEV_MODE) queryString.push('bbpbs_debug=true'); + + // NB syncUrl by default starts with ?pub=$$PUBLICATION + const syncUrl = `${BB_HELPERS.getSyncUrl(publication)}&${queryString.join('&')}`; + + return [{ + type: 'iframe', + url: syncUrl + }]; + } +}; + +registerBidder(spec); diff --git a/modules/bluebillywigBidAdapter.md b/modules/bluebillywigBidAdapter.md new file mode 100644 index 00000000000..7879697baf5 --- /dev/null +++ b/modules/bluebillywigBidAdapter.md @@ -0,0 +1,38 @@ +# Overview + +``` +Module Name: Blue Billywig Adapter +Module Type: Bidder Adapter +Maintainer: dev+prebid@bluebillywig.com +``` + +# Description + +Prebid Blue Billywig Bidder Adapter + +# Test Parameters + +``` + const adUnits = [{ + code: 'ad-unit', + sizes: [[[768,432],[640,480],[640,360]]], + mediaTypes: { + video: { + playerSize: [768, 432], + context: 'outstream', + mimes: ['video/mp4'], + protocols: [ 2,3,5,6] + } + }, + bids: [{ + bidder: 'bluebillywig', + params: { + publicationName: "bbprebid", + rendererCode: "renderer", + accountId: 642, + connections: [ 'bluebillywig' ], + bluebillywig: {} + } + }] + }]; +``` diff --git a/modules/brainyBidAdapter.js b/modules/brainyBidAdapter.js deleted file mode 100644 index a5d076d8fd0..00000000000 --- a/modules/brainyBidAdapter.js +++ /dev/null @@ -1,154 +0,0 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { BANNER } from '../src/mediaTypes'; - -const BIDDER_CODE = 'brainy'; -const BASE_URL = '//proparm.jp/ssp/p/pbjs'; - -/** - * Check if the browser supports flash - * 0 is return if it dosen't support flash - * @return {int} Flash version - */ -/** - * 接続元のブラウザがフラッシュに対応しているか判定 - * 対応していなければ0を返す - * @return {int} フラッシュのバージョン - */ -function _getFlash() { - try { - var _mac = (navigator.userAgent.indexOf('Mac') != -1); - if (document.all) { - if (_mac) { - if (window['sample']) { - return ((window['sample'].FlashVersion() & 0xffff0000) >> 16); - } - } else { - var _axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash'); - return Math.floor(_axo.FlashVersion() / 0x10000); - } - } else { - if (navigator.plugins && navigator.plugins['Shockwave Flash']) { - var info = navigator.plugins['Shockwave Flash'].description.split(' '); - var _v = parseInt(info[2]); - if (!isNaN(_v)) { - return _v; - } - } - } - } catch (e) {} - return 0; -} - -export const spec = { - code: BIDDER_CODE, - supportedMediaTypes: [BANNER], - - /** - * Check if the bid account ID and slotID is valid - * @param {object} bid the brainy bid to validate - * @return {boolean} - */ - /** - * adUnits.bidに値が入っているかを判断する - * @param {object} bid 検証する入札リクエスト - * @return {boolean} - */ - isBidRequestValid: function(bid) { - return !!(bid && bid.params && bid.params.accountID && bid.params.slotID); - }, - - /** - * Format the bid request object for our endpoint - * @param {BidRequest[]} bidRequests Array of brainy bidders - * @return object of parameters for Prebid AJAX request - */ - /** - * 入札リクエストをbrainyに対応するように整形する - * @param {BidRequest[]} bidRequests 入札のための配列 - * @return Prebid AJAX用に整形したオブジェクト - */ - buildRequests: function(validBidRequests) { - var bidRequests = []; - for (var i = 0, len = validBidRequests.length; i < len; i++) { - var bid = validBidRequests[i]; - var accountID = utils.getBidIdParameter('accountID', bid.params); - var slotID = utils.getBidIdParameter('slotID', bid.params); - var url = utils.getTopWindowUrl(); - var flash = _getFlash(); - var nocache = new Date().getTime() + Math.floor(Math.random() * 100000000); - var requestURL; - - requestURL = '_aid=' + accountID + '&'; - requestURL += '_slot=' + slotID + '&'; - requestURL += '_url=' + url + '&'; - requestURL += '_flash=' + flash + '&'; - requestURL += '_nocache=' + nocache; - - bidRequests.push({ - method: 'GET', - url: BASE_URL, - data: requestURL, - bidRequest: bid - }) - } - return bidRequests; - }, - - /** - * Format brainy responses as Prebid bid responses - * @param {String} brainyResponseObj A successful response from brainy. - * @param {object} request Object received from web page - * @return {object} An array of formatted bids. - */ - /** - * brainySSPからのレスポンスを解釈するメソッド - * @param {String} brainyResponseObj SSPから受け取った文字列 - * @param {object} request メディアから受け取ったオブジェクト - * @return {object} 分解、再格納したbidResponses - */ - interpretResponse: function (brainyResponseObj, request) { - var bidResponses = []; - var bidRequest = request.bidRequest; - var responseBody = brainyResponseObj ? brainyResponseObj.body : {}; - - bidResponses.push({ - requestId: bidRequest.bidId, - cpm: responseBody.cpm || 0, - width: responseBody.width, - height: responseBody.height, - creativeId: responseBody.adID, - currency: 'USD', - netRevenue: true, - ttl: 1000, - mediaType: BANNER, - ad: responseBody.src - }); - - return bidResponses; - }, - - /** - * SyncURLがある場合にレスポンスを解析してURLを返す - * @param {object} syncOptions Syncの設定 - * @param {object} serverResponses SSPからのレスポンス - * @return {object} 表示タイプとURLが入ったオブジェクト - */ - getUserSyncs: function(syncOptions, serverResponses) { - const syncs = []; - if (syncOptions.pixelEnabled) { - const brainyResponseObj = serverResponses[0].body; - if (!brainyResponseObj) { - return []; - } - if (brainyResponseObj.syncUrl && brainyResponseObj.syncUrl != 'null' && brainyResponseObj.syncUrl.length > 0) { - syncs.push({ - type: 'image', - url: brainyResponseObj.syncUrl - }); - } - } - return syncs; - } -}; -registerBidder(spec); diff --git a/modules/bridgewellBidAdapter.js b/modules/bridgewellBidAdapter.js index cac827e5a5d..0303e4f74bd 100644 --- a/modules/bridgewellBidAdapter.js +++ b/modules/bridgewellBidAdapter.js @@ -1,10 +1,10 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER, NATIVE} from '../src/mediaTypes'; -import find from 'core-js/library/fn/array/find'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE } from '../src/mediaTypes.js'; +import find from 'core-js-pure/features/array/find.js'; const BIDDER_CODE = 'bridgewell'; -const REQUEST_ENDPOINT = '//rec.scupio.com/recweb/prebid.aspx?cb=' + Math.random(); +const REQUEST_ENDPOINT = 'https://prebid.scupio.com/recweb/prebid.aspx?cb=' + Math.random(); const BIDDER_VERSION = '0.0.2'; export const spec = { @@ -17,23 +17,11 @@ export const spec = { * @param {BidRequest} bid The bid params to validate. * @return boolean True if this is a valid bid, and false otherwise. */ - isBidRequestValid: function(bid) { + isBidRequestValid: function (bid) { let valid = false; - let typeOfCpmWeight; - - if (bid && bid.params) { - if (bid.params.ChannelID) { - // cpmWeight is optinal parameter and should above than zero - typeOfCpmWeight = typeof bid.params.cpmWeight; - if (typeOfCpmWeight === 'undefined') { - bid.params.cpmWeight = 1; - valid = true; - } else if (typeOfCpmWeight === 'number' && bid.params.cpmWeight > 0) { - valid = true; - } else { - valid = false; - } - } + + if (bid && bid.params && bid.params.ChannelID) { + valid = true; } return valid; @@ -45,11 +33,12 @@ export const spec = { * @param {BidRequest[]} validBidRequests - an array of bids * @return ServerRequest Info describing the request to the server. */ - buildRequests: function(validBidRequests) { + buildRequests: function (validBidRequests, bidderRequest) { const adUnits = []; - utils._each(validBidRequests, function(bid) { + utils._each(validBidRequests, function (bid) { adUnits.push({ ChannelID: bid.params.ChannelID, + adUnitCode: bid.adUnitCode, mediaTypes: bid.mediaTypes || { banner: { sizes: bid.sizes @@ -58,6 +47,11 @@ export const spec = { }); }); + let topUrl = ''; + if (bidderRequest && bidderRequest.refererInfo) { + topUrl = bidderRequest.refererInfo.referer; + } + return { method: 'POST', url: REQUEST_ENDPOINT, @@ -67,8 +61,8 @@ export const spec = { bridgewell: BIDDER_VERSION }, inIframe: utils.inIframe(), - url: utils.getTopWindowUrl(), - referrer: utils.getTopWindowReferrer(), + url: topUrl, + referrer: getTopWindowReferrer(), adUnits: adUnits }, validBidRequests: validBidRequests @@ -82,40 +76,41 @@ export const spec = { * @param {*} bidRequest * @return {Bid[]} An array of bids which were nested inside the server. */ - interpretResponse: function(serverResponse, bidRequest) { + interpretResponse: function (serverResponse, bidRequest) { const bidResponses = []; // map responses to requests - utils._each(bidRequest.validBidRequests, function(req) { + utils._each(bidRequest.validBidRequests, function (req) { const bidResponse = {}; if (!serverResponse.body) { return; } - let matchedResponse = find(serverResponse.body, function(res) { + let matchedResponse = find(serverResponse.body, function (res) { let valid = false; - if (!!res && !res.consumed) { // response exists and not consumed - if (res.width && res.height) { - let mediaTypes = req.mediaTypes; - // for prebid 1.0 and later usage, mediaTypes.banner.sizes - let sizes = mediaTypes && mediaTypes.banner && mediaTypes.banner.sizes ? mediaTypes.banner.sizes : req.sizes; - if (sizes) { - let sizeValid; - let width = res.width; - let height = res.height; - // check response size validation - if (typeof sizes[0] === 'number') { // for foramt Array[Number] check - sizeValid = width === sizes[0] && height === sizes[1]; - } else { // for format Array[Array[Number]] check - sizeValid = find(sizes, function(size) { - return (width === size[0] && height === size[1]); - }); - } - - if (sizeValid || (mediaTypes && mediaTypes.native)) { // dont care native sizes - valid = true; + if (res && !res.consumed) { + let mediaTypes = req.mediaTypes; + let adUnitCode = req.adUnitCode; + if (res.adUnitCode) { + return res.adUnitCode === adUnitCode; + } else if (res.width && res.height && mediaTypes) { + if (mediaTypes.native) { // dont care native sizes + valid = true; + } else if (mediaTypes.banner) { + if (mediaTypes.banner.sizes) { + let width = res.width; + let height = res.height; + let sizes = mediaTypes.banner.sizes; + // check response size validation + if (typeof sizes[0] === 'number') { // for foramt Array[Number] check + valid = width === sizes[0] && height === sizes[1]; + } else { // for format Array[Array[Number]] check + valid = !!find(sizes, function (size) { + return (width === size[0] && height === size[1]); + }); + } } } } @@ -139,7 +134,7 @@ export const spec = { } bidResponse.requestId = req.bidId; - bidResponse.cpm = matchedResponse.cpm * req.params.cpmWeight; + bidResponse.cpm = matchedResponse.cpm; bidResponse.width = matchedResponse.width; bidResponse.height = matchedResponse.height; bidResponse.ttl = matchedResponse.ttl; @@ -266,4 +261,12 @@ export const spec = { } }; +function getTopWindowReferrer() { + try { + return window.top.document.referrer; + } catch (e) { + return ''; + } +} + registerBidder(spec); diff --git a/modules/bridgewellBidAdapter.md b/modules/bridgewellBidAdapter.md index 014be62ccef..6bcab4b8820 100644 --- a/modules/bridgewellBidAdapter.md +++ b/modules/bridgewellBidAdapter.md @@ -1,8 +1,8 @@ # Overview -Module Name: Bridgewell Bidder Adapter -Module Type: Bidder Adapter -Maintainer: kuchunchou@bridgewell.com +Module Name: Bridgewell Bidder Adapter +Module Type: Bidder Adapter +Maintainer: scupio@bridgewell.com # Description @@ -12,34 +12,15 @@ Module that connects to Bridgewell demand source to fetch bids. ``` var adUnits = [{ code: 'test-div', - sizes: [ - [300, 250] - ], - bids: [{ - bidder: 'bridgewell', - params: { - ChannelID: 'CgUxMjMzOBIBNiIFcGVubnkqCQisAhD6ARoBOQ' - } - }] - }, { - code: 'test-div', - sizes: [ - [728, 90] - ], - bids: [{ - bidder: 'bridgewell', - params: { - ChannelID: 'CgUxMjMzOBIBNiIGcGVubnkzKggI2AUQWhoBOQ', - cpmWeight: 1.5 + mediaTypes: { + banner: { + sizes: [300, 250] } - }] - }, { - code: 'test-div', - sizes: [728, 90], + }, bids: [{ bidder: 'bridgewell', params: { - ChannelID: 'CgUxMjMzOBIBNiIGcGVubnkzKggI2AUQWhoBOQ' + ChannelID: 'CgUxMjMzOBIBNiIFcGVubnkqCQisAhD6ARoBOQ' } }] }, { diff --git a/modules/brightcomBidAdapter.js b/modules/brightcomBidAdapter.js index 626aa99f5de..a4b013a2fe2 100644 --- a/modules/brightcomBidAdapter.js +++ b/modules/brightcomBidAdapter.js @@ -1,8 +1,7 @@ -import * as utils from '../src/utils'; -import * as url from '../src/url'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER } from '../src/mediaTypes'; -import { config } from '../src/config'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'brightcom'; const URL = 'https://brightcombid.marphezis.com/hb'; @@ -25,9 +24,10 @@ function buildRequests(bidReqs, bidderRequest) { const brightcomImps = []; const publisherId = utils.getBidIdParameter('publisherId', bidReqs[0].params); utils._each(bidReqs, function (bid) { - bid.sizes = ((utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0])) ? bid.sizes : [bid.sizes]); - bid.sizes = bid.sizes.filter(size => utils.isArray(size)); - const processedSizes = bid.sizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)})); + let bidSizes = (bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes) || bid.sizes; + bidSizes = ((utils.isArray(bidSizes) && utils.isArray(bidSizes[0])) ? bidSizes : [bidSizes]); + bidSizes = bidSizes.filter(size => utils.isArray(size)); + const processedSizes = bidSizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)})); const element = document.getElementById(bid.adUnitCode); const minSize = _getMinSize(processedSizes); @@ -56,7 +56,7 @@ function buildRequests(bidReqs, bidderRequest) { id: utils.getUniqueIdentifierStr(), imp: brightcomImps, site: { - domain: url.parse(referrer).host, + domain: utils.parseUrl(referrer).host, page: referrer, publisher: { id: publisherId diff --git a/modules/brightcomBidAdapter.md b/modules/brightcomBidAdapter.md index badc6ea94a4..9f9aa0e5dd7 100644 --- a/modules/brightcomBidAdapter.md +++ b/modules/brightcomBidAdapter.md @@ -16,17 +16,25 @@ Brightcom's adapter integration to the Prebid library. var adUnits = [ { code: 'test-leaderboard', - sizes: [[728, 90]], + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, bids: [{ bidder: 'brightcom', params: { - publisherId: 2141020, - bidFloor: 0.01 + publisherId: 2141020, + bidFloor: 0.01 } }] }, { code: 'test-banner', - sizes: [[300, 250]], + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, bids: [{ bidder: 'brightcom', params: { diff --git a/modules/britepoolIdSystem.js b/modules/britepoolIdSystem.js new file mode 100644 index 00000000000..17a39e96aad --- /dev/null +++ b/modules/britepoolIdSystem.js @@ -0,0 +1,132 @@ +/** + * This module adds BritePoolId to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/britepoolIdSystem + * @requires module:modules/userId + */ + +import * as utils from '../src/utils.js' +import {ajax} from '../src/ajax.js'; +import {submodule} from '../src/hook.js'; + +/** @type {Submodule} */ +export const britepoolIdSubmodule = { + /** + * Used to link submodule with config + * @type {string} + */ + name: 'britepoolId', + /** + * Decode the stored id value for passing to bid requests + * @function + * @param {string} value + * @returns {{britepoolid:string}} + */ + decode(value) { + return (value && typeof value['primaryBPID'] === 'string') ? { 'britepoolid': value['primaryBPID'] } : null; + }, + /** + * Performs action to obtain id and return a value in the callback's response argument + * @function + * @param {SubmoduleParams} [configParams] + * @returns {function(callback:function)} + */ + getId(submoduleConfigParams, consentData) { + const { params, headers, url, getter, errors } = britepoolIdSubmodule.createParams(submoduleConfigParams, consentData); + let getterResponse = null; + if (typeof getter === 'function') { + getterResponse = getter(params); + // First let's rule out that the response is not a function + if (typeof getterResponse !== 'function') { + // Optimization to return value from getter + return { + id: britepoolIdSubmodule.normalizeValue(getterResponse) + }; + } + } + // Return for async operation + return { + callback: function(callback) { + if (errors.length > 0) { + errors.forEach(error => utils.logError(error)); + callback(); + return; + } + if (getterResponse) { + // Resolve the getter function response + try { + getterResponse(function(response) { + callback(britepoolIdSubmodule.normalizeValue(response)); + }); + } catch (error) { + if (error !== '') utils.logError(error); + callback(); + } + } else { + ajax(url, { + success: response => { + const responseObj = britepoolIdSubmodule.normalizeValue(response); + callback(responseObj ? { primaryBPID: responseObj.primaryBPID } : null); + }, + error: error => { + if (error !== '') utils.logError(error); + callback(); + } + }, JSON.stringify(params), { customHeaders: headers, contentType: 'application/json', method: 'POST', withCredentials: true }); + } + } + } + }, + /** + * Helper method to create params for our API call + * @param {SubmoduleParams} [configParams] + * @returns {object} Object with parsed out params + */ + createParams(submoduleConfigParams, consentData) { + let errors = []; + const headers = {}; + let params = Object.assign({}, submoduleConfigParams); + if (params.getter) { + // Custom getter will not require other params + if (typeof params.getter !== 'function') { + errors.push(`userIdTargeting - britepoolId submodule requires getter to be a function`); + return { errors }; + } + } else { + if (params.api_key) { + // Add x-api-key into the header + headers['x-api-key'] = params.api_key; + } + } + const url = params.url || 'https://api.britepool.com/v1/britepool/id'; + const getter = params.getter; + delete params.api_key; + delete params.url; + delete params.getter; + return { + params, + headers, + url, + getter, + errors + }; + }, + /** + * Helper method to normalize a JSON value + */ + normalizeValue(value) { + let valueObj = null; + if (typeof value === 'object') { + valueObj = value; + } else if (typeof value === 'string') { + try { + valueObj = JSON.parse(value); + } catch (error) { + utils.logError(error); + } + } + return valueObj; + } +}; + +submodule('userId', britepoolIdSubmodule); diff --git a/modules/britepoolIdSystem.md b/modules/britepoolIdSystem.md new file mode 100644 index 00000000000..89287aed7ca --- /dev/null +++ b/modules/britepoolIdSystem.md @@ -0,0 +1,42 @@ +## BritePool User ID Submodule + +BritePool User ID Module. For assistance setting up your module please contact us at [prebid@britepool.com](prebid@britepool.com). + +### Prebid Params + +Individual params may be set for the BritePool User ID Submodule. At least one identifier must be set in the params. +``` +pbjs.setConfig({ + usersync: { + userIds: [{ + name: 'britepoolId', + storage: { + name: 'britepoolid', + type: 'cookie', + expires: 30 + }, + params: { + url: 'https://sandbox-api.britepool.com/v1/britepool/id', // optional + api_key: '3fdbe297-3690-4f5c-9e11-ee9186a6d77c', // provided by britepool + hash: '31c5543c1734d25c7206f5fd591525d0295bec6fe84ff82f946a34fe970a1e66', // example hash identifier (sha256) + ssid: '221aa074-57fc-453b-81f0-6c74f628cd5c' // example identifier + } + }] + } +}); +``` +## Parameter Descriptions for the `usersync` Configuration Section +The below parameters apply only to the BritePool User ID Module integration. + +| Param under usersync.userIds[] | Scope | Type | Description | Example | +| --- | --- | --- | --- | --- | +| name | Required | String | ID value for the BritePool module - `"britepoolId"` | `"britepoolId"` | +| params | Required | Object | Details for BritePool initialization. | | +| params.api_key | Required | String |BritePool API Key provided by BritePool | "3fdbe297-3690-4f5c-9e11-ee9186a6d77c" | +| params.url | Optional | String |BritePool API url | "https://sandbox-api.britepool.com/v1/britepool/id" | +| params.identifier | Required | String | Where identifier in the params object is the key name. At least one identifier is required. Available Identifiers `aaid` `dtid` `idfa` `ilid` `luid` `mmid` `msid` `mwid` `rida` `ssid` `hash` | `params.ssid` `params.aaid` | +| storage | Required | Object | The publisher must specify the local storage in which to store the results of the call to get the user ID. This can be either cookie or HTML5 storage. | | +| storage.type | Required | String | This is where the results of the user ID will be stored. The recommended method is `localStorage` by specifying `html5`. | `"html5"` | +| storage.name | Required | String | The name of the cookie or html5 local storage where the user ID will be stored. | `"britepoolid"` | +| storage.expires | Optional | Integer | How long (in days) the user ID information will be stored. | `365` | +| value | Optional | Object | Used only if the page has a separate mechanism for storing the BritePool ID. The value is an object containing the values to be sent to the adapters. In this scenario, no URL is called and nothing is added to local storage | `{"primaryBPID": "eb33b0cb-8d35-4722-b9c0-1a31d4064888"}` | diff --git a/modules/browsiRtdProvider.js b/modules/browsiRtdProvider.js new file mode 100644 index 00000000000..9317786fb8d --- /dev/null +++ b/modules/browsiRtdProvider.js @@ -0,0 +1,312 @@ +/** + * This module adds browsi provider to the eal time data module + * The {@link module:modules/realTimeData} module is required + * The module will fetch predictions from browsi server + * The module will place browsi bootstrap script on page + * @module modules/browsiProvider + * @requires module:modules/realTimeData + */ + +/** + * @typedef {Object} ModuleParams + * @property {string} siteKey + * @property {string} pubKey + * @property {string} url + * @property {?string} keyName + * @property {?number} auctionDelay + * @property {?number} timeout + */ + +import {config} from '../src/config.js'; +import * as utils from '../src/utils.js'; +import {submodule} from '../src/hook.js'; +import {ajaxBuilder} from '../src/ajax.js'; +import {loadExternalScript} from '../src/adloader.js'; +import { getStorageManager } from '../src/storageManager.js'; +import find from 'core-js-pure/features/array/find.js'; + +const storage = getStorageManager(); + +/** @type {string} */ +const MODULE_NAME = 'realTimeData'; +/** @type {number} */ +const DEF_TIMEOUT = 1000; +/** @type {ModuleParams} */ +let _moduleParams = {}; +/** @type {null|Object} */ +let _data = null; +/** @type {null | function} */ +let _dataReadyCallback = null; + +/** + * add browsi script to page + * @param {Object} data + */ +export function addBrowsiTag(data) { + let script = loadExternalScript(data.u, 'browsi'); + script.async = true; + script.setAttribute('data-sitekey', _moduleParams.siteKey); + script.setAttribute('data-pubkey', _moduleParams.pubKey); + script.setAttribute('prebidbpt', 'true'); + script.setAttribute('id', 'browsi-tag'); + script.setAttribute('src', data.u); + script.prebidData = utils.deepClone(data); + if (_moduleParams.keyName) { + script.prebidData.kn = _moduleParams.keyName; + } + return script; +} + +/** + * collect required data from page + * send data to browsi server to get predictions + */ +function collectData() { + const win = window.top; + const doc = win.document; + let browsiData = null; + try { + browsiData = storage.getDataFromLocalStorage('__brtd'); + } catch (e) { + utils.logError('unable to parse __brtd'); + } + + let predictorData = { + ...{ + sk: _moduleParams.siteKey, + sw: (win.screen && win.screen.width) || -1, + sh: (win.screen && win.screen.height) || -1, + url: `${doc.location.protocol}//${doc.location.host}${doc.location.pathname}`, + }, + ...(browsiData ? {us: browsiData} : {us: '{}'}), + ...(document.referrer ? {r: document.referrer} : {}), + ...(document.title ? {at: document.title} : {}) + }; + getPredictionsFromServer(`//${_moduleParams.url}/prebid?${toUrlParams(predictorData)}`); +} + +export function setData(data) { + _data = data; + + if (typeof _dataReadyCallback === 'function') { + _dataReadyCallback(_data); + _dataReadyCallback = null; + } +} + +/** + * wait for data from server + * call callback when data is ready + * @param {function} callback + */ +function waitForData(callback) { + if (_data) { + _dataReadyCallback = null; + callback(_data); + } else { + _dataReadyCallback = callback; + } +} + +/** + * filter server data according to adUnits received + * call callback (onDone) when data is ready + * @param {adUnit[]} adUnits + * @param {function} onDone callback function + */ +function sendDataToModule(adUnits, onDone) { + try { + waitForData(_predictionsData => { + const _predictions = _predictionsData.p; + if (!_predictions || !Object.keys(_predictions).length) { + return onDone({}); + } + let dataToReturn = adUnits.reduce((rp, cau) => { + const adUnitCode = cau && cau.code; + if (!adUnitCode) { return rp } + const adSlot = getSlotByCode(adUnitCode); + const identifier = adSlot ? getMacroId(_predictionsData.pmd, adSlot) : adUnitCode; + const predictionData = _predictions[identifier]; + if (!predictionData) { return rp } + + if (predictionData.p) { + if (!isIdMatchingAdUnit(adSlot, predictionData.w)) { + return rp; + } + rp[adUnitCode] = getKVObject(predictionData.p, _predictionsData.kn); + } + return rp; + }, {}); + return onDone(dataToReturn); + }); + } catch (e) { + onDone({}); + } +} + +/** + * get all slots on page + * @return {Object[]} slot GoogleTag slots + */ +function getAllSlots() { + return utils.isGptPubadsDefined() && window.googletag.pubads().getSlots(); +} +/** + * get prediction and return valid object for key value set + * @param {number} p + * @param {string?} keyName + * @return {Object} key:value + */ +function getKVObject(p, keyName) { + const prValue = p < 0 ? 'NA' : (Math.floor(p * 10) / 10).toFixed(2); + let prObject = {}; + prObject[((_moduleParams['keyName'] || keyName).toString())] = prValue.toString(); + return prObject; +} +/** + * check if placement id matches one of given ad units + * @param {Object} slot google slot + * @param {string[]} whitelist ad units + * @return {boolean} + */ +export function isIdMatchingAdUnit(slot, whitelist) { + if (!whitelist || !whitelist.length || !slot) { + return true; + } + const slotAdUnits = slot.getAdUnitPath(); + return whitelist.indexOf(slotAdUnits) !== -1; +} + +/** + * get GPT slot by placement id + * @param {string} code placement id + * @return {?Object} + */ +function getSlotByCode(code) { + const slots = getAllSlots(); + if (!slots || !slots.length) { + return null; + } + return find(slots, s => s.getSlotElementId() === code || s.getAdUnitPath() === code) || null; +} + +/** + * generate id according to macro script + * @param {Object} macro replacement macro + * @param {Object} slot google slot + * @return {?Object} + */ +export function getMacroId(macro, slot) { + if (macro) { + try { + const macroResult = evaluate(macro, slot.getSlotElementId(), slot.getAdUnitPath(), (match, p1) => { + return (p1 && slot.getTargeting(p1).join('_')) || 'NA'; + }); + return macroResult; + } catch (e) { + utils.logError(`failed to evaluate: ${macro}`); + } + } + return slot.getSlotElementId(); +} + +function evaluate(macro, divId, adUnit, replacer) { + let macroResult = macro.p + .replace(/['"]+/g, '') + .replace(//g, divId); + + if (adUnit) { + macroResult = macroResult.replace(//g, adUnit); + } + if (replacer) { + macroResult = macroResult.replace(//g, replacer); + } + if (macro.s) { + macroResult = macroResult.substring(macro.s.s, macro.s.e); + } + return macroResult; +} +/** + * XMLHttpRequest to get data form browsi server + * @param {string} url server url with query params + */ +function getPredictionsFromServer(url) { + let ajax = ajaxBuilder(_moduleParams.auctionDelay || _moduleParams.timeout || DEF_TIMEOUT); + + ajax(url, + { + success: function (response, req) { + if (req.status === 200) { + try { + const data = JSON.parse(response); + if (data && data.p && data.kn) { + setData({p: data.p, kn: data.kn, pmd: data.pmd}); + } else { + setData({}); + } + addBrowsiTag(data); + } catch (err) { + utils.logError('unable to parse data'); + setData({}) + } + } else if (req.status === 204) { + // unrecognized site key + setData({}); + } + }, + error: function () { + setData({}); + utils.logError('unable to get prediction data'); + } + } + ); +} + +/** + * serialize object and return query params string + * @param {Object} data + * @return {string} + */ +function toUrlParams(data) { + return Object.keys(data) + .map(key => key + '=' + encodeURIComponent(data[key])) + .join('&'); +} + +/** @type {RtdSubmodule} */ +export const browsiSubmodule = { + /** + * used to link submodule with realTimeData + * @type {string} + */ + name: 'browsi', + /** + * get data and send back to realTimeData module + * @function + * @param {adUnit[]} adUnits + * @param {function} onDone + */ + getData: sendDataToModule +}; + +export function init(config) { + const confListener = config.getConfig(MODULE_NAME, ({realTimeData}) => { + try { + _moduleParams = realTimeData.dataProviders && realTimeData.dataProviders.filter( + pr => pr.name && pr.name.toLowerCase() === 'browsi')[0].params; + _moduleParams.auctionDelay = realTimeData.auctionDelay; + _moduleParams.timeout = realTimeData.timeout; + } catch (e) { + _moduleParams = {}; + } + if (_moduleParams.siteKey && _moduleParams.pubKey && _moduleParams.url) { + confListener(); + collectData(); + } else { + utils.logError('missing params for Browsi provider'); + } + }); +} + +submodule('realTimeData', browsiSubmodule); +init(config); diff --git a/modules/bucksenseBidAdapter.js b/modules/bucksenseBidAdapter.js index 12a9e287f38..3f327e62121 100644 --- a/modules/bucksenseBidAdapter.js +++ b/modules/bucksenseBidAdapter.js @@ -1,10 +1,10 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER } from '../src/mediaTypes'; -import * as utils from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; const WHO = 'BKSHBID-005'; const BIDDER_CODE = 'bucksense'; -const URL = 'https://prebid.bksn.se:445/prebidjs/'; +const URL = 'https://prebid.bksn.se/prebidjs/'; export const spec = { code: BIDDER_CODE, diff --git a/modules/buzzoolaBidAdapter.js b/modules/buzzoolaBidAdapter.js new file mode 100644 index 00000000000..f87607657c3 --- /dev/null +++ b/modules/buzzoolaBidAdapter.js @@ -0,0 +1,108 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {Renderer} from '../src/Renderer.js'; +import {OUTSTREAM} from '../src/video.js'; + +const BIDDER_CODE = 'buzzoola'; +const ENDPOINT = 'https://exchange.buzzoola.com/ssp/prebidjs'; +const RENDERER_SRC = 'https://tube.buzzoola.com/new/build/buzzlibrary.js'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['buzzoolaAdapter'], + supportedMediaTypes: [BANNER, VIDEO], + + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return {boolean} True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + let types = bid.mediaTypes; + return !!(bid && bid.mediaTypes && (types.banner || types.video) && bid.params && bid.params.placementId); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests an array of bids + * @param bidderRequest + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function (validBidRequests, bidderRequest) { + return { + url: ENDPOINT, + method: 'POST', + data: bidderRequest, + } + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @param bidderRequest + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function ({body}, {data}) { + let requestBids = {}; + let response; + + try { + response = JSON.parse(body); + } catch (ex) { + response = body; + } + + if (!Array.isArray(response)) response = []; + + data.bids.forEach(bid => requestBids[bid.bidId] = bid); + + return response.map(bid => { + let requestBid = requestBids[bid.requestId]; + let context = utils.deepAccess(requestBid, 'mediaTypes.video.context'); + let validBid = utils.deepClone(bid); + + if (validBid.mediaType === VIDEO && context === OUTSTREAM) { + let renderer = Renderer.install({ + id: validBid.requestId, + url: RENDERER_SRC, + loaded: false + }); + + renderer.setRender(setOutstreamRenderer); + validBid.renderer = renderer + } + + return validBid; + }); + } +}; + +/** + * Initialize Buzzoola Outstream player + * + * @param bid + */ +function setOutstreamRenderer(bid) { + let adData = JSON.parse(bid.ad); + let unitSettings = utils.deepAccess(adData, 'placement.unit_settings'); + let extendedSettings = { + width: '' + bid.width, + height: '' + bid.height, + container_height: '' + bid.height + }; + + adData.placement = Object.assign({}, adData.placement); + adData.placement.unit_settings = Object.assign({}, unitSettings, extendedSettings); + + bid.renderer.push(() => { + window.Buzzoola.Core.install(document.querySelector(`#${bid.adUnitCode}`), { + data: adData + }); + }); +} + +registerBidder(spec); diff --git a/modules/buzzoolaBidAdapter.md b/modules/buzzoolaBidAdapter.md new file mode 100644 index 00000000000..aec3eda6c58 --- /dev/null +++ b/modules/buzzoolaBidAdapter.md @@ -0,0 +1,72 @@ +# Overview + +``` +Module Name: Buzzoola Bid Adapter +Module Type: Bidder Adapter +Maintainer: devteam@buzzoola.com +``` + +# Description + +Connects to Buzzoola exchange for bids. + +Buzzoola bid adapter supports Banner and Video (instream and outstream). + +# Test Parameters +``` +var adUnits = [ + // Banner adUnit + { + code: 'banner-div', + mediaTypes: { + banner: { + sizes: [[240, 400], [300, 600]], + } + }, + bids: [{ + bidder: 'buzzoola', + params: { + placementId: 417846 + } + }] + }, + // Video instream adUnit + { + code: 'video-instream', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 380], + mimes: ['video/mp4'], + minduration: 1, + maxduration: 2, + } + }, + bids: [{ + bidder: 'buzzoola', + params: { + placementId: 417845 + } + }] + }, + // Video outstream adUnit + { + code: 'video-outstream', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 380], + mimes: ['video/mp4'], + minduration: 1, + maxduration: 2, + } + }, + bids: [{ + bidder: 'buzzoola', + params: { + placementId: 417845 + } + }] + } +]; +``` diff --git a/modules/byplayBidAdapter.js b/modules/byplayBidAdapter.js new file mode 100644 index 00000000000..6133cdfa647 --- /dev/null +++ b/modules/byplayBidAdapter.js @@ -0,0 +1,67 @@ +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; +import { VIDEO } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'byplay'; +const ENDPOINT_URL = 'https://prebid.byplay.net/bidder'; +const VIDEO_PLAYER_URL = 'https://cdn.byplay.net/prebid-byplay-v2.js'; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [VIDEO], + isBidRequestValid: (bid) => { + return !!bid.params.sectionId; + }, + buildRequests: function(validBidRequests) { + return validBidRequests.map(req => { + const payload = { + requestId: req.bidId, + sectionId: req.params.sectionId, + ...(req.params.env ? { env: req.params.env } : {}) + }; + + return { + method: 'POST', + url: ENDPOINT_URL, + data: JSON.stringify(payload), + options: { + withCredentials: false + } + }; + }); + }, + interpretResponse: (serverResponse, bidderRequest) => { + const response = serverResponse.body; + const data = JSON.parse(bidderRequest.data); + const bidResponse = { + requestId: data.requestId, + cpm: response.cpm, + width: response.width, + height: response.height, + creativeId: response.creativeId || '0', + ttl: config.getConfig('_bidderTimeout'), + currency: 'JPY', + netRevenue: response.netRevenue, + mediaType: VIDEO, + vastXml: response.vastXml, + renderer: createRenderer() + }; + + return [bidResponse]; + } +}; + +function createRenderer() { + const renderer = Renderer.install({ url: VIDEO_PLAYER_URL }); + + renderer.setRender(bid => { + bid.renderer.push(() => { + window.adtagRender(bid); + }); + }); + + return renderer; +} + +registerBidder(spec); diff --git a/modules/byplayBidAdapter.md b/modules/byplayBidAdapter.md new file mode 100644 index 00000000000..67fb9c40d35 --- /dev/null +++ b/modules/byplayBidAdapter.md @@ -0,0 +1,37 @@ +# Overview + +``` +Module Name: ByPlay Bidder Adapter +Module Type: Bidder Adapter +Maintainer: byplayers@tsumikiinc.com +``` + +# Description + +Connects to ByPlay exchange for bids. + +ByPlay bid adapter supports Video. + +# Test Parameters +``` + const adUnits = [ + { + code: 'byplay-ad', + mediaTypes: { + video: { + playerSize: [400, 225], + context: 'outstream' + } + }, + bids: [ + { + bidder: 'byplay', + params: { + sectionId: '7986', + env: 'dev' + } + } + ] + } + ]; +``` diff --git a/modules/c1xBidAdapter.js b/modules/c1xBidAdapter.js index 1e8d3cf2e0a..8e1f1487ba7 100644 --- a/modules/c1xBidAdapter.js +++ b/modules/c1xBidAdapter.js @@ -1,10 +1,10 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import * as utils from '../src/utils'; -import { userSync } from '../src/userSync'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; +import { userSync } from '../src/userSync.js'; const BIDDER_CODE = 'c1x'; const URL = 'https://ht.c1exchange.com/ht'; -const PIXEL_ENDPOINT = '//px.c1exchange.com/pubpixel/'; +const PIXEL_ENDPOINT = 'https://px.c1exchange.com/pubpixel/'; const LOG_MSG = { invalidBid: 'C1X: [ERROR] bidder returns an invalid bid', noSite: 'C1X: [ERROR] no site id supplied', @@ -41,7 +41,6 @@ export const c1xAdapter = { // flattened tags in a tag object tagObj = c1xTags.reduce((current, next) => Object.assign(current, next)); const pixelId = tagObj.pixelId; - const useSSL = document.location.protocol; payload = { adunits: adunits.toString(), @@ -58,7 +57,7 @@ export const c1xAdapter = { } if (pixelId) { - pixelUrl = (useSSL ? 'https:' : 'http:') + PIXEL_ENDPOINT + pixelId; + pixelUrl = PIXEL_ENDPOINT + pixelId; if (payload.consent_required) { pixelUrl += '&gdpr=' + (bidderRequest.gdprConsent.gdprApplies ? 1 : 0); pixelUrl += '&consent=' + encodeURIComponent(bidderRequest.gdprConsent.consentString || ''); diff --git a/modules/categoryTranslation.js b/modules/categoryTranslation.js index f4d0a281f57..9a9289fcd73 100644 --- a/modules/categoryTranslation.js +++ b/modules/categoryTranslation.js @@ -11,12 +11,14 @@ * If publisher has not defined translation file than prebid will use default prebid translation file provided here //cdn.jsdelivr.net/gh/prebid/category-mapping-file@1/freewheel-mapping.json */ -import { config } from '../src/config'; -import { setupBeforeHookFnOnce, hook } from '../src/hook'; -import { ajax } from '../src/ajax'; -import { timestamp, logError, setDataInLocalStorage, getDataFromLocalStorage } from '../src/utils'; -import { addBidResponse } from '../src/auction'; +import { config } from '../src/config.js'; +import { setupBeforeHookFnOnce, hook } from '../src/hook.js'; +import { ajax } from '../src/ajax.js'; +import { timestamp, logError } from '../src/utils.js'; +import { addBidResponse } from '../src/auction.js'; +import { getCoreStorageManager } from '../src/storageManager.js'; +export const storage = getCoreStorageManager('categoryTranslation'); const DEFAULT_TRANSLATION_FILE_URL = 'https://cdn.jsdelivr.net/gh/prebid/category-mapping-file@1/freewheel-mapping.json'; const DEFAULT_IAB_TO_FW_MAPPING_KEY = 'iabToFwMappingkey'; const DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB = 'iabToFwMappingkeyPub'; @@ -26,8 +28,8 @@ export const registerAdserver = hook('async', function(adServer) { let url; if (adServer === 'freewheel') { url = DEFAULT_TRANSLATION_FILE_URL; + initTranslation(url, DEFAULT_IAB_TO_FW_MAPPING_KEY); } - initTranslation(url, DEFAULT_IAB_TO_FW_MAPPING_KEY); }, 'registerAdserver'); registerAdserver(); @@ -43,15 +45,15 @@ export function getAdserverCategoryHook(fn, adUnitCode, bid) { let localStorageKey = (config.getConfig('brandCategoryTranslation.translationFile')) ? DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB : DEFAULT_IAB_TO_FW_MAPPING_KEY; if (bid.meta && !bid.meta.adServerCatId) { - let mapping = getDataFromLocalStorage(localStorageKey); + let mapping = storage.getDataFromLocalStorage(localStorageKey); if (mapping) { try { mapping = JSON.parse(mapping); } catch (error) { logError('Failed to parse translation mapping file'); } - if (bid.meta.iabSubCatId && mapping['mapping'] && mapping['mapping'][bid.meta.iabSubCatId]) { - bid.meta.adServerCatId = mapping['mapping'][bid.meta.iabSubCatId]['id']; + if (bid.meta.primaryCatId && mapping['mapping'] && mapping['mapping'][bid.meta.primaryCatId]) { + bid.meta.adServerCatId = mapping['mapping'][bid.meta.primaryCatId]['id']; } else { // This bid will be automatically ignored by adpod module as adServerCatId was not found bid.meta.adServerCatId = undefined; @@ -65,24 +67,29 @@ export function getAdserverCategoryHook(fn, adUnitCode, bid) { export function initTranslation(url, localStorageKey) { setupBeforeHookFnOnce(addBidResponse, getAdserverCategoryHook, 50); - let mappingData = getDataFromLocalStorage(localStorageKey); - if (!mappingData || timestamp() < mappingData.lastUpdated + refreshInDays * 24 * 60 * 60 * 1000) { - ajax(url, - { - success: (response) => { - try { - response = JSON.parse(response); - response['lastUpdated'] = timestamp(); - setDataInLocalStorage(localStorageKey, JSON.stringify(response)); - } catch (error) { - logError('Failed to parse translation mapping file'); + let mappingData = storage.getDataFromLocalStorage(localStorageKey); + try { + mappingData = mappingData ? JSON.parse(mappingData) : undefined; + if (!mappingData || timestamp() > mappingData.lastUpdated + refreshInDays * 24 * 60 * 60 * 1000) { + ajax(url, + { + success: (response) => { + try { + response = JSON.parse(response); + response['lastUpdated'] = timestamp(); + storage.setDataInLocalStorage(localStorageKey, JSON.stringify(response)); + } catch (error) { + logError('Failed to parse translation mapping file'); + } + }, + error: () => { + logError('Failed to load brand category translation file.') } }, - error: () => { - logError('Failed to load brand category translation file.') - } - }, - ); + ); + } + } catch (error) { + logError('Failed to parse translation mapping file'); } } diff --git a/modules/ccxBidAdapter.js b/modules/ccxBidAdapter.js index 226ed44f6da..ee15d6bb3ec 100644 --- a/modules/ccxBidAdapter.js +++ b/modules/ccxBidAdapter.js @@ -1,6 +1,9 @@ -import * as utils from '../src/utils' -import { registerBidder } from '../src/adapters/bidderFactory' -import { config } from '../src/config' +import * as utils from '../src/utils.js' +import { registerBidder } from '../src/adapters/bidderFactory.js' +import { config } from '../src/config.js' +import { getStorageManager } from '../src/storageManager.js'; + +const storage = getStorageManager(); const BIDDER_CODE = 'ccx' const BID_URL = 'https://delivery.clickonometrics.pl/ortb/prebid/bid' const SUPPORTED_VIDEO_PROTOCOLS = [2, 3, 5, 6] @@ -15,9 +18,9 @@ function _getDeviceObj () { return device } -function _getSiteObj () { +function _getSiteObj (bidderRequest) { let site = {} - let url = config.getConfig('pageUrl') || utils.getTopWindowUrl() + let url = config.getConfig('pageUrl') || utils.deepAccess(window, 'location.href'); if (url.length > 0) { url = url.split('?')[0] } @@ -167,10 +170,26 @@ export const spec = { if (validBidRequests.length > 0) { let requestBody = {} requestBody.imp = [] - requestBody.site = _getSiteObj() + requestBody.site = _getSiteObj(bidderRequest) requestBody.device = _getDeviceObj() requestBody.id = bidderRequest.bids[0].auctionId - requestBody.ext = {'ce': (utils.cookiesAreEnabled() ? 1 : 0)} + requestBody.ext = {'ce': (storage.cookiesAreEnabled() ? 1 : 0)} + + // Attaching GDPR Consent Params + if (bidderRequest && bidderRequest.gdprConsent) { + requestBody.user = { + ext: { + consent: bidderRequest.gdprConsent.consentString + } + }; + + requestBody.regs = { + ext: { + gdpr: (bidderRequest.gdprConsent.gdprApplies ? 1 : 0) + } + }; + } + utils._each(validBidRequests, function (bid) { requestBody.imp.push(_buildBid(bid)) }) diff --git a/modules/cedatoBidAdapter.js b/modules/cedatoBidAdapter.js index 78bb7b45c7b..ab381698f01 100644 --- a/modules/cedatoBidAdapter.js +++ b/modules/cedatoBidAdapter.js @@ -1,20 +1,20 @@ -import * as utils from 'src/utils'; -import { registerBidder } from 'src/adapters/bidderFactory'; -import { BANNER } from 'src/mediaTypes'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const storage = getStorageManager(); const BIDDER_CODE = 'cedato'; -const BID_URL = '//h.cedatoplayer.com/hb'; -const SYNC_URL = '//h.cedatoplayer.com/hb_usync?uid={UUID}'; -const COOKIE_NAME = 'hb-cedato-id'; -const UUID_LEN = 36; +const BID_URL = 'https://h.cedatoplayer.com/hb'; +const SYNC_URL = 'https://h.cedatoplayer.com/hb_usync'; const TTL = 10000; const CURRENCY = 'USD'; -const FIRST_PRICE = 1; const NET_REVENUE = true; export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: function(bid) { return !!( @@ -22,109 +22,193 @@ export const spec = { bid.params && bid.params.player_id && utils.checkCookieSupport() && - utils.cookiesAreEnabled() + storage.cookiesAreEnabled() ); }, buildRequests: function(bidRequests, bidderRequest) { - const req = bidRequests[Math.floor(Math.random() * bidRequests.length)]; - const params = req.params; - const at = FIRST_PRICE; - const site = { id: params.player_id, domain: document.domain }; - const device = { ua: navigator.userAgent, ip: '' }; - const user = { id: getUserID() } + const site = { domain: document.domain }; + const device = { ua: navigator.userAgent, w: screen.width, h: screen.height }; const currency = CURRENCY; const tmax = bidderRequest.timeout; + const auctionId = bidderRequest.auctionId; + const auctionStart = bidderRequest.auctionStart; + const bidderRequestId = bidderRequest.bidderRequestId; const imp = bidRequests.map(req => { - const banner = { 'format': getFormats(utils.deepAccess(req, 'mediaTypes.banner.sizes')) }; - const bidfloor = params.bidfloor; + const banner = getMediaType(req, 'banner'); + const video = getMediaType(req, 'video'); + const params = req.params; const bidId = req.bidId; + const adUnitCode = req.adUnitCode; + const bidRequestsCount = req.bidRequestsCount; + const bidderWinsCount = req.bidderWinsCount; + const transactionId = req.transactionId; return { bidId, banner, - bidfloor, + video, + adUnitCode, + bidRequestsCount, + bidderWinsCount, + transactionId, + params }; }); const payload = { version: '$prebid.version$', - at, site, device, - user, imp, currency, tmax, + auctionId, + auctionStart, + bidderRequestId }; - if (bidderRequest && bidderRequest.gdprConsent) { - payload.gdpr_consent = { - consent_string: bidderRequest.gdprConsent.consentString, - consent_required: bidderRequest.gdprConsent.gdprApplies - }; + if (bidderRequest) { + payload.referer_info = bidderRequest.refererInfo; + payload.us_privacy = bidderRequest.uspConsent; + + if (bidderRequest.gdprConsent) { + payload.gdpr_consent = { + consent_string: bidderRequest.gdprConsent.consentString, + consent_required: bidderRequest.gdprConsent.gdprApplies + }; + } } - return { - method: 'POST', - url: BID_URL, - data: JSON.stringify(payload), - }; + return formatRequest(payload, bidderRequest); }, - interpretResponse: function(resp) { - if (resp.body === '') return []; - - const bids = resp.body.seatbid[0].bid.map(bid => { - const cpm = bid.price; - const requestId = bid.uuid; - const width = bid.w; - const height = bid.h; - const creativeId = bid.crid; - const dealId = bid.dealid; - const currency = resp.body.cur; - const netRevenue = NET_REVENUE; - const ttl = TTL; - const ad = bid.adm; + interpretResponse: function(resp, {bidderRequest}) { + resp = resp.body; + const bids = []; - return { - cpm, - requestId, - width, - height, - creativeId, - dealId, - currency, - netRevenue, - ttl, - ad, - }; + if (!resp) { + return bids; + } + + resp.seatbid[0].bid.map(serverBid => { + const bid = newBid(serverBid, bidderRequest); + bid.currency = resp.cur; + bids.push(bid); }); return bids; }, - getUserSyncs: function(syncOptions, resps, gdprConsent) { + getUserSyncs: function(syncOptions, resps, gdprConsent, uspConsent) { const syncs = []; - if (syncOptions.pixelEnabled) { - resps.forEach(() => { - syncs.push(getSync('image', gdprConsent)); - }); - } if (syncOptions.iframeEnabled) { - resps.forEach(() => { - syncs.push(getSync('iframe', gdprConsent)); - }); + syncs.push(getSync('iframe', gdprConsent, uspConsent)); + } else if (syncOptions.pixelEnabled) { + syncs.push(getSync('image', gdprConsent, uspConsent)); } return syncs; } } -const getSync = (type, gdprConsent) => { - const uuid = getUserID(); +function getMediaType(req, type) { + const { mediaTypes } = req; + + if (!mediaTypes) { + return; + } + + switch (type) { + case 'banner': + if (mediaTypes.banner) { + const { sizes } = mediaTypes.banner; + return { + format: getFormats(sizes) + }; + } + break; + + case 'video': + if (mediaTypes.video) { + const { playerSize, context } = mediaTypes.video; + return { + context: context, + format: getFormats(playerSize) + }; + } + } +} + +function newBid(serverBid, bidderRequest) { + const bidRequest = utils.getBidRequest(serverBid.uuid, [bidderRequest]); + + const cpm = serverBid.price; + const requestId = serverBid.uuid; + const width = serverBid.w; + const height = serverBid.h; + const creativeId = serverBid.crid; + const dealId = serverBid.dealid; + const mediaType = serverBid.media_type; + const netRevenue = NET_REVENUE; + const ttl = TTL; + + const bid = { + cpm, + requestId, + width, + height, + mediaType, + creativeId, + dealId, + netRevenue, + ttl, + }; + + if (mediaType == 'video') { + const videoContext = utils.deepAccess(bidRequest, 'mediaTypes.video.context'); + + if (videoContext == 'instream') { + bid.vastUrl = serverBid.vast_url; + bid.vastImpUrl = serverBid.notify_url; + } + } else { + bid.ad = serverBid.adm; + } + + return bid; +} + +function formatRequest(payload, bidderRequest) { + const payloadByUrl = {}; + const requests = []; + + payload.imp.forEach(imp => { + const url = imp.params.bid_url || BID_URL; + if (!payloadByUrl[url]) { + payloadByUrl[url] = { + ...payload, + imp: [] + }; + } + payloadByUrl[url].imp.push(imp); + }); + + for (const url in payloadByUrl) { + requests.push({ + url, + method: 'POST', + data: JSON.stringify(payloadByUrl[url]), + bidderRequest + }); + } + + return requests; +} + +const getSync = (type, gdprConsent, uspConsent = '') => { const syncUrl = SYNC_URL; - let params = '&type=' + type; + let params = '?type=' + type + '&us_privacy=' + uspConsent; if (gdprConsent && typeof gdprConsent.consentString === 'string') { if (typeof gdprConsent.gdprApplies === 'boolean') { params += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; @@ -134,26 +218,10 @@ const getSync = (type, gdprConsent) => { } return { type: type, - url: syncUrl.replace('{UUID}', uuid) + params, + url: syncUrl + params, }; } -const getUserID = () => { - const cookieName = COOKIE_NAME; - const uuidLen = UUID_LEN; - - const i = document.cookie.indexOf(cookieName); - - if (i === -1) { - const uuid = utils.generateUUID(); - document.cookie = `${cookieName}=${uuid}; path=/`; - return uuid; - } - - const j = i + cookieName.length + 1; - return document.cookie.substring(j, j + uuidLen); -}; - const getFormats = arr => arr.map((s) => { return { w: s[0], h: s[1] }; }); diff --git a/modules/cleanmedianetBidAdapter.js b/modules/cleanmedianetBidAdapter.js index 15871e1a6ae..a8f37450d68 100644 --- a/modules/cleanmedianetBidAdapter.js +++ b/modules/cleanmedianetBidAdapter.js @@ -1,11 +1,14 @@ -import * as utils from '../src/utils'; -import {parse} from '../src/url'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {config} from '../src/config'; -import {Renderer} from '../src/Renderer'; -import {BANNER, VIDEO} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; +import {Renderer} from '../src/Renderer.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; export const helper = { + getTopWindowDomain: function (url) { + const domainStart = url.indexOf('://') + '://'.length; + return url.substring(domainStart, url.indexOf('/', domainStart) < 0 ? url.length : url.indexOf('/', domainStart)); + }, startsWith: function (str, search) { return str.substr(0, search.length) === search; }, @@ -66,15 +69,22 @@ export const spec = { const rtbBidRequest = { id: auctionId, site: { - domain: parse(url).hostname, + domain: helper.getTopWindowDomain(url), page: url, ref: bidderRequest.refererInfo.referer }, device: { - ua: navigator.userAgent + ua: navigator.userAgent, + dnt: utils.getDNT() ? 1 : 0, + h: screen.height, + w: screen.width, + language: navigator.language }, imp: [], - ext: {} + ext: {}, + user: { + ext: {} + } }; if ( @@ -86,6 +96,16 @@ export const spec = { consent_string: bidderRequest.gdprConsent.consentString, consent_required: bidderRequest.gdprConsent.gdprApplies }; + rtbBidRequest.regs = { + ext: { + gdpr: bidderRequest.gdprConsent.gdprApplies === true ? 1 : 0 + } + }; + rtbBidRequest.user = { + ext: { + consent: bidderRequest.gdprConsent.consentString + } + } } const imp = { @@ -94,12 +114,7 @@ export const spec = { tagid: adUnitCode, bidfloor: params.bidfloor || 0, bidfloorcur: 'USD', - secure: helper.startsWith( - utils.getTopWindowUrl().toLowerCase(), - 'http://' - ) - ? 0 - : 1 + secure: 1 }; const hasFavoredMediaType = @@ -113,7 +128,7 @@ export const spec = { w: sizes.length ? sizes[0][0] : 300, h: sizes.length ? sizes[0][1] : 250, pos: params.pos || 0, - topframe: bidderRequest.refererInfo.reachedTop + topframe: utils.inIframe() ? 0 : 1 } }); rtbBidRequest.imp.push(bannerImp); @@ -179,7 +194,7 @@ export const spec = { cpm: bid.price, width: bid.w, height: bid.h, - ttl: 60 * 10, + ttl: 360, creativeId: bid.crid || bid.adid, netRevenue: true, currency: bid.cur || response.cur, @@ -264,7 +279,7 @@ function newRenderer(bidRequest, bid, rendererOptions = {}) { url: (bidRequest.params && bidRequest.params.rendererUrl) || (bid.ext && bid.ext.renderer_url) || - '//s.wlplayer.com/video/latest/renderer.js', + 'https://s.wlplayer.com/video/latest/renderer.js', config: rendererOptions, loaded: false }); diff --git a/modules/clickforceBidAdapter.js b/modules/clickforceBidAdapter.js index 16ecdf713d9..20408fe9177 100644 --- a/modules/clickforceBidAdapter.js +++ b/modules/clickforceBidAdapter.js @@ -1,8 +1,8 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER, NATIVE} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, NATIVE} from '../src/mediaTypes.js'; const BIDDER_CODE = 'clickforce'; -const ENDPOINT_URL = '//ad.doublemax.net/adserver/prebid.json?cb=' + new Date().getTime() + '&hb=1&ver=1.21'; +const ENDPOINT_URL = 'https://ad.holmesmind.com/adserver/prebid.json?cb=' + new Date().getTime() + '&hb=1&ver=1.21'; export const spec = { code: BIDDER_CODE, @@ -112,12 +112,12 @@ export const spec = { if (syncOptions.iframeEnabled) { return [{ type: 'iframe', - url: 'https://cdn.doublemax.net/js/capmapping.htm' + url: 'https://cdn.holmesmind.com/js/capmapping.htm' }] } else if (syncOptions.pixelEnabled) { return [{ type: 'image', - url: 'https://c.doublemax.net/cm' + url: 'https://c.holmesmind.com/cm' }] } } diff --git a/modules/clicktripzBidAdapter.js b/modules/clicktripzBidAdapter.js new file mode 100644 index 00000000000..2149cbe4527 --- /dev/null +++ b/modules/clicktripzBidAdapter.js @@ -0,0 +1,67 @@ +import {logError, _each} from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'clicktripz'; +const ENDPOINT_URL = 'https://www.clicktripz.com/x/prebid/v1'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['ctz'], // short code + + isBidRequestValid: function (bid) { + if (bid && bid.params && bid.params.placementId && bid.params.siteId) { + return true; + } + + return false; + }, + + buildRequests: function (validBidRequests) { + let bidRequests = []; + + _each(validBidRequests, function (bid) { + bidRequests.push({ + bidId: bid.bidId, + placementId: bid.params.placementId, + siteId: bid.params.siteId, + sizes: bid.sizes.map(function (size) { + return size.join('x') + }) + }); + }); + return { + method: 'POST', + url: ENDPOINT_URL, + data: bidRequests + }; + }, + + interpretResponse: function (serverResponse) { + let bidResponses = []; + + if (serverResponse && serverResponse.body) { + _each(serverResponse.body, function (bid) { + if (bid.errors) { + logError(bid.errors); + return; + } + + const size = bid.size.split('x'); + bidResponses.push({ + requestId: bid.bidId, + cpm: bid.cpm, + width: size[0], + height: size[1], + creativeId: bid.creativeId, + currency: bid.currency, + netRevenue: bid.netRevenue, + ttl: bid.ttl, + adUrl: bid.adUrl + }); + }); + } + return bidResponses; + } +}; + +registerBidder(spec); diff --git a/modules/clicktripzBidAdapter.md b/modules/clicktripzBidAdapter.md new file mode 100644 index 00000000000..1de1e26f37a --- /dev/null +++ b/modules/clicktripzBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +``` +Module Name: Clicktripz Bidder Adapter +Module Type: Bidder Adapter +Maintainer: integration-support@clicktripz.com +``` + +# Description +Our module makes it easy to integrate Clicktripz demand sources into your website. + +Supported Ad Fortmats: +* Banner + +# Test Parameters +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]], + } + }, + bids: [ + { + bidder: "clicktripz", + params: { + placementId: '4312c63f', + siteId: 'prebid', + } + } + ] + } + ]; diff --git a/modules/coinzillaBidAdapter.js b/modules/coinzillaBidAdapter.js index 6918d47eb10..240a3f1fcde 100644 --- a/modules/coinzillaBidAdapter.js +++ b/modules/coinzillaBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import {config} from '../src/config'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'coinzilla'; const ENDPOINT_URL = 'https://request.czilladx.com/serve/request.php'; @@ -31,7 +31,7 @@ export const spec = { return []; } return validBidRequests.map(bidRequest => { - const sizes = utils.parseSizesInput(bidRequest.sizes)[0]; + const sizes = utils.parseSizesInput(bidRequest.params.size || bidRequest.sizes)[0]; const width = sizes.split('x')[0]; const height = sizes.split('x')[1]; const payload = { diff --git a/modules/collectcentBidAdapter.js b/modules/collectcentBidAdapter.js index 50ac377788e..add3e06430d 100644 --- a/modules/collectcentBidAdapter.js +++ b/modules/collectcentBidAdapter.js @@ -1,10 +1,10 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; -import * as utils from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; const BIDDER_CODE = 'collectcent'; -const URL_MULTI = '//publishers.motionspots.com/?c=o&m=multi'; -const URL_SYNC = '//publishers.motionspots.com/?c=o&m=cookie'; +const URL_MULTI = 'https://publishers.motionspots.com/?c=o&m=multi'; +const URL_SYNC = 'https://publishers.motionspots.com/?c=o&m=cookie'; export const spec = { code: BIDDER_CODE, diff --git a/modules/colombiaBidAdapter.js b/modules/colombiaBidAdapter.js index e5ebc41ebfd..55109dbaab2 100644 --- a/modules/colombiaBidAdapter.js +++ b/modules/colombiaBidAdapter.js @@ -1,72 +1,82 @@ -import * as utils from '../src/utils'; -import {config} from '../src/config'; -import {registerBidder} from '../src/adapters/bidderFactory'; -const BIDDER_CODE = 'colombia'; -const ENDPOINT_URL = 'https://ade.clmbtech.com/cde/prebid.htm'; -const HOST_NAME = document.location.protocol + '//' + window.location.host; - -export const spec = { - code: BIDDER_CODE, - aliases: ['clmb'], - isBidRequestValid: function(bid) { - return !!(bid.params.placementId); - }, - buildRequests: function(validBidRequests) { - return validBidRequests.map(bidRequest => { - const params = bidRequest.params; - const sizes = utils.parseSizesInput(bidRequest.sizes)[0]; - const width = sizes.split('x')[0]; - const height = sizes.split('x')[1]; - const placementId = params.placementId; - const cb = Math.floor(Math.random() * 99999999999); - const referrer = encodeURIComponent(utils.getTopWindowUrl()); - const bidId = bidRequest.bidId; - const payload = { - v: 'hb1', - p: placementId, - w: width, - h: height, - cb: cb, - r: referrer, - uid: bidId, - t: 'i', - d: HOST_NAME, - }; - return { - method: 'POST', - url: ENDPOINT_URL, - data: payload, - } - }); - }, - interpretResponse: function(serverResponse, bidRequest) { - const bidResponses = []; - const response = serverResponse.body; - const crid = response.creativeId || 0; - const width = response.width || 0; - const height = response.height || 0; - const cpm = response.cpm || 0; - if (width !== 0 && height !== 0 && cpm !== 0 && crid !== 0) { - const dealId = response.dealid || ''; - const currency = response.currency || 'USD'; - const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue; - const referrer = utils.getTopWindowUrl(); - const bidResponse = { - requestId: bidRequest.data.uid, - cpm: cpm, - width: response.width, - height: response.height, - creativeId: crid, - dealId: dealId, - currency: currency, - netRevenue: netRevenue, - ttl: config.getConfig('_bidderTimeout'), - referrer: referrer, - ad: response.ad - }; - bidResponses.push(bidResponse); - } - return bidResponses; - } -} -registerBidder(spec); +import * as utils from '../src/utils.js'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +const BIDDER_CODE = 'colombia'; +const ENDPOINT_URL = 'https://ade.clmbtech.com/cde/prebid.htm'; +const HOST_NAME = document.location.protocol + '//' + window.location.host; + +export const spec = { + code: BIDDER_CODE, + aliases: ['clmb'], + supportedMediaTypes: [BANNER], + isBidRequestValid: function(bid) { + return !!(bid.params.placementId); + }, + buildRequests: function(validBidRequests, bidderRequest) { + return validBidRequests.map(bidRequest => { + const params = bidRequest.params; + const sizes = utils.parseSizesInput(bidRequest.sizes)[0]; + const width = sizes.split('x')[0]; + const height = sizes.split('x')[1]; + const placementId = params.placementId; + const cb = Math.floor(Math.random() * 99999999999); + const bidId = bidRequest.bidId; + const referrer = (bidderRequest && bidderRequest.refererInfo) ? bidderRequest.refererInfo.referer : ''; + const payload = { + v: 'hb1', + p: placementId, + w: width, + h: height, + cb: cb, + r: referrer, + uid: bidId, + t: 'i', + d: HOST_NAME, + }; + return { + method: 'POST', + url: ENDPOINT_URL, + data: payload, + } + }); + }, + interpretResponse: function(serverResponse, bidRequest) { + const bidResponses = []; + const response = serverResponse.body; + const crid = response.creativeId || 0; + const width = response.width || 0; + const height = response.height || 0; + let cpm = response.cpm || 0; + if (width == 300 && height == 250) { + cpm = cpm * 0.2; + } + if (width == 320 && height == 50) { + cpm = cpm * 0.55; + } + if (cpm <= 0) { + return bidResponses; + } + if (width !== 0 && height !== 0 && cpm !== 0 && crid !== 0) { + const dealId = response.dealid || ''; + const currency = response.currency || 'USD'; + const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue; + const bidResponse = { + requestId: bidRequest.data.uid, + cpm: cpm, + width: response.width, + height: response.height, + creativeId: crid, + dealId: dealId, + currency: currency, + netRevenue: netRevenue, + ttl: config.getConfig('_bidderTimeout'), + referrer: bidRequest.data.r, + ad: response.ad + }; + bidResponses.push(bidResponse); + } + return bidResponses; + } +} +registerBidder(spec); diff --git a/modules/colombiaBidAdapter.md b/modules/colombiaBidAdapter.md index 2131fcb4c5a..c754e49771d 100644 --- a/modules/colombiaBidAdapter.md +++ b/modules/colombiaBidAdapter.md @@ -10,13 +10,17 @@ Maintainer: colombiaonline@timesinteret.in Connect to COLOMBIA for bids. -THE COLOMBIA adapter requires setup and approval from the COLOMBIA team. Please reach out to your account team or colombiaonline@timesinteret.in for more information. +COLOMBIA adapter requires setup and approval from the COLOMBIA team. Please reach out to your account team or colombiaonline@timesinteret.in for more information. # Test Parameters ``` var adUnits = [{ code: 'test-ad-div', - sizes: [[300, 250]], + mediaTypes: { + banner: { + sizes: [[300, 250],[728,90],[320,50]] + } + }, bids: [{ bidder: 'colombia', params: { diff --git a/modules/colossussspBidAdapter.js b/modules/colossussspBidAdapter.js index 2ad320ede38..baa60a76a0d 100644 --- a/modules/colossussspBidAdapter.js +++ b/modules/colossussspBidAdapter.js @@ -1,10 +1,10 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; -import * as utils from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; const BIDDER_CODE = 'colossusssp'; -const URL = '//colossusssp.com/?c=o&m=multi'; -const URL_SYNC = '//colossusssp.com/?c=o&m=cookie'; +const G_URL = 'https://colossusssp.com/?c=o&m=multi'; +const G_URL_SYNC = 'https://colossusssp.com/?c=o&m=cookie'; function isBidResponseValid(bid) { if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) { @@ -23,6 +23,19 @@ function isBidResponseValid(bid) { } } +function getUserId(eids, id, source, uidExt) { + if (id) { + var uid = { id }; + if (uidExt) { + uid.ext = uidExt; + } + eids.push({ + source, + uids: [ uid ] + }); + } +} + export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO, NATIVE], @@ -42,15 +55,16 @@ export const spec = { * @param {BidRequest[]} validBidRequests A non-empty list of valid bid requests that should be sent to the Server. * @return ServerRequest Info describing the request to the server. */ - buildRequests: (validBidRequests) => { + buildRequests: (validBidRequests, bidderRequest) => { let winTop = window; + let location; try { - window.top.location.toString(); + location = new URL(bidderRequest.refererInfo.referer) winTop = window.top; } catch (e) { + location = winTop.location; utils.logMessage(e); }; - let location = utils.getTopWindowLocation(); let placements = []; let request = { 'deviceWidth': winTop.screen.width, @@ -59,21 +73,45 @@ export const spec = { 'secure': location.protocol === 'https:' ? 1 : 0, 'host': location.host, 'page': location.pathname, - 'placements': placements + 'placements': placements, }; + + if (bidderRequest) { + if (bidderRequest.uspConsent) { + request.ccpa = bidderRequest.uspConsent; + } + if (bidderRequest.gdprConsent) { + request.gdpr_consent = bidderRequest.gdprConsent.consentString || 'ALL' + request.gdpr_require = bidderRequest.gdprConsent.gdprApplies ? 1 : 0 + } + } + for (let i = 0; i < validBidRequests.length; i++) { let bid = validBidRequests[i]; + let traff = bid.params.traffic || BANNER let placement = { placementId: bid.params.placement_id, bidId: bid.bidId, - sizes: bid.sizes, - traffic: bid.params.traffic || BANNER + sizes: bid.mediaTypes[traff].sizes, + traffic: traff, + eids: [] }; + if (bid.schain) { + placement.schain = bid.schain; + } + if (bid.userId) { + getUserId(placement.eids, bid.userId.britepoolid, 'britepool.com'); + getUserId(placement.eids, bid.userId.idl_env, 'identityLink'); + getUserId(placement.eids, bid.userId.id5id, 'id5-sync.com') + getUserId(placement.eids, bid.userId.tdid, 'adserver.org', { + rtiPartner: 'TDID' + }); + } placements.push(placement); } return { method: 'POST', - url: URL, + url: G_URL, data: request }; }, @@ -103,7 +141,7 @@ export const spec = { getUserSyncs: () => { return [{ type: 'image', - url: URL_SYNC + url: G_URL_SYNC }]; } }; diff --git a/modules/colossussspBidAdapter.md b/modules/colossussspBidAdapter.md index 4760002f0db..d95080546c2 100644 --- a/modules/colossussspBidAdapter.md +++ b/modules/colossussspBidAdapter.md @@ -14,7 +14,11 @@ Module that connects to Colossus SSP demand sources ``` var adUnits = [{ code: 'placementid_0', - sizes: [[300, 250]], + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]] + } + }, bids: [{ bidder: 'colossusssp', params: { diff --git a/modules/connectadBidAdapter.js b/modules/connectadBidAdapter.js new file mode 100644 index 00000000000..3dcb8da9838 --- /dev/null +++ b/modules/connectadBidAdapter.js @@ -0,0 +1,299 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js' +import {config} from '../src/config.js'; + +const BIDDER_CODE = 'connectad'; +const BIDDER_CODE_ALIAS = 'connectadrealtime'; +const ENDPOINT_URL = 'https://i.connectad.io/api/v2'; +const SUPPORTED_MEDIA_TYPES = [BANNER]; + +export const spec = { + code: BIDDER_CODE, + aliases: [ BIDDER_CODE_ALIAS ], + supportedMediaTypes: SUPPORTED_MEDIA_TYPES, + + isBidRequestValid: function(bid) { + return !!(bid.params.networkId && bid.params.siteId); + }, + + buildRequests: function(validBidRequests, bidderRequest) { + let digitrust; + + let ret = { + method: 'POST', + url: '', + data: '', + bidRequest: [] + }; + + if (validBidRequests.length < 1) { + return ret; + } + + const data = Object.assign({ + placements: [], + time: Date.now(), + user: {}, + url: (bidderRequest.refererInfo && bidderRequest.refererInfo.referer) ? bidderRequest.refererInfo.referer : window.location.href, + referrer: window.document.referrer, + referrer_info: bidderRequest.refererInfo, + screensize: getScreenSize(), + dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0, + language: navigator.language, + ua: navigator.userAgent + }); + + // coppa compliance + if (config.getConfig('coppa') === true) { + utils.deepSetValue(data, 'user.coppa', 1); + } + + // adding schain object + if (validBidRequests[0].schain) { + utils.deepSetValue(data, 'source.ext.schain', validBidRequests[0].schain); + } + + // Attaching GDPR Consent Params + if (bidderRequest.gdprConsent) { + let gdprApplies; + if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { + gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; + } + utils.deepSetValue(data, 'user.ext.gdpr', gdprApplies); + utils.deepSetValue(data, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + + // CCPA + if (bidderRequest.uspConsent) { + utils.deepSetValue(data, 'user.ext.us_privacy', bidderRequest.uspConsent); + } + + // Digitrust Support + const bidRequestDigitrust = utils.deepAccess(validBidRequests[0], 'userId.digitrustid.data'); + if (bidRequestDigitrust && (!bidRequestDigitrust.privacy || !bidRequestDigitrust.privacy.optout)) { + digitrust = { + id: bidRequestDigitrust.id, + keyv: bidRequestDigitrust.keyv + } + } + + if (digitrust) { + utils.deepSetValue(data, 'user.ext.digitrust', { + id: digitrust.id, + keyv: digitrust.keyv + }) + } + + if (validBidRequests[0].userId && typeof validBidRequests[0].userId === 'object' && (validBidRequests[0].userId.tdid || validBidRequests[0].userId.pubcid || validBidRequests[0].userId.lipb || validBidRequests[0].userId.id5id || validBidRequests[0].userId.parrableid)) { + utils.deepSetValue(data, 'user.ext.eids', []); + + if (validBidRequests[0].userId.tdid) { + data.user.ext.eids.push({ + source: 'adserver.org', + uids: [{ + id: validBidRequests[0].userId.tdid, + ext: { + rtiPartner: 'TDID' + } + }] + }); + } + + if (validBidRequests[0].userId.pubcid) { + data.user.ext.eids.push({ + source: 'pubcommon', + uids: [{ + id: validBidRequests[0].userId.pubcid, + }] + }); + } + + if (validBidRequests[0].userId.id5id) { + data.user.ext.eids.push({ + source: 'id5-sync.com', + uids: [{ + id: validBidRequests[0].userId.id5id, + }] + }); + } + + if (validBidRequests[0].userId.parrableid) { + data.user.ext.eids.push({ + source: 'parrable.com', + uids: [{ + id: validBidRequests[0].userId.parrableid, + }] + }); + } + + if (validBidRequests[0].userId.lipb && validBidRequests[0].userId.lipb.lipbid) { + data.user.ext.eids.push({ + source: 'liveintent.com', + uids: [{ + id: validBidRequests[0].userId.lipb.lipbid + }] + }); + } + } + + validBidRequests.map(bid => { + const placement = Object.assign({ + id: bid.transactionId, + divName: bid.bidId, + sizes: bid.mediaTypes.banner.sizes, + adTypes: getSize(bid.mediaTypes.banner.sizes || bid.sizes) + }, bid.params); + + if (placement.networkId && placement.siteId) { + data.placements.push(placement); + } + }); + + ret.data = JSON.stringify(data); + ret.bidRequest = validBidRequests; + ret.url = ENDPOINT_URL; + + return ret; + }, + + interpretResponse: function(serverResponse, bidRequest, bidderRequest) { + let bid; + let bids; + let bidId; + let bidObj; + let bidResponses = []; + + bids = bidRequest.bidRequest; + + serverResponse = (serverResponse || {}).body; + for (let i = 0; i < bids.length; i++) { + bid = {}; + bidObj = bids[i]; + bidId = bidObj.bidId; + + if (serverResponse) { + const decision = serverResponse.decisions && serverResponse.decisions[bidId]; + const price = decision && decision.pricing && decision.pricing.clearPrice; + + if (decision && price) { + bid.requestId = bidId; + bid.cpm = price; + bid.width = decision.width; + bid.height = decision.height; + bid.dealid = decision.dealid || null; + bid.ad = retrieveAd(decision); + bid.currency = 'USD'; + bid.creativeId = decision.adId; + bid.ttl = 360; + bid.netRevenue = true; + bidResponses.push(bid); + } + } + } + + return bidResponses; + }, + + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { + let syncEndpoint = 'https://cdn.connectad.io/connectmyusers.php?'; + + if (gdprConsent) { + syncEndpoint = utils.tryAppendQueryString(syncEndpoint, 'gdpr', (gdprConsent.gdprApplies ? 1 : 0)); + } + + if (gdprConsent && typeof gdprConsent.consentString === 'string') { + syncEndpoint = utils.tryAppendQueryString(syncEndpoint, 'gdpr_consent', gdprConsent.consentString); + } + + if (uspConsent) { + syncEndpoint = utils.tryAppendQueryString(syncEndpoint, 'us_privacy', uspConsent); + } + + if (config.getConfig('coppa') === true) { + syncEndpoint = utils.tryAppendQueryString(syncEndpoint, 'coppa', 1); + } + + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: syncEndpoint + }]; + } else { + utils.logWarn('Bidder ConnectAd: Please activate iFrame Sync'); + } + } +}; + +const sizeMap = [ + null, + '120x90', + '200x200', + '468x60', + '728x90', + '300x250', + '160x600', + '120x600', + '300x100', + '180x150', + '336x280', + '240x400', + '234x60', + '88x31', + '120x60', + '120x240', + '125x125', + '220x250', + '250x250', + '250x90', + '0x0', + '200x90', + '300x50', + '320x50', + '320x480', + '185x185', + '620x45', + '300x125', + '800x250', + '980x120', + '980x150', + '320x150', + '300x300', + '200x600', + '320x500', + '320x320' +]; + +sizeMap[77] = '970x90'; +sizeMap[123] = '970x250'; +sizeMap[43] = '300x600'; +sizeMap[286] = '970x66'; +sizeMap[3230] = '970x280'; +sizeMap[429] = '486x60'; +sizeMap[374] = '700x500'; +sizeMap[934] = '300x1050'; +sizeMap[1578] = '320x100'; +sizeMap[331] = '320x250'; +sizeMap[3301] = '320x267'; +sizeMap[2730] = '728x250'; + +function getSize(sizes) { + const result = []; + sizes.forEach(function(size) { + const index = sizeMap.indexOf(size[0] + 'x' + size[1]); + if (index >= 0) { + result.push(index); + } + }); + return result; +} + +function retrieveAd(decision) { + return decision.contents && decision.contents[0] && decision.contents[0].body; +} + +function getScreenSize() { + return [window.screen.width, window.screen.height].join('x'); +} + +registerBidder(spec); diff --git a/modules/connectadBidAdapter.md b/modules/connectadBidAdapter.md new file mode 100644 index 00000000000..e63494e1add --- /dev/null +++ b/modules/connectadBidAdapter.md @@ -0,0 +1,46 @@ +# Overview + +``` +Module Name: ConnectAd PreBid Adapter +Module Type: Bidder Adapter +Maintainer: support@connectad.io +``` + +# Description + +ConnectAd bid adapter supports only Banner at present. Video and Mobile will follow Q2/2020 + +# Sample Ad Unit: For Publishers +``` +var adUnits = [ +{ + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]] + } + }, + bids: [{ + bidder: 'connectad', + params: { + siteId: 123456, + networkId: 123456, + bidfloor: 0.20 // Optional: Requested Bidfloor + } + }] +} + +# ## Configuration +ConnectAd recommends the UserSync configuration below otherwise we will not be able to performe user syncs. + +```javascript +pbjs.setConfig({ + userSync: { + filterSettings: { + iframe: { + bidders: ['connectad'], + filter: 'include' + } + } + } +}); \ No newline at end of file diff --git a/modules/consentManagement.js b/modules/consentManagement.js index 1e2a6648145..53e97006bd1 100644 --- a/modules/consentManagement.js +++ b/modules/consentManagement.js @@ -4,11 +4,11 @@ * and make it available for any GDPR supported adapters to read/pass this information to * their system. */ -import * as utils from '../src/utils'; -import { config } from '../src/config'; -import { gdprDataHandler } from '../src/adapterManager'; -import includes from 'core-js/library/fn/array/includes'; -import strIncludes from 'core-js/library/fn/string/includes'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { gdprDataHandler } from '../src/adapterManager.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import strIncludes from 'core-js-pure/features/string/includes.js'; const DEFAULT_CMP = 'iab'; const DEFAULT_CONSENT_TIMEOUT = 10000; @@ -17,8 +17,10 @@ const DEFAULT_ALLOW_AUCTION_WO_CONSENT = true; export let userCMP; export let consentTimeout; export let allowAuction; +export let gdprScope; export let staticConsentData; +let cmpVersion = 0; let consentData; let addedConsentHook = false; @@ -47,11 +49,70 @@ function lookupStaticConsentData(cmpSuccess, cmpError, hookConfig) { * @param {object} hookConfig contains module related variables (see comment in requestBidsHook function) */ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { - function handleCmpResponseCallbacks() { + function findCMP() { + let f = window; + let cmpFrame; + let cmpFunction; + while (!cmpFrame) { + try { + if (typeof f.__tcfapi === 'function' || typeof f.__cmp === 'function') { + if (typeof f.__tcfapi === 'function') { + cmpVersion = 2; + cmpFunction = f.__tcfapi; + } else { + cmpVersion = 1; + cmpFunction = f.__cmp; + } + cmpFrame = f; + break; + } + } catch (e) { } + + // need separate try/catch blocks due to the exception errors thrown when trying to check for a frame that doesn't exist in 3rd party env + try { + if (f.frames['__tcfapiLocator']) { + cmpVersion = 2; + cmpFrame = f; + break; + } + } catch (e) { } + + try { + if (f.frames['__cmpLocator']) { + cmpVersion = 1; + cmpFrame = f; + break; + } + } catch (e) { } + + if (f === window.top) break; + f = f.parent; + } + return { + cmpFrame, + cmpFunction + }; + } + + function v2CmpResponseCallback(tcfData, success) { + utils.logInfo('Received a response from CMP', tcfData); + if (success) { + if (tcfData.eventStatus === 'tcloaded' || tcfData.eventStatus === 'useractioncomplete') { + cmpSuccess(tcfData, hookConfig); + } else if (tcfData.eventStatus === 'cmpuishown' && tcfData.tcString && tcfData.purposeOneTreatment === true) { + cmpSuccess(tcfData, hookConfig); + } + } else { + cmpError('CMP unable to register callback function. Please check CMP setup.', hookConfig); + } + } + + function handleV1CmpResponseCallbacks() { const cmpResponse = {}; function afterEach() { if (cmpResponse.getConsentData && cmpResponse.getVendorConsents) { + utils.logInfo('Received all requested responses from CMP', cmpResponse); cmpSuccess(cmpResponse, hookConfig); } } @@ -68,10 +129,13 @@ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { } } - let callbackHandler = handleCmpResponseCallbacks(); + let v1CallbackHandler = handleV1CmpResponseCallbacks(); let cmpCallbacks = {}; - let cmpFunction; + let { cmpFrame, cmpFunction } = findCMP(); + if (!cmpFrame) { + return cmpError('CMP not found.', hookConfig); + } // to collect the consent information from the user, we perform two calls to the CMP in parallel: // first to collect the user's consent choices represented in an encoded string (via getConsentData) // second to collect the user's full unparsed consent information (via getVendorConsents) @@ -81,34 +145,28 @@ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { // check to see if prebid is in a safeframe (with CMP support) // else assume prebid may be inside an iframe and use the IAB CMP locator code to see if CMP's located in a higher parent window. this works in cross domain iframes // if the CMP is not found, the iframe function will call the cmpError exit callback to abort the rest of the CMP workflow - try { - cmpFunction = window.__cmp || utils.getWindowTop().__cmp; - } catch (e) { } if (utils.isFn(cmpFunction)) { - cmpFunction('getConsentData', null, callbackHandler.consentDataCallback); - cmpFunction('getVendorConsents', null, callbackHandler.vendorConsentsCallback); - } else if (inASafeFrame() && typeof window.$sf.ext.cmp === 'function') { - callCmpWhileInSafeFrame('getConsentData', callbackHandler.consentDataCallback); - callCmpWhileInSafeFrame('getVendorConsents', callbackHandler.vendorConsentsCallback); - } else { - // find the CMP frame - let f = window; - let cmpFrame; - while (!cmpFrame) { - try { - if (f.frames['__cmpLocator']) cmpFrame = f; - } catch (e) { } - if (f === window.top) break; - f = f.parent; + utils.logInfo('Detected CMP API is directly accessible, calling it now...'); + if (cmpVersion === 1) { + cmpFunction('getConsentData', null, v1CallbackHandler.consentDataCallback); + cmpFunction('getVendorConsents', null, v1CallbackHandler.vendorConsentsCallback); + } else if (cmpVersion === 2) { + cmpFunction('addEventListener', cmpVersion, v2CmpResponseCallback); } - - if (!cmpFrame) { - return cmpError('CMP not found.', hookConfig); + } else if (cmpVersion === 1 && inASafeFrame() && typeof window.$sf.ext.cmp === 'function') { + // this safeframe workflow is only supported with TCF v1 spec; the v2 recommends to use the iframe postMessage route instead (even if you are in a safeframe). + utils.logInfo('Detected Prebid.js is encased in a SafeFrame and CMP is registered, calling it now...'); + callCmpWhileInSafeFrame('getConsentData', v1CallbackHandler.consentDataCallback); + callCmpWhileInSafeFrame('getVendorConsents', v1CallbackHandler.vendorConsentsCallback); + } else { + utils.logInfo('Detected CMP is outside the current iframe where Prebid.js is located, calling it now...'); + if (cmpVersion === 1) { + callCmpWhileInIframe('getConsentData', cmpFrame, v1CallbackHandler.consentDataCallback); + callCmpWhileInIframe('getVendorConsents', cmpFrame, v1CallbackHandler.vendorConsentsCallback); + } else if (cmpVersion === 2) { + callCmpWhileInIframe('addEventListener', cmpFrame, v2CmpResponseCallback); } - - callCmpWhileInIframe('getConsentData', cmpFrame, callbackHandler.consentDataCallback); - callCmpWhileInIframe('getVendorConsents', cmpFrame, callbackHandler.vendorConsentsCallback); } function inASafeFrame() { @@ -138,17 +196,22 @@ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { } function callCmpWhileInIframe(commandName, cmpFrame, moduleCallback) { + let apiName = (cmpVersion === 2) ? '__tcfapi' : '__cmp'; + /* Setup up a __cmp function to do the postMessage and stash the callback. This function behaves (from the caller's perspective identicially to the in-frame __cmp call */ - window.__cmp = function (cmd, arg, callback) { + window[apiName] = function (cmd, arg, callback) { let callId = Math.random() + ''; + let callName = `${apiName}Call`; let msg = { - __cmpCall: { + [callName]: { command: cmd, parameter: arg, callId: callId } }; + if (cmpVersion !== 1) msg[callName].version = cmpVersion; + cmpCallbacks[callId] = callback; cmpFrame.postMessage(msg, '*'); } @@ -157,28 +220,19 @@ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { window.addEventListener('message', readPostMessageResponse, false); // call CMP - window.__cmp(commandName, null, cmpIframeCallback); + window[apiName](commandName, null, moduleCallback); function readPostMessageResponse(event) { - let json = (typeof event.data === 'string' && strIncludes(event.data, 'cmpReturn')) ? JSON.parse(event.data) : event.data; - if (json.__cmpReturn && json.__cmpReturn.callId) { - let i = json.__cmpReturn; + let cmpDataPkgName = `${apiName}Return`; + let json = (typeof event.data === 'string' && strIncludes(event.data, cmpDataPkgName)) ? JSON.parse(event.data) : event.data; + if (json[cmpDataPkgName] && json[cmpDataPkgName].callId) { + let payload = json[cmpDataPkgName]; // TODO - clean up this logic (move listeners?); we have duplicate messages responses because 2 eventlisteners are active from the 2 cmp requests running in parallel - if (typeof cmpCallbacks[i.callId] !== 'undefined') { - cmpCallbacks[i.callId](i.returnValue, i.success); - delete cmpCallbacks[i.callId]; + if (typeof cmpCallbacks[payload.callId] !== 'undefined') { + cmpCallbacks[payload.callId](payload.returnValue, payload.success); } } } - - function removePostMessageListener() { - window.removeEventListener('message', readPostMessageResponse, false); - } - - function cmpIframeCallback(consentObject) { - removePostMessageListener(); - moduleCallback(consentObject); - } } } @@ -204,6 +258,7 @@ export function requestBidsHook(fn, reqBidsConfigObj) { // in case we already have consent (eg during bid refresh) if (consentData) { + utils.logInfo('User consent information already known. Pulling internally stored information...'); return exitModule(null, hookConfig); } @@ -232,22 +287,51 @@ export function requestBidsHook(fn, reqBidsConfigObj) { * @param {object} hookConfig contains module related variables (see comment in requestBidsHook function) */ function processCmpData(consentObject, hookConfig) { - let gdprApplies = consentObject && consentObject.getConsentData && consentObject.getConsentData.gdprApplies; - if ( - (typeof gdprApplies !== 'boolean') || - (gdprApplies === true && - !(utils.isStr(consentObject.getConsentData.consentData) && - utils.isPlainObject(consentObject.getVendorConsents) && - Object.keys(consentObject.getVendorConsents).length > 1 + function checkV1Data(consentObject) { + let gdprApplies = consentObject && consentObject.getConsentData && consentObject.getConsentData.gdprApplies; + return !!( + (typeof gdprApplies !== 'boolean') || + (gdprApplies === true && + !(utils.isStr(consentObject.getConsentData.consentData) && + utils.isPlainObject(consentObject.getVendorConsents) && + Object.keys(consentObject.getVendorConsents).length > 1 + ) ) - ) - ) { - cmpFailed(`CMP returned unexpected value during lookup process.`, hookConfig, consentObject); - } else { - clearTimeout(hookConfig.timer); - storeConsentData(consentObject); + ); + } - exitModule(null, hookConfig); + function checkV2Data() { + // if CMP does not respond with a gdprApplies boolean, use defaultGdprScope (gdprScope) + let gdprApplies = consentObject && typeof consentObject.gdprApplies === 'boolean' ? consentObject.gdprApplies : gdprScope; + let tcString = consentObject && consentObject.tcString; + return !!( + (typeof gdprApplies !== 'boolean') || + (gdprApplies === true && !utils.isStr(tcString)) + ); + } + + // do extra things for static config + if (userCMP === 'static') { + cmpVersion = (consentObject.getConsentData) ? 1 : (consentObject.getTCData) ? 2 : 0; + // remove extra layer in static v2 data object so it matches normal v2 CMP object for processing step + if (cmpVersion === 2) { + consentObject = consentObject.getTCData; + } + } + + // determine which set of checks to run based on cmpVersion + let checkFn = (cmpVersion === 1) ? checkV1Data : (cmpVersion === 2) ? checkV2Data : null; + + if (utils.isFn(checkFn)) { + if (checkFn(consentObject)) { + cmpFailed(`CMP returned unexpected value during lookup process.`, hookConfig, consentObject); + } else { + clearTimeout(hookConfig.timer); + storeConsentData(consentObject); + exitModule(null, hookConfig); + } + } else { + cmpFailed('Unable to derive CMP version to process data. Consent object does not conform to TCF v1 or v2 specs.', hookConfig, consentObject); } } @@ -279,17 +363,26 @@ function cmpFailed(errMsg, hookConfig, extraArgs) { * @param {object} cmpConsentObject required; an object representing user's consent choices (can be undefined in certain use-cases for this function only) */ function storeConsentData(cmpConsentObject) { - consentData = { - consentString: (cmpConsentObject) ? cmpConsentObject.getConsentData.consentData : undefined, - vendorData: (cmpConsentObject) ? cmpConsentObject.getVendorConsents : undefined, - gdprApplies: (cmpConsentObject) ? cmpConsentObject.getConsentData.gdprApplies : undefined - }; + if (cmpVersion === 1) { + consentData = { + consentString: (cmpConsentObject) ? cmpConsentObject.getConsentData.consentData : undefined, + vendorData: (cmpConsentObject) ? cmpConsentObject.getVendorConsents : undefined, + gdprApplies: (cmpConsentObject) ? cmpConsentObject.getConsentData.gdprApplies : gdprScope + }; + } else { + consentData = { + consentString: (cmpConsentObject) ? cmpConsentObject.tcString : undefined, + vendorData: (cmpConsentObject) || undefined, + gdprApplies: cmpConsentObject && typeof cmpConsentObject.gdprApplies === 'boolean' ? cmpConsentObject.gdprApplies : gdprScope + }; + } + consentData.apiVersion = cmpVersion; gdprDataHandler.setConsentData(consentData); } /** * This function handles the exit logic for the module. - * There are several paths in the module's logic to call this function and we only allow 1 of the 3 potential exits to happen before suppressing others. + * While there are several paths in the module's logic to call this function, we only allow 1 of the 3 potential exits to happen before suppressing others. * * We prevent multiple exits to avoid conflicting messages in the console depending on certain scenarios. * One scenario could be auction was canceled due to timeout with CMP being reached. @@ -335,14 +428,23 @@ function exitModule(errMsg, hookConfig, extraArgs) { */ export function resetConsentData() { consentData = undefined; + userCMP = undefined; + cmpVersion = 0; gdprDataHandler.setConsentData(null); } /** * A configuration function that initializes some module variables, as well as add a hook into the requestBids function - * @param {object} config required; consentManagement module config settings; cmp (string), timeout (int), allowAuctionWithoutConsent (boolean) + * @param {{cmp:string, timeout:number, allowAuctionWithoutConsent:boolean, defaultGdprScope:boolean}} config required; consentManagement module config settings; cmp (string), timeout (int), allowAuctionWithoutConsent (boolean) */ export function setConsentConfig(config) { + // if `config.gdpr` or `config.usp` exist, assume new config format. + // else for backward compatability, just use `config` + config = config.gdpr || config.usp ? config.gdpr : config; + if (!config || typeof config !== 'object') { + utils.logWarn('consentManagement config not defined, exiting consent manager'); + return; + } if (utils.isStr(config.cmpApi)) { userCMP = config.cmpApi; } else { @@ -364,6 +466,9 @@ export function setConsentConfig(config) { utils.logInfo(`consentManagement config did not specify allowAuctionWithoutConsent. Using system default setting (${DEFAULT_ALLOW_AUCTION_WO_CONSENT}).`); } + // if true, then gdprApplies should be set to true + gdprScope = config.defaultGdprScope === true; + utils.logInfo('consentManagement module has been activated...'); if (userCMP === 'static') { diff --git a/modules/consentManagementUsp.js b/modules/consentManagementUsp.js new file mode 100644 index 00000000000..1a5879a40ff --- /dev/null +++ b/modules/consentManagementUsp.js @@ -0,0 +1,311 @@ +/** + * This module adds USPAPI (CCPA) consentManagement support to prebid.js. It + * interacts with supported USP Consent APIs to grab the user's consent + * information and make it available for any USP (CCPA) supported adapters to + * read/pass this information to their system. + */ +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { uspDataHandler } from '../src/adapterManager.js'; + +const DEFAULT_CONSENT_API = 'iab'; +const DEFAULT_CONSENT_TIMEOUT = 50; +const USPAPI_VERSION = 1; + +export let consentAPI; +export let consentTimeout; +export let staticConsentData; + +let consentData; +let addedConsentHook = false; + +// consent APIs +const uspCallMap = { + 'iab': lookupUspConsent, + 'static': lookupStaticConsentData +}; + +/** + * This function reads the consent string from the config to obtain the consent information of the user. + * @param {function(string)} cmpSuccess acts as a success callback when the value is read from config; pass along consentObject (string) from CMP + * @param {function(string)} cmpError acts as an error callback while interacting with the config string; pass along an error message (string) + * @param {object} hookConfig contains module related variables (see comment in requestBidsHook function) + */ +function lookupStaticConsentData(cmpSuccess, cmpError, hookConfig) { + cmpSuccess(staticConsentData, hookConfig); +} + +/** + * This function handles interacting with an USP compliant consent manager to obtain the consent information of the user. + * Given the async nature of the USP's API, we pass in acting success/error callback functions to exit this function + * based on the appropriate result. + * @param {function(string)} uspSuccess acts as a success callback when USPAPI returns a value; pass along consentObject (string) from USPAPI + * @param {function(string)} uspError acts as an error callback while interacting with USPAPI; pass along an error message (string) + * @param {object} hookConfig contains module related variables (see comment in requestBidsHook function) + */ +function lookupUspConsent(uspSuccess, uspError, hookConfig) { + function handleUspApiResponseCallbacks() { + const uspResponse = {}; + + function afterEach() { + if (uspResponse.usPrivacy) { + uspSuccess(uspResponse, hookConfig); + } else { + uspError('Unable to get USP consent string.', hookConfig); + } + } + + return { + consentDataCallback: (consentResponse, success) => { + if (success && consentResponse.uspString) { + uspResponse.usPrivacy = consentResponse.uspString; + } + afterEach(); + } + }; + } + + let callbackHandler = handleUspApiResponseCallbacks(); + let uspapiCallbacks = {}; + + // to collect the consent information from the user, we perform a call to USPAPI + // to collect the user's consent choices represented as a string (via getUSPData) + + // the following code also determines where the USPAPI is located and uses the proper workflow to communicate with it: + // - use the USPAPI locator code to see if USP's located in the current window or an ancestor window. This works in friendly or cross domain iframes + // - if USPAPI is not found, the iframe function will call the uspError exit callback to abort the rest of the USPAPI workflow + // - try to call the __uspapi() function directly, otherwise use the postMessage() api + // find the CMP frame/window + + try { + // try to call __uspapi directly + window.__uspapi('getUSPData', USPAPI_VERSION, callbackHandler.consentDataCallback); + } catch (e) { + // must not have been accessible, try using postMessage() api + let f = window; + let uspapiFrame; + while (!uspapiFrame) { + try { + if (f.frames['__uspapiLocator']) uspapiFrame = f; + } catch (e) { } + if (f === window.top) break; + f = f.parent; + } + + if (!uspapiFrame) { + return uspError('USP CMP not found.', hookConfig); + } + callUspApiWhileInIframe('getUSPData', uspapiFrame, callbackHandler.consentDataCallback); + } + + function callUspApiWhileInIframe(commandName, uspapiFrame, moduleCallback) { + /* Setup up a __uspapi function to do the postMessage and stash the callback. + This function behaves, from the caller's perspective, identicially to the in-frame __uspapi call (although it is not synchronous) */ + window.__uspapi = function (cmd, ver, callback) { + let callId = Math.random() + ''; + let msg = { + __uspapiCall: { + command: cmd, + version: ver, + callId: callId + } + }; + + uspapiCallbacks[callId] = callback; + uspapiFrame.postMessage(msg, '*'); + } + + /** when we get the return message, call the stashed callback */ + window.addEventListener('message', readPostMessageResponse, false); + + // call uspapi + window.__uspapi(commandName, USPAPI_VERSION, uspapiCallback); + + function readPostMessageResponse(event) { + const res = event && event.data && event.data.__uspapiReturn; + if (res && res.callId) { + if (typeof uspapiCallbacks[res.callId] !== 'undefined') { + uspapiCallbacks[res.callId](res.returnValue, res.success); + delete uspapiCallbacks[res.callId]; + } + } + } + + function uspapiCallback(consentObject, success) { + window.removeEventListener('message', readPostMessageResponse, false); + moduleCallback(consentObject, success); + } + } +} + +/** + * If consentManagementUSP module is enabled (ie included in setConfig), this hook function will attempt to fetch the + * user's encoded consent string from the supported USPAPI. Once obtained, the module will store this + * data as part of a uspConsent object which gets transferred to adapterManager's uspDataHandler object. + * This information is later added into the bidRequest object for any supported adapters to read/pass along to their system. + * @param {object} reqBidsConfigObj required; This is the same param that's used in pbjs.requestBids. + * @param {function} fn required; The next function in the chain, used by hook.js + */ +export function requestBidsHook(fn, reqBidsConfigObj) { + // preserves all module related variables for the current auction instance (used primiarily for concurrent auctions) + const hookConfig = { + context: this, + args: [reqBidsConfigObj], + nextFn: fn, + adUnits: reqBidsConfigObj.adUnits || $$PREBID_GLOBAL$$.adUnits, + bidsBackHandler: reqBidsConfigObj.bidsBackHandler, + haveExited: false, + timer: null + }; + + // in case we already have consent (eg during bid refresh) + if (consentData) { + return exitModule(null, hookConfig); + } + + if (!uspCallMap[consentAPI]) { + utils.logWarn(`USP framework (${consentAPI}) is not a supported framework. Aborting consentManagement module and resuming auction.`); + return hookConfig.nextFn.apply(hookConfig.context, hookConfig.args); + } + + uspCallMap[consentAPI].call(this, processUspData, uspapiFailed, hookConfig); + + // only let this code run if module is still active (ie if the callbacks used by USPs haven't already finished) + if (!hookConfig.haveExited) { + if (consentTimeout === 0) { + processUspData(undefined, hookConfig); + } else { + hookConfig.timer = setTimeout(uspapiTimeout.bind(null, hookConfig), consentTimeout); + } + } +} + +/** + * This function checks the consent data provided by USPAPI to ensure it's in an expected state. + * If it's bad, we exit the module depending on config settings. + * If it's good, then we store the value and exits the module. + * @param {object} consentObject required; object returned by USPAPI that contains user's consent choices + * @param {object} hookConfig contains module related variables (see comment in requestBidsHook function) + */ +function processUspData(consentObject, hookConfig) { + const valid = !!(consentObject && consentObject.usPrivacy); + if (!valid) { + uspapiFailed(`USPAPI returned unexpected value during lookup process.`, hookConfig, consentObject); + return; + } + + clearTimeout(hookConfig.timer); + storeUspConsentData(consentObject); + exitModule(null, hookConfig); +} + +/** + * General timeout callback when interacting with USPAPI takes too long. + */ +function uspapiTimeout(hookConfig) { + uspapiFailed('USPAPI workflow exceeded timeout threshold.', hookConfig); +} + +/** + * This function contains the controlled steps to perform when there's a problem with USPAPI. + * @param {string} errMsg required; should be a short descriptive message for why the failure/issue happened. + * @param {object} hookConfig contains module related variables (see comment in requestBidsHook function) + * @param {object} extraArgs contains additional data that's passed along in the error/warning messages for easier debugging +*/ +function uspapiFailed(errMsg, hookConfig, extraArgs) { + clearTimeout(hookConfig.timer); + + exitModule(errMsg, hookConfig, extraArgs); +} + +/** + * Stores USP data locally in module and then invokes uspDataHandler.setConsentData() to make information available in adaptermanger.js for later in the auction + * @param {object} cmpConsentObject required; an object representing user's consent choices (can be undefined in certain use-cases for this function only) + */ +function storeUspConsentData(consentObject) { + if (consentObject && consentObject.usPrivacy) { + consentData = consentObject.usPrivacy; + uspDataHandler.setConsentData(consentData); + } +} + +/** + * This function handles the exit logic for the module. + * There are a couple paths in the module's logic to call this function and we only allow 1 of the 2 potential exits to happen before suppressing others. + * + * We prevent multiple exits to avoid conflicting messages in the console depending on certain scenarios. + * One scenario could be auction was canceled due to timeout with USPAPI being reached. + * While the timeout is the accepted exit and runs first, the USP's callback still tries to process the user's data (which normally leads to a good exit). + * In this case, the good exit will be suppressed since we already decided to cancel the auction. + * + * Three exit paths are: + * 1. good exit where auction runs (USPAPI data is processed normally). + * 2. bad exit but auction still continues (warning message is logged, USPAPI data is undefined and still passed along). + * @param {string} errMsg optional; only to be used when there was a 'bad' exit. String is a descriptive message for the failure/issue encountered. + * @param {object} hookConfig contains module related variables (see comment in requestBidsHook function) + * @param {object} extraArgs contains additional data that's passed along in the error/warning messages for easier debugging + */ +function exitModule(errMsg, hookConfig, extraArgs) { + if (hookConfig.haveExited === false) { + hookConfig.haveExited = true; + + let context = hookConfig.context; + let args = hookConfig.args; + let nextFn = hookConfig.nextFn; + + if (errMsg) { + utils.logWarn(errMsg + ' Resuming auction without consent data as per consentManagement config.', extraArgs); + } + nextFn.apply(context, args); + } +} + +/** + * Simply resets the module's consentData variable back to undefined, mainly for testing purposes + */ +export function resetConsentData() { + consentData = undefined; + consentAPI = undefined; + uspDataHandler.setConsentData(null); +} + +/** + * A configuration function that initializes some module variables, as well as add a hook into the requestBids function + * @param {object} config required; consentManagementUSP module config settings; usp (string), timeout (int), allowAuctionWithoutConsent (boolean) + */ +export function setConsentConfig(config) { + config = config.usp; + if (!config || typeof config !== 'object') { + utils.logWarn('consentManagement.usp config not defined, exiting usp consent manager'); + return; + } + if (utils.isStr(config.cmpApi)) { + consentAPI = config.cmpApi; + } else { + consentAPI = DEFAULT_CONSENT_API; + utils.logInfo(`consentManagement.usp config did not specify cmpApi. Using system default setting (${DEFAULT_CONSENT_API}).`); + } + + if (utils.isNumber(config.timeout)) { + consentTimeout = config.timeout; + } else { + consentTimeout = DEFAULT_CONSENT_TIMEOUT; + utils.logInfo(`consentManagement.usp config did not specify timeout. Using system default setting (${DEFAULT_CONSENT_TIMEOUT}).`); + } + + utils.logInfo('USPAPI consentManagement module has been activated...'); + + if (consentAPI === 'static') { + if (utils.isPlainObject(config.consentData) && utils.isPlainObject(config.consentData.getUSPData)) { + if (config.consentData.getUSPData.uspString) staticConsentData = { usPrivacy: config.consentData.getUSPData.uspString }; + consentTimeout = 0; + } else { + utils.logError(`consentManagement config with cmpApi: 'static' did not specify consentData. No consents will be available to adapters.`); + } + } + if (!addedConsentHook) { + $$PREBID_GLOBAL$$.requestBids.before(requestBidsHook, 50); + } + addedConsentHook = true; +} +config.getConfig('consentManagement', config => setConsentConfig(config.consentManagement)); diff --git a/modules/consumableBidAdapter.js b/modules/consumableBidAdapter.js index d462acaee59..8eb56f7d0c2 100644 --- a/modules/consumableBidAdapter.js +++ b/modules/consumableBidAdapter.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'consumable'; @@ -47,7 +47,7 @@ export const spec = { const data = Object.assign({ placements: [], time: Date.now(), - url: utils.getTopWindowUrl(), + url: bidderRequest.refererInfo.referer, referrer: document.referrer, source: [{ 'name': 'prebidjs', @@ -62,10 +62,15 @@ export const spec = { }; } + if (bidderRequest && bidderRequest.uspConsent) { + data.ccpa = bidderRequest.uspConsent; + } + validBidRequests.map(bid => { + const sizes = (bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes) || bid.sizes || []; const placement = Object.assign({ divName: bid.bidId, - adTypes: bid.adTypes || getSize(bid.sizes) + adTypes: bid.adTypes || getSize(sizes) }, bid.params); if (placement.networkId && placement.siteId && placement.unitId && placement.unitName) { @@ -75,6 +80,7 @@ export const spec = { ret.data = JSON.stringify(data); ret.bidRequest = validBidRequests; + ret.bidderRequest = bidderRequest; ret.url = BASE_URI; return ret; @@ -117,7 +123,7 @@ export const spec = { bid.creativeId = decision.adId; bid.ttl = 30; bid.netRevenue = true; - bid.referrer = utils.getTopWindowUrl(); + bid.referrer = bidRequest.bidderRequest.refererInfo.referer; bidResponses.push(bid); } @@ -131,7 +137,7 @@ export const spec = { if (syncOptions.iframeEnabled) { return [{ type: 'iframe', - url: '//sync.serverbid.com/ss/' + siteId + '.html' + url: 'https://sync.serverbid.com/ss/' + siteId + '.html' }]; } diff --git a/modules/contentigniteBidAdapter.js b/modules/contentigniteBidAdapter.js deleted file mode 100644 index 2e3092114f6..00000000000 --- a/modules/contentigniteBidAdapter.js +++ /dev/null @@ -1,115 +0,0 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { config } from '../src/config'; -import * as utils from '../src/utils'; - -const BIDDER_CODE = 'contentignite'; - -export const spec = { - code: BIDDER_CODE, - pageID: Math.floor(Math.random() * 10e6), - - isBidRequestValid: (bid) => { - return !!(bid.params.accountID && bid.params.zoneID); - }, - - buildRequests: (validBidRequests) => { - let i; - let zoneID; - let bidRequest; - let accountID; - let keyword; - let requestURI; - const serverRequests = []; - const zoneCounters = {}; - - for (i = 0; i < validBidRequests.length; i++) { - bidRequest = validBidRequests[i]; - zoneID = utils.getBidIdParameter('zoneID', bidRequest.params); - accountID = utils.getBidIdParameter('accountID', bidRequest.params); - keyword = utils.getBidIdParameter('keyword', bidRequest.params); - - if (!(zoneID in zoneCounters)) { - zoneCounters[zoneID] = 0; - } - - requestURI = - location.protocol + '//serve.connectignite.com/adserve/;type=hbr;'; - requestURI += `ID=${encodeURIComponent(accountID)};`; - requestURI += `setID=${encodeURIComponent(zoneID)};`; - requestURI += `pid=${spec.pageID};`; - requestURI += `place=${encodeURIComponent(zoneCounters[zoneID])};`; - - // append the keyword for targeting if one was passed in - if (keyword !== '') { - requestURI += `kw=${encodeURIComponent(keyword)};`; - } - - zoneCounters[zoneID]++; - serverRequests.push({ - method: 'GET', - url: requestURI, - data: {}, - bidRequest: bidRequest - }); - } - return serverRequests; - }, - - // tslint:disable-next-line:cyclomatic-complexity - interpretResponse: (serverResponse, bidRequest) => { - const bidObj = bidRequest.bidRequest; - const bidResponses = []; - const bidResponse = {}; - let isCorrectSize = false; - let isCorrectCPM = true; - let cpm; - let minCPM; - let maxCPM; - let width; - let height; - - serverResponse = serverResponse.body; - if (serverResponse && serverResponse.status === 'SUCCESS' && bidObj) { - cpm = serverResponse.cpm; - minCPM = utils.getBidIdParameter('minCPM', bidObj.params); - maxCPM = utils.getBidIdParameter('maxCPM', bidObj.params); - width = parseInt(serverResponse.width); - height = parseInt(serverResponse.height); - - // Ensure response CPM is within the given bounds - if (minCPM !== '' && cpm < parseFloat(minCPM)) { - isCorrectCPM = false; - utils.logWarn('ContentIgnite: CPM did not meet minCPM requirements.'); - } else if (maxCPM !== '' && cpm > parseFloat(maxCPM)) { - isCorrectCPM = false; - utils.logWarn('ContentIgnite: CPM did not meet maxCPM requirements.'); - } - - // Ensure that response ad matches one of the placement sizes. - utils._each(bidObj.sizes, (size) => { - if (width === size[0] && height === size[1]) { - isCorrectSize = true; - } else { - utils.logWarn( - 'ContentIgnite: Returned ad is of a different size to that requested.' - ); - } - }); - if (isCorrectCPM && isCorrectSize) { - bidResponse.requestId = bidObj.bidId; - bidResponse.creativeId = serverResponse.placement_id; - bidResponse.cpm = cpm; - bidResponse.width = width; - bidResponse.height = height; - bidResponse.ad = serverResponse.ad_code; - bidResponse.currency = 'USD'; - bidResponse.netRevenue = true; - bidResponse.ttl = config.getConfig('_bidderTimeout'); - bidResponse.referrer = utils.getTopWindowUrl(); - bidResponses.push(bidResponse); - } - } - return bidResponses; - } -}; -registerBidder(spec); diff --git a/modules/convergeBidAdapter.js b/modules/convergeBidAdapter.js new file mode 100644 index 00000000000..bea3b6cb1ab --- /dev/null +++ b/modules/convergeBidAdapter.js @@ -0,0 +1,313 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'converge'; +const ENDPOINT_URL = 'https://tech.convergd.com/hb'; +const TIME_TO_LIVE = 360; +const SYNC_URL = 'https://tech.convergd.com/push_sync'; +const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; + +let hasSynced = false; + +const LOG_ERROR_MESS = { + noAuid: 'Bid from response has no auid parameter - ', + noAdm: 'Bid from response has no adm parameter - ', + noBid: 'Array of bid objects is empty', + noPlacementCode: "Can't find in requested bids the bid with auid - ", + emptyUids: 'Uids should be not empty', + emptySeatbid: 'Seatbid array from response has empty item', + emptyResponse: 'Response is empty', + hasEmptySeatbidArray: 'Response has empty seatbid array', + hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' +}; +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [ BANNER, VIDEO ], + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bid) { + return !!bid.params.uid; + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests - an array of bids + * @param {bidderRequest} bidderRequest - bidder request object + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests, bidderRequest) { + const auids = []; + const bidsMap = {}; + const slotsMapByUid = {}; + const sizeMap = {}; + const bids = validBidRequests || []; + let priceType = 'net'; + let pageKeywords; + let reqId; + + bids.forEach(bid => { + if (bid.params.priceType === 'gross') { + priceType = 'gross'; + } + reqId = bid.bidderRequestId; + const {params: {uid}, adUnitCode} = bid; + auids.push(uid); + const sizesId = utils.parseSizesInput(bid.sizes); + + if (!pageKeywords && !utils.isEmpty(bid.params.keywords)) { + const keywords = utils.transformBidderParamKeywords(bid.params.keywords); + + if (keywords.length > 0) { + keywords.forEach(deleteValues); + } + pageKeywords = keywords; + } + + if (!slotsMapByUid[uid]) { + slotsMapByUid[uid] = {}; + } + const slotsMap = slotsMapByUid[uid]; + if (!slotsMap[adUnitCode]) { + slotsMap[adUnitCode] = {adUnitCode, bids: [bid], parents: []}; + } else { + slotsMap[adUnitCode].bids.push(bid); + } + const slot = slotsMap[adUnitCode]; + + sizesId.forEach((sizeId) => { + sizeMap[sizeId] = true; + if (!bidsMap[uid]) { + bidsMap[uid] = {}; + } + + if (!bidsMap[uid][sizeId]) { + bidsMap[uid][sizeId] = [slot]; + } else { + bidsMap[uid][sizeId].push(slot); + } + slot.parents.push({parent: bidsMap[uid], key: sizeId, uid}); + }); + }); + + const payload = { + pt: priceType, + auids: auids.join(','), + sizes: utils.getKeys(sizeMap).join(','), + r: reqId, + wrapperType: 'Prebid_js', + wrapperVersion: '$prebid.version$' + }; + + if (pageKeywords) { + payload.keywords = JSON.stringify(pageKeywords); + } + + if (bidderRequest) { + if (bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { + payload.u = bidderRequest.refererInfo.referer; + } + if (bidderRequest.timeout) { + payload.wtimeout = bidderRequest.timeout; + } + if (bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.consentString) { + payload.gdpr_consent = bidderRequest.gdprConsent.consentString; + } + payload.gdpr_applies = + (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') + ? Number(bidderRequest.gdprConsent.gdprApplies) : 1; + } + if (bidderRequest.uspConsent) { + payload.us_privacy = bidderRequest.uspConsent; + } + } + + return { + method: 'GET', + url: ENDPOINT_URL, + data: utils.parseQueryStringParameters(payload).replace(/\&$/, ''), + bidsMap: bidsMap, + }; + }, + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @param {*} bidRequest + * @param {Renderer} RendererConst + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse, bidRequest, RendererConst = Renderer) { + serverResponse = serverResponse && serverResponse.body; + const bidResponses = []; + const bidsMap = bidRequest.bidsMap; + const priceType = bidRequest.data.pt; + + let errorMessage; + + if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse; + else if (serverResponse.seatbid && !serverResponse.seatbid.length) { + errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; + } + + if (!errorMessage && serverResponse.seatbid) { + serverResponse.seatbid.forEach(respItem => { + _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses, RendererConst); + }); + } + if (errorMessage) utils.logError(errorMessage); + return bidResponses; + }, + getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { + if (!hasSynced && syncOptions.pixelEnabled) { + let params = ''; + + if (gdprConsent && typeof gdprConsent.consentString === 'string') { + if (typeof gdprConsent.gdprApplies === 'boolean') { + params += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + params += `&gdpr_consent=${gdprConsent.consentString}`; + } + } + if (uspConsent) { + params += `&us_privacy=${uspConsent}`; + } + + hasSynced = true; + return { + type: 'image', + url: SYNC_URL + params + }; + } + } +}; + +function isPopulatedArray(arr) { + return !!(utils.isArray(arr) && arr.length > 0); +} + +function deleteValues(keyPairObj) { + if (isPopulatedArray(keyPairObj.value) && keyPairObj.value[0] === '') { + delete keyPairObj.value; + } +} + +function _getBidFromResponse(respItem) { + if (!respItem) { + utils.logError(LOG_ERROR_MESS.emptySeatbid); + } else if (!respItem.bid) { + utils.logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(respItem)); + } else if (!respItem.bid[0]) { + utils.logError(LOG_ERROR_MESS.noBid); + } + return respItem && respItem.bid && respItem.bid[0]; +} + +function _addBidResponse(serverBid, bidsMap, priceType, bidResponses, RendererConst) { + if (!serverBid) return; + let errorMessage; + if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); + if (!serverBid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid); + else { + const awaitingBids = bidsMap[serverBid.auid]; + if (awaitingBids) { + const sizeId = `${serverBid.w}x${serverBid.h}`; + if (awaitingBids[sizeId]) { + const slot = awaitingBids[sizeId][0]; + + const bid = slot.bids.shift(); + const bidResponse = { + requestId: bid.bidId, // bid.bidderRequestId, + bidderCode: spec.code, + cpm: serverBid.price, + width: serverBid.w, + height: serverBid.h, + creativeId: serverBid.auid, // bid.bidId, + currency: 'EUR', + netRevenue: priceType !== 'gross', + ttl: TIME_TO_LIVE, + dealId: serverBid.dealid + }; + if (serverBid.content_type === 'video' || (!serverBid.content_type && bid.mediaTypes && bid.mediaTypes.video)) { + bidResponse.vastXml = serverBid.adm; + bidResponse.mediaType = VIDEO; + bidResponse.adResponse = { + content: bidResponse.vastXml + }; + if (!bid.renderer && (!bid.mediaTypes || !bid.mediaTypes.video || bid.mediaTypes.video.context === 'outstream')) { + bidResponse.renderer = createRenderer(bidResponse, { + id: bid.bidId, + url: RENDERER_URL + }, RendererConst); + } + } else { + bidResponse.ad = serverBid.adm; + bidResponse.mediaType = BANNER; + } + + bidResponses.push(bidResponse); + + if (!slot.bids.length) { + slot.parents.forEach(({parent, key, uid}) => { + const index = parent[key].indexOf(slot); + if (index > -1) { + parent[key].splice(index, 1); + } + if (!parent[key].length) { + delete parent[key]; + if (!utils.getKeys(parent).length) { + delete bidsMap[uid]; + } + } + }); + } + } + } else { + errorMessage = LOG_ERROR_MESS.noPlacementCode + serverBid.auid; + } + } + if (errorMessage) { + utils.logError(errorMessage); + } +} + +function outstreamRender (bid) { + bid.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + targetId: bid.adUnitCode, + adResponse: bid.adResponse + }); + }); +} + +function createRenderer (bid, rendererParams, RendererConst) { + const rendererInst = RendererConst.install({ + id: rendererParams.id, + url: rendererParams.url, + loaded: false + }); + + try { + rendererInst.setRender(outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on renderer', err); + } + + return rendererInst; +} + +export function resetUserSync() { + hasSynced = false; +} + +export function getSyncUrl() { + return SYNC_URL; +} + +registerBidder(spec); diff --git a/modules/convergeBidAdapter.md b/modules/convergeBidAdapter.md new file mode 100644 index 00000000000..ab916a8b3b6 --- /dev/null +++ b/modules/convergeBidAdapter.md @@ -0,0 +1,57 @@ +# Overview + +Module Name: Converge Bidder Adapter +Module Type: Bidder Adapter +Maintainer: support@converge-digital.com + +# Description + +Module that connects to Converge demand source to fetch bids. +Converge Bid Adapter supports Banner and Video (instream and outstream). + +# Test Parameters +``` + var adUnits = [ + { + code: 'test-div', + sizes: [[300, 250]], + bids: [ + { + bidder: "converge", + params: { + uid: '59', + priceType: 'gross' // by default is 'net' + } + } + ] + },{ + code: 'test-div', + sizes: [[728, 90]], + bids: [ + { + bidder: "converge", + params: { + uid: 1, + priceType: 'gross', + keywords: { + brandsafety: ['disaster'], + topic: ['stress', 'fear'] + } + } + } + ] + },{ + code: 'test-div', + sizes: [[640, 360]], + mediaTypes: { video: {} }, + bids: [ + { + bidder: "converge", + params: { + uid: 60 + } + } + ] + } + ]; +``` diff --git a/modules/conversantBidAdapter.js b/modules/conversantBidAdapter.js index 90865493d8d..2ecdb2b7e98 100644 --- a/modules/conversantBidAdapter.js +++ b/modules/conversantBidAdapter.js @@ -1,13 +1,17 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const GVLID = 24; +export const storage = getStorageManager(GVLID); const BIDDER_CODE = 'conversant'; -const URL = '//web.hb.ad.cpe.dotomi.com/s2s/header/24'; -const VERSION = '2.2.4'; +const URL = 'https://web.hb.ad.cpe.dotomi.com/s2s/header/24'; export const spec = { code: BIDDER_CODE, + gvlid: GVLID, aliases: ['cnvr'], // short code supportedMediaTypes: [BANNER, VIDEO], @@ -24,7 +28,7 @@ export const spec = { } if (!utils.isStr(bid.params.site_id)) { - utils.logWarn(BIDDER_CODE + ': site_id must be specified as a string') + utils.logWarn(BIDDER_CODE + ': site_id must be specified as a string'); return false; } @@ -45,29 +49,31 @@ export const spec = { * Make a server request from the list of BidRequests. * * @param {BidRequest[]} validBidRequests - an array of bids + * @param bidderRequest * @return {ServerRequest} Info describing the request to the server. */ buildRequests: function(validBidRequests, bidderRequest) { - const loc = utils.getTopWindowLocation(); - const page = loc.href; - const isPageSecure = (loc.protocol === 'https:') ? 1 : 0; + const page = (bidderRequest && bidderRequest.refererInfo) ? bidderRequest.refererInfo.referer : ''; let siteId = ''; let requestId = ''; let pubcid = null; + let pubcidName = '_pubcid'; + let bidurl = URL; const conversantImps = validBidRequests.map(function(bid) { const bidfloor = utils.getBidIdParameter('bidfloor', bid.params); - const secure = isPageSecure || (utils.getBidIdParameter('secure', bid.params) ? 1 : 0); - siteId = utils.getBidIdParameter('site_id', bid.params); + siteId = utils.getBidIdParameter('site_id', bid.params) || siteId; + pubcidName = utils.getBidIdParameter('pubcid_name', bid.params) || pubcidName; + requestId = bid.auctionId; const imp = { id: bid.bidId, - secure: secure, + secure: 1, bidfloor: bidfloor || 0, displaymanager: 'Prebid.js', - displaymanagerver: VERSION + displaymanagerver: '$prebid.version$' }; copyOptProperty(bid.params.tag_id, imp, 'tagid'); @@ -104,6 +110,9 @@ export const spec = { } else if (bid.crumbs && bid.crumbs.pubcid) { pubcid = bid.crumbs.pubcid; } + if (bid.params.white_label_url) { + bidurl = bid.params.white_label_url; + } return imp; }); @@ -122,24 +131,36 @@ export const spec = { let userExt = {}; - // Add GDPR flag and consent string - if (bidderRequest && bidderRequest.gdprConsent) { - userExt.consent = bidderRequest.gdprConsent.consentString; + if (bidderRequest) { + // Add GDPR flag and consent string + if (bidderRequest.gdprConsent) { + userExt.consent = bidderRequest.gdprConsent.consentString; - if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { - payload.regs = { - ext: { - gdpr: (bidderRequest.gdprConsent.gdprApplies ? 1 : 0) - } - }; + if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { + utils.deepSetValue(payload, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies ? 1 : 0); + } + } + + if (bidderRequest.uspConsent) { + utils.deepSetValue(payload, 'regs.ext.us_privacy', bidderRequest.uspConsent); } } + if (!pubcid) { + pubcid = readStoredValue(pubcidName); + } + // Add common id if available if (pubcid) { userExt.fpc = pubcid; } + // Add Eids if available + const eids = collectEids(validBidRequests); + if (eids.length > 0) { + userExt.eids = eids; + } + // Only add the user object if it's not empty if (!utils.isEmpty(userExt)) { payload.user = {ext: userExt}; @@ -147,7 +168,7 @@ export const spec = { return { method: 'POST', - url: URL, + url: bidurl, data: payload, }; }, @@ -155,6 +176,7 @@ export const spec = { * Unpack the response from the server into a list of bids. * * @param {*} serverResponse A successful response from the server. + * @param bidRequest * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: function(serverResponse, bidRequest) { @@ -185,7 +207,12 @@ export const spec = { }; if (request.video) { - bid.vastUrl = responseAd; + if (responseAd.charAt(0) === '<') { + bid.vastXml = responseAd; + } else { + bid.vastUrl = responseAd; + } + bid.mediaType = 'video'; bid.width = request.video.w; bid.height = request.video.h; @@ -250,7 +277,7 @@ function getDevice() { * * [[300, 250], [300, 600]] => [{w: 300, h: 250}, {w: 300, h: 600}] * - * @param {number[2][]|number[2]} bidSizes - arrays of widths and heights + * @param {Array.>} bidSizes - arrays of widths and heights * @returns {object[]} Array of objects with w and h */ function convertSizes(bidSizes) { @@ -289,4 +316,62 @@ function copyOptProperty(src, dst, dstName) { } } +/** + * Collect IDs from validBidRequests and store them as an extended id array + * @param bidRequests valid bid requests + */ +function collectEids(bidRequests) { + const request = bidRequests[0]; // bidRequests have the same userId object + const eids = []; + if (utils.isArray(request.userIdAsEids) && request.userIdAsEids.length > 0) { + // later following white-list can be converted to block-list if needed + const requiredSourceValues = { + 'adserver.org': 1, + 'liveramp.com': 1, + 'criteo.com': 1, + 'id5-sync.com': 1, + 'parrable.com': 1, + 'digitru.st': 1, + 'liveintent.com': 1 + }; + request.userIdAsEids.forEach(function(eid) { + if (requiredSourceValues.hasOwnProperty(eid.source)) { + eids.push(eid); + } + }); + } + return eids; +} + +/** + * Look for a stored value from both cookie and local storage and return the first value found. + * @param key Key for the search + * @return {string} Stored value + */ +function readStoredValue(key) { + let storedValue; + try { + // check cookies first + storedValue = storage.getCookie(key); + + if (!storedValue) { + // check expiration time before reading local storage + const storedValueExp = storage.getDataFromLocalStorage(`${key}_exp`); + if (storedValueExp === '' || (storedValueExp && (new Date(storedValueExp)).getTime() - Date.now() > 0)) { + storedValue = storage.getDataFromLocalStorage(key); + storedValue = storedValue ? decodeURIComponent(storedValue) : storedValue; + } + } + + // deserialize JSON if needed + if (utils.isStr(storedValue) && storedValue.charAt(0) === '{') { + storedValue = JSON.parse(storedValue); + } + } catch (e) { + utils.logError(e); + } + + return storedValue; +} + registerBidder(spec); diff --git a/modules/conversantBidAdapter.md b/modules/conversantBidAdapter.md index 3ce83d8c893..fba793adad2 100644 --- a/modules/conversantBidAdapter.md +++ b/modules/conversantBidAdapter.md @@ -13,7 +13,11 @@ Module that connects to Conversant's demand sources. Supports banners and video var adUnits = [ { code: 'banner-test-div', - sizes: [[300, 250]], + mediaTypes: { + banner: { + sizes: [[300, 250],[300,600]] + } + }, bids: [{ bidder: "conversant", params: { @@ -34,6 +38,7 @@ var adUnits = [ site_id: '108060', api: [2], protocols: [1, 2], + white_label_url: 'https://web.hb.ad.cpe.dotomi.com/s2s/header/24', mimes: ['video/mp4'] } }] diff --git a/modules/cosmosBidAdapter.js b/modules/cosmosBidAdapter.js new file mode 100644 index 00000000000..73ee5c223b3 --- /dev/null +++ b/modules/cosmosBidAdapter.js @@ -0,0 +1,392 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; + +const BIDDER_CODE = 'cosmos'; +const BID_ENDPOINT = 'https://bid.cosmoshq.com/openrtb2/bids'; +const USER_SYNC_ENDPOINT = 'https://sync.cosmoshq.com/js/v1/usersync.html'; +const HTTP_POST = 'POST'; +const LOG_PREFIX = 'COSMOS: '; +const DEFAULT_CURRENCY = 'USD'; +const HTTPS = 'https:'; +const MEDIA_TYPES = 'mediaTypes'; +const MIMES = 'mimes'; +const DEFAULT_NET_REVENUE = false; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], + + /** + * generate UUID + **/ + _createUUID: function () { + return ('' + new Date().getTime()); + }, + + /** + * copy object if not null + **/ + _copyObject: function (src, dst) { + if (src) { + // copy complete object + Object.keys(src).forEach(param => dst[param] = src[param]); + } + }, + + /** + * parse object + **/ + _parse: function (rawPayload) { + try { + if (rawPayload) { + return JSON.parse(rawPayload); + } + } catch (ex) { + utils.logError(LOG_PREFIX, 'Exception: ', ex); + } + return null; + }, + + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + **/ + isBidRequestValid: function (bid) { + if (!bid || !bid.params) { + utils.logError(LOG_PREFIX, 'nil/empty bid object'); + return false; + } + + if (!utils.isEmpty(bid.params.publisherId) || + !utils.isNumber(bid.params.publisherId)) { + utils.logError(LOG_PREFIX, 'publisherId is mandatory and must be numeric. Ad Unit: ', JSON.stringify(bid)); + return false; + } + // video bid request validation + if (bid.hasOwnProperty(MEDIA_TYPES) && bid.mediaTypes.hasOwnProperty(VIDEO)) { + if (!bid.mediaTypes.video.hasOwnProperty(MIMES) || + !utils.isArray(bid.mediaTypes.video.mimes) || + bid.mediaTypes.video.mimes.length === 0) { + utils.logError(LOG_PREFIX, 'mimes are mandatory for video bid request. Ad Unit: ', JSON.stringify(bid)); + return false; + } + } + + return true; + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @return ServerRequest Info describing the request to the server. + **/ + buildRequests: function (validBidRequests, bidderRequest) { + if (validBidRequests.length === 0) { + return []; + } + + var refererInfo; + if (bidderRequest && bidderRequest.refererInfo) { + refererInfo = bidderRequest.refererInfo; + } + + let clonedBidRequests = utils.deepClone(validBidRequests); + return clonedBidRequests.map(bidRequest => { + const oRequest = spec._createRequest(bidRequest, refererInfo); + if (oRequest) { + spec._setGDPRParams(bidderRequest, oRequest); + return { + method: HTTP_POST, + url: BID_ENDPOINT, + data: JSON.stringify(oRequest) + }; + } + }); + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + **/ + interpretResponse: function (serverResponse, request) { + let response = serverResponse.body; + var bidResponses = []; + try { + if (response.seatbid) { + var currency = response.cur ? response.cur : DEFAULT_CURRENCY; + response.seatbid.forEach(seatbid => { + var bids = seatbid.bid ? seatbid.bid : []; + bids.forEach(bid => { + var bidResponse = { + requestId: bid.impid, + cpm: (parseFloat(bid.price) || 0).toFixed(2), + width: bid.w, + height: bid.h, + creativeId: bid.crid, + currency: currency, + netRevenue: DEFAULT_NET_REVENUE, + ttl: 300 + }; + if (bid.dealid) { + bidResponse.dealId = bid.dealid; + } + + var req = spec._parse(request.data); + if (req.imp && req.imp.length > 0) { + req.imp.forEach(impr => { + if (impr.id === bid.impid) { + if (impr.banner) { + bidResponse.ad = bid.adm; + bidResponse.mediaType = BANNER; + } else { + bidResponse.width = bid.hasOwnProperty('w') ? bid.w : impr.video.w; + bidResponse.height = bid.hasOwnProperty('h') ? bid.h : impr.video.h; + bidResponse.vastXml = bid.adm; + bidResponse.mediaType = VIDEO; + } + } + }); + } + bidResponses.push(bidResponse); + }); + }); + } + } catch (ex) { + utils.logError(LOG_PREFIX, 'Exception: ', ex); + } + return bidResponses; + }, + + /** + * Register the user sync pixels which should be dropped after the auction. + * @param {SyncOptions} syncOptions Which user syncs are allowed? + * @param {ServerResponse[]} serverResponses List of server's responses. + * @return {UserSync[]} The user syncs which should be dropped. + **/ + getUserSyncs: function (syncOptions, serverResponses) { + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: USER_SYNC_ENDPOINT + }]; + } else { + utils.logWarn(LOG_PREFIX + 'Please enable iframe based user sync.'); + } + }, + + /** + * create IAB standard OpenRTB bid request + **/ + _createRequest: function (bidRequests, refererInfo) { + var oRequest = {}; + try { + oRequest = { + id: spec._createUUID(), + imp: spec._createImpressions(bidRequests), + user: {}, + ext: {} + }; + var site = spec._createSite(bidRequests, refererInfo); + var app = spec._createApp(bidRequests); + var device = spec._createDevice(bidRequests); + if (app) { + oRequest.app = app; + } + if (site) { + oRequest.site = site; + } + if (device) { + oRequest.device = device; + } + } catch (ex) { + utils.logError(LOG_PREFIX, 'Exception: ', ex); + oRequest = null; + } + return oRequest; + }, + + /** + * create impression array objects + **/ + _createImpressions: function (request) { + var impressions = []; + var impression = spec._creatImpression(request); + if (impression) { + impressions.push(impression); + } + return impressions; + }, + + /** + * create impression (single) object + **/ + _creatImpression: function (request) { + if (!request.hasOwnProperty(MEDIA_TYPES)) { + return undefined; + } + + var params = request && request.params ? request.params : null; + var impression = { + id: request.bidId ? request.bidId : spec._createUUID(), + secure: window.location.protocol === HTTPS ? 1 : 0, + bidfloorcur: request.params.currency ? request.params.currency : DEFAULT_CURRENCY + }; + if (params.bidFloor) { + impression.bidfloor = params.bidFloor; + } + + if (params.tagId) { + impression.tagid = params.tagId.toString(); + } + + var banner; + var video; + var mediaType; + for (mediaType in request.mediaTypes) { + switch (mediaType) { + case BANNER: + banner = spec._createBanner(request); + if (banner) { + impression.banner = banner; + } + break; + case VIDEO: + video = spec._createVideo(request); + if (video) { + impression.video = video; + } + break; + } + } + + return impression.hasOwnProperty(BANNER) || + impression.hasOwnProperty(VIDEO) ? impression : undefined; + }, + + /** + * create the banner object + **/ + _createBanner: function (request) { + if (utils.deepAccess(request, 'mediaTypes.banner')) { + var banner = {}; + var sizes = request.mediaTypes.banner.sizes; + if (sizes && utils.isArray(sizes) && sizes.length > 0) { + var format = []; + banner.w = sizes[0][0]; + banner.h = sizes[0][1]; + sizes.forEach(size => { + format.push({ + w: size[0], + h: size[1] + }); + }); + banner.format = format; + } + + spec._copyObject(request.mediaTypes.banner, banner); + spec._copyObject(request.params.banner, banner); + return banner; + } + return undefined; + }, + + /** + * create video object + **/ + _createVideo: function (request) { + if (utils.deepAccess(request, 'mediaTypes.video')) { + var video = {}; + var sizes = request.mediaTypes.video.playerSize; + if (sizes && utils.isArray(sizes) && sizes.length > 1) { + video.w = sizes[0]; + video.h = sizes[1]; + } + spec._copyObject(request.mediaTypes.video, video); + spec._copyObject(request.params.video, video); + return video; + } + return undefined; + }, + + /** + * create site object + **/ + _createSite: function (request, refererInfo) { + var rSite = request.params.site; + if (rSite || !request.params.app) { + var site = {}; + spec._copyObject(rSite, site); + + if (refererInfo) { + if (refererInfo.referer) { + site.ref = encodeURIComponent(refererInfo.referer); + } + if (utils.isArray(refererInfo.stack) && refererInfo.stack.length > 0) { + site.page = encodeURIComponent(refererInfo.stack[0]); + let anchrTag = document.createElement('a'); + anchrTag.href = site.page; + site.domain = anchrTag.hostname; + } + } + + // override publisher object + site.publisher = { + id: request.params.publisherId.toString() + }; + return site; + } + return undefined; + }, + + /** + * create app object + **/ + _createApp: function (request) { + var rApp = request.params.app; + if (rApp) { + var app = {}; + spec._copyObject(rApp, app); + // override publisher object + app.publisher = { + id: request.params.publisherId.toString() + }; + return app; + } + return undefined; + }, + + /** + * create device obejct + **/ + _createDevice: function (request) { + var device = {}; + var rDevice = request.params.device; + spec._copyObject(rDevice, device); + device.dnt = utils.getDNT() ? 1 : 0; + device.ua = navigator.userAgent; + device.language = (navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage); + device.w = (window.screen.width || window.innerWidth); + device.h = (window.screen.height || window.innerHeigh); + return device; + }, + + /** + * set GDPR parameters + **/ + _setGDPRParams: function (bidderRequest, oRequest) { + if (!bidderRequest || !bidderRequest.gdprConsent) { + return; + } + + oRequest.regs = { ext: { gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0 } }; + oRequest.user = { ext: { consent: bidderRequest.gdprConsent.consentString } }; + }, + +} +registerBidder(spec); diff --git a/modules/cosmosBidAdapter.md b/modules/cosmosBidAdapter.md new file mode 100644 index 00000000000..187a19ba17a --- /dev/null +++ b/modules/cosmosBidAdapter.md @@ -0,0 +1,80 @@ +# Overview + +``` +Module Name: Cosmos Bid Adapter +Module Type: Bidder Adapter +Maintainer: dev@cosmoshq.com +``` + +# Description + +Module that connects to Cosmos server for bids. +Supported Ad Fortmats: +* Banner +* Video + +# Configuration +## Following configuration required for enabling user sync. +```javascript +pbjs.setConfig({ + userSync: { + iframeEnabled: true, + enabledBidders: ['cosmos'], + syncDelay: 6000 + }}); +``` +## For Video ads, enable prebid cache +```javascript +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + } +}); +``` + +# Test Parameters +``` + var adUnits = [ + // Banner adUnit + { + code: 'banner-div', + mediaTypes: { + banner: { //supported as per the openRTB spec + sizes: [[300, 250]] // required + } + }, + bids: [ + { + bidder: "cosmos", + params: { + publisherId: 1001, // required + tagId: 1 // optional + } + } + ] + }, + // Video adUnit + { + code: 'video-div', + mediaTypes: { + video: { // supported as per the openRTB spec + sizes: [[300, 50]], // required + mimes : ['video/mp4', 'application/javascript'], // required + context: 'instream' // optional + } + }, + bids: [ + { + bidder: "cosmos", + params: { + publisherId: 1001, // required + tagId: 1, // optional + video: { // supported as per the openRTB spec + + } + } + } + ] + } + ]; +``` diff --git a/modules/cpmstarBidAdapter.js b/modules/cpmstarBidAdapter.js index 84b76cbbc35..b416c00c2d0 100755 --- a/modules/cpmstarBidAdapter.js +++ b/modules/cpmstarBidAdapter.js @@ -1,13 +1,14 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import {VIDEO, BANNER} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'cpmstar'; -const ENDPOINT_DEV = '//dev.server.cpmstar.com/view.aspx'; -const ENDPOINT_STAGING = '//staging.server.cpmstar.com/view.aspx'; -const ENDPOINT_PRODUCTION = '//server.cpmstar.com/view.aspx'; +const ENDPOINT_DEV = 'https://dev.server.cpmstar.com/view.aspx'; +const ENDPOINT_STAGING = 'https://staging.server.cpmstar.com/view.aspx'; +const ENDPOINT_PRODUCTION = 'https://server.cpmstar.com/view.aspx'; const DEFAULT_TTL = 300; const DEFAULT_CURRENCY = 'USD'; @@ -17,12 +18,12 @@ export const spec = { supportedMediaTypes: [BANNER, VIDEO], pageID: Math.floor(Math.random() * 10e6), - getMediaType: function(bidRequest) { + getMediaType: function (bidRequest) { if (bidRequest == null) return BANNER; return !utils.deepAccess(bidRequest, 'mediaTypes.video') ? BANNER : VIDEO; }, - getPlayerSize: function(bidRequest) { + getPlayerSize: function (bidRequest) { var playerSize = utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize'); if (playerSize == null) return [640, 440]; if (playerSize[0] != null) playerSize = playerSize[0]; @@ -46,9 +47,33 @@ export const spec = { var mediaType = spec.getMediaType(bidRequest); var playerSize = spec.getPlayerSize(bidRequest); var videoArgs = '&fv=0' + (playerSize ? ('&w=' + playerSize[0] + '&h=' + playerSize[1]) : ''); + + var url = ENDPOINT + '?media=' + mediaType + (mediaType == VIDEO ? videoArgs : '') + + '&json=c_b&mv=1&poolid=' + utils.getBidIdParameter('placementId', bidRequest.params) + + '&reachedTop=' + encodeURIComponent(bidderRequest.refererInfo.reachedTop) + + '&requestid=' + bidRequest.bidId + + '&referer=' + encodeURIComponent(referer); + + if (bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.consentString != null) { + url += '&gdpr_consent=' + bidderRequest.gdprConsent.consentString; + } + if (bidderRequest.gdprConsent.gdprApplies != null) { + url += '&gdpr=' + (bidderRequest.gdprConsent.gdprApplies ? 1 : 0); + } + } + + if (bidderRequest.uspConsent != null) { + url += '&us_privacy=' + bidderRequest.uspConsent; + } + + if (config.getConfig('coppa')) { + url += '&tfcd=' + (config.getConfig('coppa') ? 1 : 0); + } + requests.push({ method: 'GET', - url: ENDPOINT + '?media=' + mediaType + (mediaType == VIDEO ? videoArgs : '') + '&json=c_b&mv=1&poolid=' + utils.getBidIdParameter('placementId', bidRequest.params) + '&reachedTop=' + encodeURIComponent(bidderRequest.refererInfo.reachedTop) + '&requestid=' + bidRequest.bidId + '&referer=' + referer, + url: url, bidRequest: bidRequest, }); } diff --git a/modules/cpmstarBidAdapter.md b/modules/cpmstarBidAdapter.md index 7dab435b0f0..c227f19bfaf 100755 --- a/modules/cpmstarBidAdapter.md +++ b/modules/cpmstarBidAdapter.md @@ -4,6 +4,9 @@ Module Name: Cpmstar Bidder Adapter Module Type: Bidder Adapter Maintainer: josh@cpmstar.com +gdpr_supported: true +usp_supported: true +coppa_supported: true ``` # Description diff --git a/modules/craftBidAdapter.js b/modules/craftBidAdapter.js new file mode 100644 index 00000000000..3838f5dee59 --- /dev/null +++ b/modules/craftBidAdapter.js @@ -0,0 +1,238 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { auctionManager } from '../src/auctionManager.js'; +import find from 'core-js-pure/features/array/find.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const BIDDER_CODE = 'craft'; +const URL = 'https://gacraft.jp/prebid-v3'; +const TTL = 360; +const storage = getStorageManager(); + +export const spec = { + code: BIDDER_CODE, + aliases: ['craft'], + supportedMediaTypes: [BANNER], + + isBidRequestValid: function(bid) { + return !!bid.params.sitekey && !!bid.params.placementId && !isAmp(); + }, + + buildRequests: function(bidRequests, bidderRequest) { + const tags = bidRequests.map(bidToTag); + const schain = bidRequests[0].schain; + const payload = { + tags: [...tags], + ua: navigator.userAgent, + sdk: { + version: '$prebid.version$' + }, + schain: schain + }; + if (bidderRequest && bidderRequest.gdprConsent) { + payload.gdpr_consent = { + consent_string: bidderRequest.gdprConsent.consentString, + consent_required: bidderRequest.gdprConsent.gdprApplies + }; + } + if (bidderRequest && bidderRequest.uspConsent) { + payload.us_privacy = bidderRequest.uspConsent; + } + if (bidderRequest && bidderRequest.refererInfo) { + let refererinfo = { + rd_ref: bidderRequest.refererInfo.referer, + rd_top: bidderRequest.refererInfo.reachedTop, + rd_ifs: bidderRequest.refererInfo.numIframes, + }; + if (bidderRequest.refererInfo.stack) { + refererinfo.rd_stk = bidderRequest.refererInfo.stack.join(','); + } + payload.referrer_detection = refererinfo; + } + const request = formatRequest(payload, bidderRequest); + return request; + }, + + interpretResponse: function(serverResponse, {bidderRequest}) { + try { + serverResponse = serverResponse.body; + const bids = []; + if (!serverResponse) { + return []; + } + if (serverResponse.error) { + let errorMessage = `in response for ${bidderRequest.bidderCode} adapter`; + if (serverResponse.error) { + errorMessage += `: ${serverResponse.error}`; + } + utils.logError(errorMessage); + return bids; + } + if (serverResponse.tags) { + serverResponse.tags.forEach(serverBid => { + const rtbBid = getRtbBid(serverBid); + if (rtbBid) { + if (rtbBid.cpm !== 0 && includes(this.supportedMediaTypes, rtbBid.ad_type)) { + const bid = newBid(serverBid, rtbBid, bidderRequest); + bid.mediaType = parseMediaType(rtbBid); + bids.push(bid); + } + } + }); + } + return bids; + } catch (e) { + return []; + } + }, + + transformBidParams: function(params, isOpenRtb) { + params = utils.convertTypes({ + 'sitekey': 'string', + 'placementId': 'string', + 'keywords': utils.transformBidderParamKeywords + }, params); + if (isOpenRtb) { + if (isPopulatedArray(params.keywords)) { + params.keywords.forEach(deleteValues); + } + Object.keys(params).forEach(paramKey => { + let convertedKey = utils.convertCamelToUnderscore(paramKey); + if (convertedKey !== paramKey) { + params[convertedKey] = params[paramKey]; + delete params[paramKey]; + } + }); + } + return params; + }, + + onBidWon: function(bid) { + var xhr = new XMLHttpRequest(); + xhr.open('POST', bid._prebidWon); + xhr.send(); + } +}; + +function isPopulatedArray(arr) { + return !!(utils.isArray(arr) && arr.length > 0); +} + +function deleteValues(keyPairObj) { + if (isPopulatedArray(keyPairObj.value) && keyPairObj.value[0] === '') { + delete keyPairObj.value; + } +} + +function hasPurpose1Consent(bidderRequest) { + let result = true; + if (bidderRequest && bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.gdprApplies && bidderRequest.gdprConsent.apiVersion === 2) { + result = !!(utils.deepAccess(bidderRequest.gdprConsent, 'vendorData.purpose.consents.1') === true); + } + } + return result; +} + +function formatRequest(payload, bidderRequest) { + let options = {}; + if (!hasPurpose1Consent(bidderRequest)) { + options = { + withCredentials: false + }; + } + const payloadString = JSON.stringify(payload); + return { + method: 'POST', + url: URL, + data: payloadString, + bidderRequest, + options + }; +} + +function newBid(serverBid, rtbBid, bidderRequest) { + const bidRequest = utils.getBidRequest(serverBid.uuid, [bidderRequest]); + const bid = { + requestId: serverBid.uuid, + cpm: rtbBid.cpm, + currency: 'JPY', + width: rtbBid.rtb.banner.width, + height: rtbBid.rtb.banner.height, + ad: rtbBid.rtb.banner.content, + ttl: TTL, + creativeId: rtbBid.creative_id, + netRevenue: false, // ??? + dealId: rtbBid.deal_id, + meta: null, + _adUnitCode: bidRequest.adUnitCode, + _bidKey: serverBid.bid_key, + _prebidWon: serverBid.won_url, + }; + return bid; +} + +function bidToTag(bid) { + const tag = {}; + for (var k in bid.params) { + tag[k] = bid.params[k]; + } + try { + if (storage.hasLocalStorage()) { + tag.uid = JSON.parse(storage.getDataFromLocalStorage(`${bid.params.sitekey}_uid`)); + } + } catch (e) { + } + tag.sizes = bid.sizes; + tag.primary_size = tag.sizes[0]; + tag.ad_types = []; + tag.uuid = bid.bidId; + if (!utils.isEmpty(bid.params.keywords)) { + let keywords = utils.transformBidderParamKeywords(bid.params.keywords); + if (keywords.length > 0) { + keywords.forEach(deleteValues); + } + tag.keywords = keywords; + } + let adUnit = find(auctionManager.getAdUnits(), au => bid.transactionId === au.transactionId); + if (adUnit && adUnit.mediaTypes && adUnit.mediaTypes.banner) { + tag.ad_types.push(BANNER); + } + + if (tag.ad_types.length === 0) { + delete tag.ad_types; + } + + return tag; +} + +function getRtbBid(tag) { + return tag && tag.ads && tag.ads.length && find(tag.ads, ad => ad.rtb); +} + +function parseMediaType(rtbBid) { + const adType = rtbBid.ad_type; + if (adType === VIDEO) { + return VIDEO; + } else if (adType === NATIVE) { + return NATIVE; + } else { + return BANNER; + } +} + +function isAmp() { + try { + const ampContext = window.context || window.parent.context; + if (ampContext && ampContext.pageViewId) { + return ampContext; + } + return false; + } catch (e) { + return false; + } +} + +registerBidder(spec); diff --git a/modules/craftBidAdapter.md b/modules/craftBidAdapter.md new file mode 100644 index 00000000000..d1a8daeab73 --- /dev/null +++ b/modules/craftBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +``` +Module Name: Craft Bid Adapter +Module Type: Bidder Adapter +Maintainer: system@gacraft.jp +``` + +# Description + +Connects to craft exchange for bids. + +Craft bid adapter supports Banner. + +# Test Parameters +``` +var adUnits = [ + // Banner adUnit + { + code: '/21998384947/prebid-example', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [{ + bidder: 'craft', + params: { + sitekey: 'craft-prebid-example', + placementId: '1234abcd' + } + }] + } +]; +``` diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js old mode 100755 new mode 100644 index ff612aff905..17277ca0fb2 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -1,42 +1,52 @@ -import { loadExternalScript } from '../src/adloader'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { parse } from '../src/url'; -import * as utils from '../src/utils'; -import find from 'core-js/library/fn/array/find'; -import JSEncrypt from 'jsencrypt/bin/jsencrypt'; -import sha256 from 'crypto-js/sha256'; - -const ADAPTER_VERSION = 16; +import {loadExternalScript} from '../src/adloader.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; +import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; +import find from 'core-js-pure/features/array/find.js'; +import { verify } from 'criteo-direct-rsa-validate/build/verify.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const GVLID = 91; +export const ADAPTER_VERSION = 31; const BIDDER_CODE = 'criteo'; -const CDB_ENDPOINT = '//bidder.criteo.com/cdb'; -const CRITEO_VENDOR_ID = 91; -const INTEGRATION_MODES = { - 'amp': 1, -}; +const CDB_ENDPOINT = 'https://bidder.criteo.com/cdb'; const PROFILE_ID_INLINE = 207; -const PROFILE_ID_PUBLISHERTAG = 185; +export const PROFILE_ID_PUBLISHERTAG = 185; +const storage = getStorageManager(GVLID); +const LOG_PREFIX = 'Criteo: '; // Unminified source code can be found in: https://github.com/Prebid-org/prebid-js-external-js-criteo/blob/master/dist/prod.js -const PUBLISHER_TAG_URL = '//static.criteo.net/js/ld/publishertag.prebid.js'; +const PUBLISHER_TAG_URL = 'https://static.criteo.net/js/ld/publishertag.prebid.js'; -export const FAST_BID_PUBKEY = `-----BEGIN PUBLIC KEY----- -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO1BjAITkFTtP0IMzmF7qsqhpu -y1dGaTPHnjMU9mRZsrnfR3C0sEN5pYEzEcFRPnkJjJuhH8Rnh5+CE+LcKg0Z8ZZ7 -OmOSj0/qnYTAYCu0cR5LiyWG79KlIgUyMbp92ulGg24gAyGrVn4+v/4c53WlOEUp -4YWvb82G0CD5NcDNpQIDAQAB ------END PUBLIC KEY-----`; +const FAST_BID_PUBKEY_E = 65537; +const FAST_BID_PUBKEY_N = 'ztQYwCE5BU7T9CDM5he6rKoabstXRmkzx54zFPZkWbK530dwtLBDeaWBMxHBUT55CYyboR/EZ4efghPi3CoNGfGWezpjko9P6p2EwGArtHEeS4slhu/SpSIFMjG6fdrpRoNuIAMhq1Z+Pr/+HOd1pThFKeGFr2/NhtAg+TXAzaU='; /** @type {BidderSpec} */ export const spec = { code: BIDDER_CODE, + gvlid: GVLID, + supportedMediaTypes: [ BANNER, VIDEO, NATIVE ], /** * @param {object} bid * @return {boolean} */ - isBidRequestValid: bid => ( - !!(bid && bid.params && (bid.params.zoneId || bid.params.networkId)) - ), + isBidRequestValid: (bid) => { + // either one of zoneId or networkId should be set + if (!(bid && bid.params && (bid.params.zoneId || bid.params.networkId))) { + return false; + } + + // video media types requires some mandatory params + if (hasVideoMediaType(bid)) { + if (!hasValidVideoMediaType(bid)) { + return false; + } + } + + return true; + }, /** * @param {BidRequest[]} bidRequests @@ -47,6 +57,12 @@ export const spec = { let url; let data; + Object.assign(bidderRequest, { + publisherExt: config.getConfig('fpd.context'), + userExt: config.getConfig('fpd.user'), + ceh: config.getConfig('criteo.ceh') + }); + // If publisher tag not already loaded try to get it from fast bid if (!publisherTagAvailable()) { window.Criteo = window.Criteo || {}; @@ -61,11 +77,16 @@ export const spec = { } if (publisherTagAvailable()) { + // eslint-disable-next-line no-undef const adapter = new Criteo.PubTag.Adapters.Prebid(PROFILE_ID_PUBLISHERTAG, ADAPTER_VERSION, bidRequests, bidderRequest, '$prebid.version$'); + const enableSendAllBids = config.getConfig('enableSendAllBids'); + if (adapter.setEnableSendAllBids && typeof adapter.setEnableSendAllBids === 'function' && typeof enableSendAllBids === 'boolean') { + adapter.setEnableSendAllBids(enableSendAllBids); + } url = adapter.buildCdbUrl(); data = adapter.buildCdbRequest(); } else { - const context = buildContext(bidRequests); + const context = buildContext(bidRequests, bidderRequest); url = buildCdbUrl(context); data = buildCdbRequest(context, bidRequests, bidderRequest); } @@ -84,6 +105,7 @@ export const spec = { const body = response.body || response; if (publisherTagAvailable()) { + // eslint-disable-next-line no-undef const adapter = Criteo.PubTag.Adapters.Prebid.GetAdapter(request); if (adapter) { return adapter.interpretResponse(body, request); @@ -106,9 +128,20 @@ export const spec = { creativeId: bidId, width: slot.width, height: slot.height, - } + dealId: slot.dealCode, + }; if (slot.native) { - bid.ad = createNativeAd(bidId, slot.native, bidRequest.params.nativeCallback); + if (bidRequest.params.nativeCallback) { + bid.ad = createNativeAd(bidId, slot.native, bidRequest.params.nativeCallback); + } else if (config.getConfig('enableSendAllBids') === true) { + return; + } else { + bid.native = createPrebidNativeAd(slot.native); + bid.mediaType = NATIVE; + } + } else if (slot.video) { + bid.vastUrl = slot.displayurl; + bid.mediaType = VIDEO; } else { bid.ad = slot.creative; } @@ -124,6 +157,7 @@ export const spec = { */ onTimeout: (timeoutData) => { if (publisherTagAvailable()) { + // eslint-disable-next-line no-undef const adapter = Criteo.PubTag.Adapters.Prebid.GetAdapter(timeoutData.auctionId); adapter.handleBidTimeout(); } @@ -134,6 +168,7 @@ export const spec = { */ onBidWon: (bid) => { if (publisherTagAvailable()) { + // eslint-disable-next-line no-undef const adapter = Criteo.PubTag.Adapters.Prebid.GetAdapter(bid.auctionId); adapter.handleBidWon(bid); } @@ -144,6 +179,7 @@ export const spec = { */ onSetTargeting: (bid) => { if (publisherTagAvailable()) { + // eslint-disable-next-line no-undef const adapter = Criteo.PubTag.Adapters.Prebid.GetAdapter(bid.auctionId); adapter.handleSetTargeting(bid); } @@ -154,29 +190,33 @@ export const spec = { * @return {boolean} */ function publisherTagAvailable() { + // eslint-disable-next-line no-undef return typeof Criteo !== 'undefined' && Criteo.PubTag && Criteo.PubTag.Adapters && Criteo.PubTag.Adapters.Prebid; } /** * @param {BidRequest[]} bidRequests - * @return {CriteoContext} + * @param bidderRequest */ -function buildContext(bidRequests) { - const url = utils.getTopWindowUrl(); - const queryString = parse(url).search; +function buildContext(bidRequests, bidderRequest) { + let referrer = ''; + if (bidderRequest && bidderRequest.refererInfo) { + referrer = bidderRequest.refererInfo.referer; + } + const queryString = utils.parseUrl(referrer).search; const context = { - url: url, + url: referrer, debug: queryString['pbt_debug'] === '1', noLog: queryString['pbt_nolog'] === '1', - integrationMode: undefined, + amp: false, }; bidRequests.forEach(bidRequest => { - if (bidRequest.params.integrationMode) { - context.integrationMode = bidRequest.params.integrationMode; + if (bidRequest.params.integrationMode === 'amp') { + context.amp = true; } - }) + }); return context; } @@ -192,8 +232,8 @@ function buildCdbUrl(context) { url += '&wv=' + encodeURIComponent('$prebid.version$'); url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); - if (context.integrationMode in INTEGRATION_MODES) { - url += '&im=' + INTEGRATION_MODES[context.integrationMode]; + if (context.amp) { + url += '&im=1'; } if (context.debug) { url += '&debug=1'; @@ -205,9 +245,20 @@ function buildCdbUrl(context) { return url; } +function checkNativeSendId(bidRequest) { + return !(bidRequest.nativeParams && + ((bidRequest.nativeParams.image && bidRequest.nativeParams.image.sendId !== true) || + (bidRequest.nativeParams.icon && bidRequest.nativeParams.icon.sendId !== true) || + (bidRequest.nativeParams.clickUrl && bidRequest.nativeParams.clickUrl.sendId !== true) || + (bidRequest.nativeParams.displayUrl && bidRequest.nativeParams.displayUrl.sendId !== true) || + (bidRequest.nativeParams.privacyLink && bidRequest.nativeParams.privacyLink.sendId !== true) || + (bidRequest.nativeParams.privacyIcon && bidRequest.nativeParams.privacyIcon.sendId !== true))); +} + /** * @param {CriteoContext} context * @param {BidRequest[]} bidRequests + * @param bidderRequest * @return {*} */ function buildCdbRequest(context, bidRequests, bidderRequest) { @@ -215,6 +266,7 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { const request = { publisher: { url: context.url, + ext: bidderRequest.publisherExt }, slots: bidRequests.map(bidRequest => { networkId = bidRequest.params.networkId || networkId; @@ -222,16 +274,44 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { impid: bidRequest.adUnitCode, transactionid: bidRequest.transactionId, auctionId: bidRequest.auctionId, - sizes: bidRequest.sizes.map(size => size[0] + 'x' + size[1]), }; if (bidRequest.params.zoneId) { slot.zoneid = bidRequest.params.zoneId; } + if (bidRequest.fpd && bidRequest.fpd.context) { + slot.ext = bidRequest.fpd.context; + } + if (bidRequest.params.ext) { + slot.ext = Object.assign({}, slot.ext, bidRequest.params.ext); + } if (bidRequest.params.publisherSubId) { slot.publishersubid = bidRequest.params.publisherSubId; } - if (bidRequest.params.nativeCallback) { + if (bidRequest.params.nativeCallback || utils.deepAccess(bidRequest, `mediaTypes.${NATIVE}`)) { slot.native = true; + if (!checkNativeSendId(bidRequest)) { + utils.logWarn(LOG_PREFIX + 'all native assets containing URL should be sent as placeholders with sendId(icon, image, clickUrl, displayUrl, privacyLink, privacyIcon)'); + } + slot.sizes = parseSizes(retrieveBannerSizes(bidRequest), parseNativeSize); + } else { + slot.sizes = parseSizes(retrieveBannerSizes(bidRequest), parseSize); + } + if (hasVideoMediaType(bidRequest)) { + const video = { + playersizes: parseSizes(utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize'), parseSize), + mimes: bidRequest.mediaTypes.video.mimes, + protocols: bidRequest.mediaTypes.video.protocols, + maxduration: bidRequest.mediaTypes.video.maxduration, + api: bidRequest.mediaTypes.video.api + }; + + video.skip = bidRequest.params.video.skip; + video.placement = bidRequest.params.video.placement; + video.minduration = bidRequest.params.video.minduration; + video.playbackmethod = bidRequest.params.video.playbackmethod; + video.startdelay = bidRequest.params.video.startdelay; + + slot.video = video; } return slot; }), @@ -239,89 +319,166 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { if (networkId) { request.publisher.networkid = networkId; } + request.user = { + ext: bidderRequest.userExt + }; + if (bidderRequest && bidderRequest.ceh) { + request.user.ceh = bidderRequest.ceh; + } if (bidderRequest && bidderRequest.gdprConsent) { request.gdprConsent = {}; if (typeof bidderRequest.gdprConsent.gdprApplies !== 'undefined') { request.gdprConsent.gdprApplies = !!(bidderRequest.gdprConsent.gdprApplies); } - if (bidderRequest.gdprConsent.vendorData && bidderRequest.gdprConsent.vendorData.vendorConsents && - typeof bidderRequest.gdprConsent.vendorData.vendorConsents[ CRITEO_VENDOR_ID.toString(10) ] !== 'undefined') { - request.gdprConsent.consentGiven = !!(bidderRequest.gdprConsent.vendorData.vendorConsents[ CRITEO_VENDOR_ID.toString(10) ]); - } + request.gdprConsent.version = bidderRequest.gdprConsent.apiVersion; if (typeof bidderRequest.gdprConsent.consentString !== 'undefined') { request.gdprConsent.consentData = bidderRequest.gdprConsent.consentString; } } + if (bidderRequest && bidderRequest.uspConsent) { + request.user.uspIab = bidderRequest.uspConsent; + } return request; } -/** - * @param {string} id - * @param {*} payload - * @param {*} callback - * @return {string} - */ -function createNativeAd(id, payload, callback) { - // Store the callback and payload in a global object to be later accessed from the creative - window.criteo_prebid_native_slots = window.criteo_prebid_native_slots || {}; - window.criteo_prebid_native_slots[id] = { callback, payload }; +function retrieveBannerSizes(bidRequest) { + return utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes') || bidRequest.sizes; +} - // The creative is in an iframe so we have to get the callback and payload - // from the parent window (doesn't work with safeframes) - return ``; +function parseSizes(sizes, parser) { + if (Array.isArray(sizes[0])) { // is there several sizes ? (ie. [[728,90],[200,300]]) + return sizes.map(size => parser(size)); + } + return [parser(sizes)]; // or a single one ? (ie. [728,90]) } -export function cryptoVerify(key, hash, code) { - var jse = new JSEncrypt(); - jse.setPublicKey(key); - return jse.verify(code, hash, sha256); +function parseSize(size) { + return size[0] + 'x' + size[1]; } -function validateFastBid(fastBid) { - // The value stored must contain the file's encrypted hash as first line - const firstLineEnd = fastBid.indexOf('\n'); - const firstLine = fastBid.substr(0, firstLineEnd).trim(); - if (firstLine.substr(0, 9) !== '// Hash: ') { - utils.logWarn('No hash found in FastBid'); +function parseNativeSize(size) { + if (size[0] === undefined && size[1] === undefined) { + return '2x2'; + } + return size[0] + 'x' + size[1]; +} + +function hasVideoMediaType(bidRequest) { + if (utils.deepAccess(bidRequest, 'params.video') === undefined) { return false; } + return utils.deepAccess(bidRequest, 'mediaTypes.video') !== undefined; +} - // Remove the hash part from the locally stored value - const fileEncryptedHash = firstLine.substr(9); - const publisherTag = fastBid.substr(firstLineEnd + 1); +function hasValidVideoMediaType(bidRequest) { + let isValid = true; - // Verify the hash using cryptography - try { - return cryptoVerify(FAST_BID_PUBKEY, fileEncryptedHash, publisherTag); - } catch (e) { - utils.logWarn('Failed to verify Criteo FastBid'); - return undefined; + var requiredMediaTypesParams = ['mimes', 'playerSize', 'maxduration', 'protocols', 'api']; + + requiredMediaTypesParams.forEach(function(param) { + if (utils.deepAccess(bidRequest, 'mediaTypes.video.' + param) === undefined) { + isValid = false; + utils.logError('Criteo Bid Adapter: mediaTypes.video.' + param + ' is required'); + } + }); + + var requiredParams = ['skip', 'placement', 'playbackmethod']; + + requiredParams.forEach(function(param) { + if (utils.deepAccess(bidRequest, 'params.video.' + param) === undefined) { + isValid = false; + utils.logError('Criteo Bid Adapter: params.video.' + param + ' is required'); + } + }); + + if (isValid) { + // We do not support long form for now, also we have to check that context & placement are consistent + if (bidRequest.mediaTypes.video.context == 'instream' && bidRequest.params.video.placement === 1) { + return true; + } else if (bidRequest.mediaTypes.video.context == 'outstream' && bidRequest.params.video.placement !== 1) { + return true; + } } + + return false; } /** - * @return {boolean} + * Create prebid compatible native ad with native payload + * @param {*} payload + * @returns prebid native ad assets */ -function tryGetCriteoFastBid() { +function createPrebidNativeAd(payload) { + return { + title: payload.products[0].title, + body: payload.products[0].description, + sponsoredBy: payload.advertiser.description, + icon: payload.advertiser.logo, + image: payload.products[0].image, + clickUrl: payload.products[0].click_url, + privacyLink: payload.privacy.optout_click_url, + privacyIcon: payload.privacy.optout_image_url, + cta: payload.products[0].call_to_action, + price: payload.products[0].price, + impressionTrackers: payload.impression_pixels.map(pix => pix.url) + }; +} + +/** + * @param {string} id + * @param {*} payload + * @param {*} callback + * @return {string} + */ +function createNativeAd(id, payload, callback) { + // Store the callback and payload in a global object to be later accessed from the creative + var slotsName = 'criteo_prebid_native_slots'; + window[slotsName] = window[slotsName] || {}; + window[slotsName][id] = { callback, payload }; + + // The creative is in an iframe so we have to get the callback and payload + // from the parent window (doesn't work with safeframes) + return ` +`; +} + +export function tryGetCriteoFastBid() { try { - const fastBid = localStorage.getItem('criteo_fast_bid'); - if (fastBid !== null) { - if (validateFastBid(fastBid) === false) { - utils.logWarn('Invalid Criteo FastBid found'); - localStorage.removeItem('criteo_fast_bid'); + const fastBidStorageKey = 'criteo_fast_bid'; + const hashPrefix = '// Hash: '; + const fastBidFromStorage = storage.getDataFromLocalStorage(fastBidStorageKey); + + if (fastBidFromStorage !== null) { + // The value stored must contain the file's encrypted hash as first line + const firstLineEndPosition = fastBidFromStorage.indexOf('\n'); + const firstLine = fastBidFromStorage.substr(0, firstLineEndPosition).trim(); + + if (firstLine.substr(0, hashPrefix.length) !== hashPrefix) { + utils.logWarn('No hash found in FastBid'); + storage.removeDataFromLocalStorage(fastBidStorageKey); } else { - utils.logInfo('Using Criteo FastBid'); - eval(fastBid); // eslint-disable-line no-eval + // Remove the hash part from the locally stored value + const publisherTagHash = firstLine.substr(hashPrefix.length); + const publisherTag = fastBidFromStorage.substr(firstLineEndPosition + 1); + + if (verify(publisherTag, publisherTagHash, FAST_BID_PUBKEY_N, FAST_BID_PUBKEY_E)) { + utils.logInfo('Using Criteo FastBid'); + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.text = publisherTag; + utils.insertElement(script); + } else { + utils.logWarn('Invalid Criteo FastBid found'); + storage.removeDataFromLocalStorage(fastBidStorageKey); + } } } } catch (e) { diff --git a/modules/criteoBidAdapter.md b/modules/criteoBidAdapter.md old mode 100755 new mode 100644 index 796c70a980f..e4c441c758d --- a/modules/criteoBidAdapter.md +++ b/modules/criteoBidAdapter.md @@ -25,3 +25,13 @@ Module that connects to Criteo's demand sources. } ]; ``` + +# Additional Config (Optional) +Set the "ceh" property to provides the user's hashed email if available +``` + pbjs.setConfig({ + criteo: { + ceh: 'hashed mail' + } + }); +``` \ No newline at end of file diff --git a/modules/criteoIdSystem.js b/modules/criteoIdSystem.js new file mode 100644 index 00000000000..c44f0c843ae --- /dev/null +++ b/modules/criteoIdSystem.js @@ -0,0 +1,141 @@ +/** + * This module adds Criteo Real Time User Sync to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/criteoIdSystem + * @requires module:modules/userId + */ + +import * as utils from '../src/utils.js' +import * as ajax from '../src/ajax.js' +import { getRefererInfo } from '../src/refererDetection.js' +import { submodule } from '../src/hook.js'; +import { getStorageManager } from '../src/storageManager.js'; + +export const storage = getStorageManager(); + +const bididStorageKey = 'cto_bidid'; +const bundleStorageKey = 'cto_bundle'; +const cookieWriteableKey = 'cto_test_cookie'; +const cookiesMaxAge = 13 * 30 * 24 * 60 * 60 * 1000; + +const pastDateString = new Date(0).toString(); +const expirationString = new Date(utils.timestamp() + cookiesMaxAge).toString(); + +function areCookiesWriteable() { + storage.setCookie(cookieWriteableKey, '1'); + const canWrite = storage.getCookie(cookieWriteableKey) === '1'; + storage.setCookie(cookieWriteableKey, '', pastDateString); + return canWrite; +} + +function extractProtocolHost (url, returnOnlyHost = false) { + const parsedUrl = utils.parseUrl(url) + return returnOnlyHost + ? `${parsedUrl.hostname}` + : `${parsedUrl.protocol}://${parsedUrl.hostname}${parsedUrl.port ? ':' + parsedUrl.port : ''}/`; +} + +function getFromAllStorages(key) { + return storage.getCookie(key) || storage.getDataFromLocalStorage(key); +} + +function saveOnAllStorages(key, value) { + if (key && value) { + storage.setCookie(key, value, expirationString); + storage.setDataInLocalStorage(key, value); + } +} + +function deleteFromAllStorages(key) { + storage.setCookie(key, '', pastDateString); + storage.removeDataFromLocalStorage(key); +} + +function getCriteoDataFromAllStorages() { + return { + bundle: getFromAllStorages(bundleStorageKey), + bidId: getFromAllStorages(bididStorageKey), + } +} + +function buildCriteoUsersyncUrl(topUrl, domain, bundle, areCookiesWriteable, isPublishertagPresent, gdprString) { + const url = 'https://gum.criteo.com/sid/json?origin=prebid' + + `${topUrl ? '&topUrl=' + encodeURIComponent(topUrl) : ''}` + + `${domain ? '&domain=' + encodeURIComponent(domain) : ''}` + + `${bundle ? '&bundle=' + encodeURIComponent(bundle) : ''}` + + `${gdprString ? '&gdprString=' + encodeURIComponent(gdprString) : ''}` + + `${areCookiesWriteable ? '&cw=1' : ''}` + + `${isPublishertagPresent ? '&pbt=1' : ''}` + + return url; +} + +function callCriteoUserSync(parsedCriteoData, gdprString) { + const cw = areCookiesWriteable(); + const topUrl = extractProtocolHost(getRefererInfo().referer); + const domain = extractProtocolHost(document.location.href, true); + const isPublishertagPresent = typeof criteo_pubtag !== 'undefined'; // eslint-disable-line camelcase + + const url = buildCriteoUsersyncUrl( + topUrl, + domain, + parsedCriteoData.bundle, + cw, + isPublishertagPresent, + gdprString + ); + + ajax.ajaxBuilder()( + url, + response => { + const jsonResponse = JSON.parse(response); + if (jsonResponse.bidId) { + saveOnAllStorages(bididStorageKey, jsonResponse.bidId); + } else { + deleteFromAllStorages(bididStorageKey); + } + + if (jsonResponse.acwsUrl) { + const urlsToCall = typeof jsonResponse.acwsUrl === 'string' ? [jsonResponse.acwsUrl] : jsonResponse.acwsUrl; + urlsToCall.forEach(url => utils.triggerPixel(url)); + } else if (jsonResponse.bundle) { + saveOnAllStorages(bundleStorageKey, jsonResponse.bundle); + } + } + ); +} + +/** @type {Submodule} */ +export const criteoIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: 'criteo', + /** + * decode the stored id value for passing to bid requests + * @function + * @returns {{criteoId: string} | undefined} + */ + decode(bidId) { + return bidId; + }, + /** + * get the Criteo Id from local storages and initiate a new user sync + * @function + * @param {SubmoduleParams} [configParams] + * @param {ConsentData} [consentData] + * @returns {{id: {criteoId: string} | undefined}}} + */ + getId(configParams, consentData) { + const hasGdprData = consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies; + const gdprConsentString = hasGdprData ? consentData.consentString : undefined; + + let localData = getCriteoDataFromAllStorages(); + callCriteoUserSync(localData, gdprConsentString); + + return { id: localData.bidId ? { criteoId: localData.bidId } : undefined } + } +}; + +submodule('userId', criteoIdSubmodule); diff --git a/modules/currency.js b/modules/currency.js index 17c38b17a98..0464d9b5cdb 100644 --- a/modules/currency.js +++ b/modules/currency.js @@ -1,8 +1,9 @@ -import { createBid } from '../src/bidfactory'; -import { STATUS } from '../src/constants'; -import { ajax } from '../src/ajax'; -import * as utils from '../src/utils'; -import { config } from '../src/config'; +import { getGlobal } from '../src/prebidGlobal.js'; +import { createBid } from '../src/bidfactory.js'; +import { STATUS } from '../src/constants.json'; +import { ajax } from '../src/ajax.js'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; import { getHook } from '../src/hook.js'; const DEFAULT_CURRENCY_RATE_URL = 'https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json?date=$$TODAY$$'; @@ -122,6 +123,8 @@ function initCurrency(url) { utils.logInfo('Installing addBidResponse decorator for currency module', arguments); + // Adding conversion function to prebid global for external module and on page use + getGlobal().convertCurrency = (cpm, fromCurrency, toCurrency) => parseFloat(cpm) * getCurrencyConversion(fromCurrency, toCurrency); getHook('addBidResponse').before(addBidResponseHook, 100); // call for the file if we haven't already @@ -149,6 +152,7 @@ function resetCurrency() { utils.logInfo('Uninstalling addBidResponse decorator for currency module', arguments); getHook('addBidResponse').getHooks({hook: addBidResponseHook}).remove(); + delete getGlobal().convertCurrency; adServerCurrency = 'USD'; conversionCache = {}; @@ -180,12 +184,9 @@ export function addBidResponseHook(fn, adUnitCode, bid) { bid.currency = 'USD'; } - let fromCurrency = bid.currency; - let cpm = bid.cpm; - // used for analytics bid.getCpmInNewCurrency = function(toCurrency) { - return (parseFloat(cpm) * getCurrencyConversion(fromCurrency, toCurrency)).toFixed(3); + return (parseFloat(this.cpm) * getCurrencyConversion(this.currency, toCurrency)).toFixed(3); }; // execute immediately if the bid is already in the desired currency @@ -212,8 +213,6 @@ function wrapFunction(fn, context, params) { let fromCurrency = bid.currency; try { let conversion = getCurrencyConversion(fromCurrency); - bid.originalCpm = bid.cpm; - bid.originalCurrency = bid.currency; if (conversion !== 1) { bid.cpm = (parseFloat(bid.cpm) * conversion).toFixed(4); bid.currency = adServerCurrency; diff --git a/modules/dailyhuntBidAdapter.js b/modules/dailyhuntBidAdapter.js new file mode 100644 index 00000000000..1018417300a --- /dev/null +++ b/modules/dailyhuntBidAdapter.js @@ -0,0 +1,395 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import * as mediaTypes from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; +import { ajax } from '../src/ajax.js'; +import find from 'core-js-pure/features/array/find.js'; +import { OUTSTREAM, INSTREAM } from '../src/video.js'; + +const BIDDER_CODE = 'dailyhunt'; +const BIDDER_ALIAS = 'dh'; +const SUPPORTED_MEDIA_TYPES = [mediaTypes.BANNER, mediaTypes.NATIVE, mediaTypes.VIDEO]; + +const PROD_PREBID_ENDPOINT_URL = 'https://pbs.dailyhunt.in/openrtb2/auction?partner='; +const PROD_PREBID_TEST_ENDPOINT_URL = 'https://qa-pbs-van.dailyhunt.in/openrtb2/auction?partner='; + +const ORTB_NATIVE_TYPE_MAPPING = { + img: { + '3': 'image', + '1': 'icon' + }, + data: { + '1': 'sponsoredBy', + '2': 'body', + '3': 'rating', + '4': 'likes', + '5': 'downloads', + '6': 'price', + '7': 'salePrice', + '8': 'phone', + '9': 'address', + '10': 'body2', + '11': 'displayUrl', + '12': 'cta' + } +} + +const ORTB_NATIVE_PARAMS = { + title: { + id: 0, + name: 'title' + }, + icon: { + id: 1, + type: 1, + name: 'img' + }, + image: { + id: 2, + type: 3, + name: 'img' + }, + sponsoredBy: { + id: 3, + name: 'data', + type: 1 + }, + body: { + id: 4, + name: 'data', + type: 2 + }, + cta: { + id: 5, + type: 12, + name: 'data' + }, + body2: { + id: 4, + name: 'data', + type: 10 + }, +}; + +// Encode URI. +const _encodeURIComponent = function (a) { + let b = window.encodeURIComponent(a); + b = b.replace(/'/g, '%27'); + return b; +} + +// Extract key from collections. +const extractKeyInfo = (collection, key) => { + for (let i = 0, result; i < collection.length; i++) { + result = utils.deepAccess(collection[i].params, key); + if (result) { + return result; + } + } + return undefined +} + +// Flattern Array. +const flatten = (arr) => { + return [].concat(...arr); +} + +const createOrtbRequest = (validBidRequests, bidderRequest) => { + let device = createOrtbDeviceObj(validBidRequests); + let user = createOrtbUserObj(validBidRequests) + let site = createOrtbSiteObj(validBidRequests, bidderRequest.refererInfo.referer) + return { + id: bidderRequest.auctionId, + imp: [], + site, + device, + user, + }; +} + +const createOrtbDeviceObj = (validBidRequests) => { + let device = { ...extractKeyInfo(validBidRequests, `device`) }; + device.ua = navigator.userAgent; + return device; +} + +const createOrtbUserObj = (validBidRequests) => ({ ...extractKeyInfo(validBidRequests, `user`) }) + +const createOrtbSiteObj = (validBidRequests, page) => { + let site = { ...extractKeyInfo(validBidRequests, `site`), page }; + let publisher = createOrtbPublisherObj(validBidRequests); + if (publisher) { + site.publisher = publisher + } + return site +} + +const createOrtbPublisherObj = (validBidRequests) => ({ ...extractKeyInfo(validBidRequests, `publisher`) }) + +const createOrtbImpObj = (bid) => { + let params = bid.params + let testMode = !!bid.params.test_mode + + // Validate Banner Request. + let bannerObj = utils.deepAccess(bid.mediaTypes, `banner`); + let nativeObj = utils.deepAccess(bid.mediaTypes, `native`); + let videoObj = utils.deepAccess(bid.mediaTypes, `video`); + + let imp = { + id: bid.bidId, + bidfloor: params.bidfloor ? params.bidfloor : 0, + ext: { + dailyhunt: { + placement_id: params.placement_id, + publisher_id: params.publisher_id, + partner: params.partner_name + } + } + }; + + // Test Mode Campaign. + if (testMode) { + imp.ext.test_mode = testMode; + } + + if (bannerObj) { + imp.banner = { + ...createOrtbImpBannerObj(bid, bannerObj) + } + } else if (nativeObj) { + imp.native = { + ...createOrtbImpNativeObj(bid, nativeObj) + } + } else if (videoObj) { + imp.video = { + ...createOrtbImpVideoObj(bid, videoObj) + } + } + return imp; +} + +const createOrtbImpBannerObj = (bid, bannerObj) => { + let format = []; + bannerObj.sizes.forEach(size => format.push({ w: size[0], h: size[1] })) + + return { + id: 'banner-' + bid.bidId, + format + } +} + +const createOrtbImpNativeObj = (bid, nativeObj) => { + const assets = utils._map(bid.nativeParams, (bidParams, key) => { + const props = ORTB_NATIVE_PARAMS[key]; + const asset = { + required: bidParams.required & 1, + }; + if (props) { + let h = 0; + let w = 0; + + asset.id = props.id; + + if (bidParams.sizes) { + const sizes = flatten(bidParams.sizes); + w = sizes[0]; + h = sizes[1]; + } + + asset[props.name] = { + len: bidParams.len ? bidParams.len : 20, + type: props.type, + w, + h + }; + + return asset; + } + }).filter(Boolean); + let request = { + assets, + ver: '1,0' + } + return { request: JSON.stringify(request) }; +} + +const createOrtbImpVideoObj = (bid, videoObj) => { + let obj = {}; + let params = bid.params + if (!utils.isEmpty(bid.params.video)) { + obj = { + ...params.video, + } + } else { + obj = { + mimes: ['video/mp4'], + }; + } + obj.ext = { + ...videoObj, + } + return obj; +} + +const createServerRequest = (ortbRequest, validBidRequests, isTestMode = 'false') => ({ + method: 'POST', + url: isTestMode === 'true' ? PROD_PREBID_TEST_ENDPOINT_URL + validBidRequests[0].params.partner_name : PROD_PREBID_ENDPOINT_URL + validBidRequests[0].params.partner_name, + data: JSON.stringify(ortbRequest), + options: { + contentType: 'application/json', + withCredentials: true + }, + bids: validBidRequests +}) + +const createPrebidBannerBid = (bid, bidResponse) => ({ + requestId: bid.bidId, + cpm: bidResponse.price.toFixed(2), + creativeId: bidResponse.crid, + width: bidResponse.w, + height: bidResponse.h, + ttl: 360, + netRevenue: bid.netRevenue === 'net', + currency: 'USD', + ad: bidResponse.adm, + mediaType: 'banner', + winUrl: bidResponse.nurl +}) + +const createPrebidNativeBid = (bid, bidResponse) => ({ + requestId: bid.bidId, + cpm: bidResponse.price.toFixed(2), + creativeId: bidResponse.crid, + currency: 'USD', + ttl: 360, + netRevenue: bid.netRevenue === 'net', + native: parseNative(bidResponse), + mediaType: 'native', + winUrl: bidResponse.nurl, + width: bidResponse.w, + height: bidResponse.h, +}) + +const parseNative = (bid) => { + let adm = JSON.parse(bid.adm) + const { assets, link, imptrackers, jstracker } = adm.native; + const result = { + clickUrl: _encodeURIComponent(link.url), + clickTrackers: link.clicktrackers || [], + impressionTrackers: imptrackers || [], + javascriptTrackers: jstracker ? [ jstracker ] : [] + }; + assets.forEach(asset => { + if (!utils.isEmpty(asset.title)) { + result.title = asset.title.text + } else if (!utils.isEmpty(asset.img)) { + result[ORTB_NATIVE_TYPE_MAPPING.img[asset.img.type]] = { + url: asset.img.url, + height: asset.img.h, + width: asset.img.w + } + } else if (!utils.isEmpty(asset.data)) { + result[ORTB_NATIVE_TYPE_MAPPING.data[asset.data.type]] = asset.data.value + } + }); + + return result; +} + +const createPrebidVideoBid = (bid, bidResponse) => { + let videoBid = { + requestId: bid.bidId, + cpm: bidResponse.price.toFixed(2), + creativeId: bidResponse.crid, + width: bidResponse.w, + height: bidResponse.h, + ttl: 360, + netRevenue: bid.netRevenue === 'net', + currency: 'USD', + mediaType: 'video', + winUrl: bidResponse.nurl, + }; + + let videoContext = bid.mediaTypes.video.context; + switch (videoContext) { + case OUTSTREAM: + videoBid.vastXml = bidResponse.adm; + break; + case INSTREAM: + videoBid.videoCacheKey = bidResponse.ext.bidder.cacheKey; + videoBid.vastUrl = bidResponse.ext.bidder.vastUrl; + break; + } + return videoBid; +} + +const getQueryVariable = (variable) => { + let query = window.location.search.substring(1); + let vars = query.split('&'); + for (var i = 0; i < vars.length; i++) { + let pair = vars[i].split('='); + if (decodeURIComponent(pair[0]) == variable) { + return decodeURIComponent(pair[1]); + } + } + return false; +} + +export const spec = { + code: BIDDER_CODE, + + aliases: [BIDDER_ALIAS], + + supportedMediaTypes: SUPPORTED_MEDIA_TYPES, + + isBidRequestValid: bid => !!bid.params.placement_id && !!bid.params.publisher_id && !!bid.params.partner_name, + + buildRequests: function (validBidRequests, bidderRequest) { + let serverRequests = []; + + // ORTB Request. + let ortbReq = createOrtbRequest(validBidRequests, bidderRequest); + + validBidRequests.forEach((bid) => { + let imp = createOrtbImpObj(bid) + ortbReq.imp.push(imp); + }); + + serverRequests.push({ ...createServerRequest(ortbReq, validBidRequests, getQueryVariable('dh_test')) }); + + return serverRequests; + }, + + interpretResponse: function (serverResponse, request) { + const { seatbid } = serverResponse.body; + let bids = request.bids; + let prebidResponse = []; + + let seatBids = seatbid[0].bid; + + seatBids.forEach(ortbResponseBid => { + let bidId = ortbResponseBid.impid; + let actualBid = find(bids, (bid) => bid.bidId === bidId); + let bidMediaType = ortbResponseBid.ext.prebid.type + switch (bidMediaType) { + case mediaTypes.BANNER: + prebidResponse.push(createPrebidBannerBid(actualBid, ortbResponseBid)); + break; + case mediaTypes.NATIVE: + prebidResponse.push(createPrebidNativeBid(actualBid, ortbResponseBid)); + break; + case mediaTypes.VIDEO: + prebidResponse.push(createPrebidVideoBid(actualBid, ortbResponseBid)); + break; + } + }) + return prebidResponse; + }, + + onBidWon: function(bid) { + ajax(bid.winUrl, null, null, { + method: 'GET' + }) + } +} + +registerBidder(spec); diff --git a/modules/dailyhuntBidAdapter.md b/modules/dailyhuntBidAdapter.md new file mode 100644 index 00000000000..acfd20a4de0 --- /dev/null +++ b/modules/dailyhuntBidAdapter.md @@ -0,0 +1,101 @@ +# Overview + +``` +Module Name: Dailyhunt Bid Adapter +Module Type: Bidder Adapter +Maintainer: Dailyhunt +``` + +# Description + +Connects to dailyhunt for bids. + +Dailyhunt bid adapter supports Banner, Native and Video. + +# Test Parameters +``` + var adUnits = [ + { + code: '/83414793/prebid_test_display', + sizes: [[300, 250], [320, 50]], + mediaTypes: { + banner : { + sizes: [[300, 250], [320, 50]], + } + }, + bids: [ + { + bidder: 'dailyhunt', + params: { + placement_id: 1, + publisher_id: 1, + partner_name: 'dailyhunt', + device: { + ip: "182.23.143.212" + } + } + } + ] + }, + { + code: '/83414793/prebid_test_native', + sizes: [[300, 250]], + mediaTypes: { + native: { + title: { + required: true + }, + body: { + required: true + }, + image: { + required: true + }, + cta: { + required: true + } + } + }, + bids: [ + { + bidder: 'dailyhunt', + params: { + placement_id: 1, + publisher_id: 1, + partner_name: 'dailyhunt', + device: { + ip: "182.23.143.212" + } + } + } + ] + }, + { + code: '/83414793/prebid_test_video', + mediaTypes: { + video: { + playerSize: [1280, 720], + context: 'instream' + } + }, + bids: [ + { + bidder: 'dailyhunt', + params: { + placement_id: 1, + publisher_id: 1, + partner_name: 'dailyhunt', + device: { + ip: "182.23.143.212" + }, + video: { + mimes: [ + 'video/mp4' + ] + } + } + } + ] + } + ]; +``` diff --git a/modules/danmarketBidAdapter.js b/modules/danmarketBidAdapter.js deleted file mode 100644 index 77f90f43319..00000000000 --- a/modules/danmarketBidAdapter.js +++ /dev/null @@ -1,161 +0,0 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -const BIDDER_CODE = 'danmarket'; -const ENDPOINT_URL = '//ads.danmarketplace.com/hb'; -const TIME_TO_LIVE = 360; -const ADAPTER_SYNC_URL = '//ads.danmarketplace.com/push_sync'; -const LOG_ERROR_MESS = { - noAuid: 'Bid from response has no auid parameter - ', - noAdm: 'Bid from response has no adm parameter - ', - noBid: 'Array of bid objects is empty', - noPlacementCode: 'Can\'t find in requested bids the bid with auid - ', - emptyUids: 'Uids should be not empty', - emptySeatbid: 'Seatbid array from response has empty item', - emptyResponse: 'Response is empty', - hasEmptySeatbidArray: 'Response has empty seatbid array', - hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' -}; - -/** - * Dentsu Aegis Network Marketplace Bid Adapter. - * Contact: niels@baarsma.net - * - */ -export const spec = { - code: BIDDER_CODE, - - aliases: ['DANMarketplace', 'DAN_Marketplace', 'danmarketplace'], - - isBidRequestValid: function(bid) { - return !!bid.params.uid; - }, - - buildRequests: function(validBidRequests, bidderRequest) { - const auids = []; - const bidsMap = {}; - const bids = validBidRequests || []; - let priceType = 'net'; - let reqId; - - bids.forEach(bid => { - if (bid.params.priceType === 'gross') { - priceType = 'gross'; - } - if (!bidsMap[bid.params.uid]) { - bidsMap[bid.params.uid] = [bid]; - auids.push(bid.params.uid); - } else { - bidsMap[bid.params.uid].push(bid); - } - reqId = bid.bidderRequestId; - }); - - const payload = { - u: utils.getTopWindowUrl(), - pt: priceType, - auids: auids.join(','), - r: reqId, - }; - - if (bidderRequest && bidderRequest.gdprConsent) { - if (bidderRequest.gdprConsent.consentString) { - payload.gdpr_consent = bidderRequest.gdprConsent.consentString; - } - payload.gdpr_applies = - (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') - ? Number(bidderRequest.gdprConsent.gdprApplies) : 1; - } - - return { - method: 'GET', - url: ENDPOINT_URL, - data: payload, - bidsMap: bidsMap, - }; - }, - - interpretResponse: function(serverResponse, bidRequest) { - serverResponse = serverResponse && serverResponse.body - const bidResponses = []; - const bidsMap = bidRequest.bidsMap; - const priceType = bidRequest.data.pt; - - let errorMessage; - - if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse; - else if (serverResponse.seatbid && !serverResponse.seatbid.length) { - errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; - } - - if (!errorMessage && serverResponse.seatbid) { - serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses); - }); - } - if (errorMessage) utils.logError(errorMessage); - return bidResponses; - }, - - getUserSyncs: function(syncOptions, serverResponses, gdprConsent) { - if (syncOptions.pixelEnabled) { - var query = []; - if (gdprConsent) { - if (gdprConsent.consentString) { - query.push('gdpr_consent=' + encodeURIComponent(gdprConsent.consentString)); - } - query.push('gdpr_applies=' + encodeURIComponent( - (typeof gdprConsent.gdprApplies === 'boolean') - ? Number(gdprConsent.gdprApplies) : 1)); - } - return [{ - type: 'image', - url: ADAPTER_SYNC_URL + (query.length ? '?' + query.join('&') : '') - }]; - } - } -} - -function _getBidFromResponse(respItem) { - if (!respItem) { - utils.logError(LOG_ERROR_MESS.emptySeatbid); - } else if (!respItem.bid) { - utils.logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(respItem)); - } else if (!respItem.bid[0]) { - utils.logError(LOG_ERROR_MESS.noBid); - } - return respItem && respItem.bid && respItem.bid[0]; -} - -function _addBidResponse(serverBid, bidsMap, priceType, bidResponses) { - if (!serverBid) return; - let errorMessage; - if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); - if (!serverBid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid); - else { - const awaitingBids = bidsMap[serverBid.auid]; - if (awaitingBids) { - awaitingBids.forEach(bid => { - const bidResponse = { - requestId: bid.bidId, // bid.bidderRequestId, - cpm: serverBid.price, - width: serverBid.w, - height: serverBid.h, - creativeId: serverBid.auid, // bid.bidId, - currency: 'USD', - netRevenue: priceType !== 'gross', - ttl: TIME_TO_LIVE, - ad: serverBid.adm, - dealId: serverBid.dealid - }; - bidResponses.push(bidResponse); - }); - } else { - errorMessage = LOG_ERROR_MESS.noPlacementCode + serverBid.auid; - } - } - if (errorMessage) { - utils.logError(errorMessage); - } -} - -registerBidder(spec); diff --git a/modules/danmarketBidAdapter.md b/modules/danmarketBidAdapter.md old mode 100755 new mode 100644 diff --git a/modules/datablocksAnalyticsAdapter.js b/modules/datablocksAnalyticsAdapter.js new file mode 100644 index 00000000000..5e977155284 --- /dev/null +++ b/modules/datablocksAnalyticsAdapter.js @@ -0,0 +1,19 @@ +/** + * Analytics Adapter for Datablocks + */ + +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; + +var datablocksAdapter = adapter({ + global: 'datablocksAnalytics', + handler: 'on', + analyticsType: 'bundle' +}); + +adapterManager.registerAnalyticsAdapter({ + adapter: datablocksAdapter, + code: 'datablocks' +}); + +export default datablocksAdapter; diff --git a/modules/datablocksAnalyticsAdapter.md b/modules/datablocksAnalyticsAdapter.md new file mode 100644 index 00000000000..07f65da6e2c --- /dev/null +++ b/modules/datablocksAnalyticsAdapter.md @@ -0,0 +1,23 @@ +# Overview + +Module Name: Datablocks Analytics Adapter +Module Type: Datablocks Adapter +Maintainer: support@datablocks.net + +# Description + +Analytics adapter for Datablocks.net. Contact support@datablocks.net for information. + +# Test Parameters + +``` +{ + provider: 'datablocks', + options: { + publisherId: 12345, + sourceId: 12356, + host: 'prebid.datablocks.net' + + } +} +``` \ No newline at end of file diff --git a/modules/datablocksBidAdapter.js b/modules/datablocksBidAdapter.js new file mode 100644 index 00000000000..b00a3eae659 --- /dev/null +++ b/modules/datablocksBidAdapter.js @@ -0,0 +1,330 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +const NATIVE_MAP = { + 'body': 2, + 'body2': 10, + 'price': 6, + 'displayUrl': 11, + 'cta': 12 +}; +const NATIVE_IMAGE = [{ + id: 1, + required: 1, + title: { + len: 140 + } +}, { + id: 2, + required: 1, + img: { type: 3 } +}, { + id: 3, + required: 1, + data: { + type: 11 + } +}, { + id: 4, + required: 0, + data: { + type: 2 + } +}, { + id: 5, + required: 0, + img: { type: 1 } +}, { + id: 6, + required: 0, + data: { + type: 12 + } +}]; + +const VIDEO_PARAMS = ['mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h', 'startdelay', + 'placement', 'linearity', 'skip', 'skipmin', 'skipafter', 'sequence', 'battr', 'maxextended', + 'minbitrate', 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend', 'delivery', + 'pos', 'companionad', 'api', 'companiontype', 'ext']; + +export const spec = { + supportedMediaTypes: [BANNER, NATIVE, VIDEO], + code: 'datablocks', + isBidRequestValid: function(bid) { + return !!(bid.params.host && bid.params.sourceId && + bid.mediaTypes && (bid.mediaTypes.banner || bid.mediaTypes.native || bid.mediaTypes.video)); + }, + buildRequests: function(validBidRequests, bidderRequest) { + if (!validBidRequests.length) { return []; } + + let imps = {}; + let site = {}; + let device = {}; + let refurl = utils.parseUrl(bidderRequest.referrer); + let requests = []; + + validBidRequests.forEach(bidRequest => { + let imp = { + id: bidRequest.bidId, + tagid: bidRequest.adUnitCode, + secure: window.location.protocol == 'https:' + } + + if (utils.deepAccess(bidRequest, `mediaTypes.banner`)) { + let sizes = bidRequest.mediaTypes.banner.sizes; + if (sizes.length == 1) { + imp.banner = { + w: sizes[0][0], + h: sizes[0][1] + } + } else if (sizes.length > 1) { + imp.banner = { + format: sizes.map(size => ({ w: size[0], h: size[1] })) + }; + } else { + return; + } + } else if (utils.deepAccess(bidRequest, 'mediaTypes.native')) { + let nativeImp = bidRequest.mediaTypes.native; + + if (nativeImp.type) { + let nativeAssets = []; + switch (nativeImp.type) { + case 'image': + nativeAssets = NATIVE_IMAGE; + break; + default: + return; + } + imp.native = JSON.stringify({ assets: nativeAssets }); + } else { + let nativeAssets = []; + let nativeKeys = Object.keys(nativeImp); + nativeKeys.forEach((nativeKey, index) => { + let required = !!nativeImp[nativeKey].required; + let assetId = index + 1; + switch (nativeKey) { + case 'title': + nativeAssets.push({ + id: assetId, + required: required, + title: { + len: nativeImp[nativeKey].len || 140 + } + }); + break; + case 'body': // desc + case 'body2': // desc2 + case 'price': + case 'display_url': + let data = { + id: assetId, + required: required, + data: { + type: NATIVE_MAP[nativeKey] + } + } + if (nativeImp[nativeKey].data && nativeImp[nativeKey].data.len) { data.data.len = nativeImp[nativeKey].data.len; } + + nativeAssets.push(data); + break; + case 'image': + if (nativeImp[nativeKey].sizes && nativeImp[nativeKey].sizes.length) { + nativeAssets.push({ + id: assetId, + required: required, + image: { + type: 3, + w: nativeImp[nativeKey].sizes[0], + h: nativeImp[nativeKey].sizes[1] + } + }) + } + } + }); + imp.native = { + request: JSON.stringify({native: {assets: nativeAssets}}) + }; + } + } else if (utils.deepAccess(bidRequest, 'mediaTypes.video')) { + let video = bidRequest.mediaTypes.video; + let sizes = video.playerSize || bidRequest.sizes || []; + if (sizes.length && Array.isArray(sizes[0])) { + imp.video = { + w: sizes[0][0], + h: sizes[0][1] + }; + } else if (sizes.length == 2 && !Array.isArray(sizes[0])) { + imp.video = { + w: sizes[0], + h: sizes[1] + }; + } else { + return; + } + + if (video.durationRangeSec) { + if (Array.isArray(video.durationRangeSec)) { + if (video.durationRangeSec.length == 1) { + imp.video.maxduration = video.durationRangeSec[0]; + } else if (video.durationRangeSec.length == 2) { + imp.video.minduration = video.durationRangeSec[0]; + imp.video.maxduration = video.durationRangeSec[1]; + } + } else { + imp.video.maxduration = video.durationRangeSec; + } + } + + if (bidRequest.params.video) { + Object.keys(bidRequest.params.video).forEach(k => { + if (VIDEO_PARAMS.indexOf(k) > -1) { + imp.video[k] = bidRequest.params.video[k]; + } + }) + } + } + let host = bidRequest.params.host; + let sourceId = bidRequest.params.sourceId; + imps[host] = imps[host] || {}; + let hostImp = imps[host][sourceId] = imps[host][sourceId] || { imps: [] }; + hostImp.imps.push(imp); + hostImp.subid = hostImp.imps.subid || bidRequest.params.subid || 'blank'; + hostImp.path = 'search'; + hostImp.idParam = 'sid'; + hostImp.protocol = '//'; + }); + + // Generate Site obj + site.domain = refurl.hostname; + site.page = refurl.protocol + '://' + refurl.hostname + refurl.pathname; + if (self === top && document.referrer) { + site.ref = document.referrer; + } + let keywords = document.getElementsByTagName('meta')['keywords']; + if (keywords && keywords.content) { + site.keywords = keywords.content; + } + + // Generate Device obj. + device.ip = 'peer'; + device.ua = window.navigator.userAgent; + device.js = 1; + device.language = ((navigator.language || navigator.userLanguage || '').split('-'))[0] || 'en'; + + RtbRequest(device, site, imps).forEach(formatted => { + requests.push({ + method: 'POST', + url: formatted.url, + data: formatted.body, + options: { + withCredentials: false + } + }) + }); + return requests; + + function RtbRequest(device, site, imps) { + let collection = []; + Object.keys(imps).forEach(host => { + let sourceIds = imps[host]; + Object.keys(sourceIds).forEach(sourceId => { + let impObj = sourceIds[sourceId]; + collection.push({ + url: `https://${host}/${impObj.path}/?${impObj.idParam}=${sourceId}`, + body: { + id: bidderRequest.auctionId, + imp: impObj.imps, + site: Object.assign({ id: impObj.subid || 'blank' }, site), + device: Object.assign({}, device) + } + }) + }) + }) + + return collection; + } + }, + interpretResponse: function(serverResponse, bidRequest) { + if (!serverResponse || !serverResponse.body || !serverResponse.body.seatbid) { + return []; + } + let body = serverResponse.body; + + let bids = body.seatbid + .map(seatbid => seatbid.bid) + .reduce((memo, bid) => memo.concat(bid), []); + let req = bidRequest.data; + let reqImps = req.imp; + + return bids.map(rtbBid => { + let imp; + for (let i in reqImps) { + let testImp = reqImps[i] + if (testImp.id == rtbBid.impid) { + imp = testImp; + break; + } + } + let br = { + requestId: rtbBid.impid, + cpm: rtbBid.price, + creativeId: rtbBid.crid, + currency: rtbBid.currency || 'USD', + netRevenue: true, + ttl: 360 + }; + if (!imp) { + return br; + } else if (imp.banner) { + br.mediaType = BANNER; + br.width = rtbBid.w; + br.height = rtbBid.h; + br.ad = rtbBid.adm; + } else if (imp.native) { + br.mediaType = NATIVE; + + let reverseNativeMap = {}; + let nativeKeys = Object.keys(NATIVE_MAP); + nativeKeys.forEach(k => { + reverseNativeMap[NATIVE_MAP[k]] = k; + }); + + let idMap = {}; + let nativeReq = JSON.parse(imp.native.request); + if (nativeReq.native && nativeReq.native.assets) { + nativeReq.native.assets.forEach(asset => { + if (asset.data) { idMap[asset.id] = reverseNativeMap[asset.data.type]; } + }) + } + + const nativeResponse = JSON.parse(rtbBid.adm); + const { assets, link, imptrackers, jstrackers } = nativeResponse.native; + const result = { + clickUrl: link.url, + clickTrackers: link.clicktrackers || undefined, + impressionTrackers: imptrackers || undefined, + javascriptTrackers: jstrackers ? [jstrackers] : undefined + }; + assets.forEach(asset => { + if (asset.title) { + result.title = asset.title.text; + } else if (asset.img) { + result.image = asset.img.url; + } else if (idMap[asset.id]) { + result[idMap[asset.id]] = asset.data.value; + } + }) + br.native = result; + } else if (imp.video) { + br.mediaType = VIDEO; + br.width = rtbBid.w; + br.height = rtbBid.h; + if (rtbBid.adm) { br.vastXml = rtbBid.adm; } else if (rtbBid.nurl) { br.vastUrl = rtbBid.nurl; } + } + return br; + }); + } + +}; +registerBidder(spec); diff --git a/modules/datablocksBidAdapter.md b/modules/datablocksBidAdapter.md new file mode 100644 index 00000000000..e30cd361974 --- /dev/null +++ b/modules/datablocksBidAdapter.md @@ -0,0 +1,73 @@ +# Overview + +``` +Module Name: Datablocks Bidder Adapter +Module Type: Bidder Adapter +Maintainer: support@datablocks.net +``` + +# Description + +Connects to Datablocks Version 5 Platform +Banner Native and Video + + +# Test Parameters +``` + var adUnits = [ + { + code: 'banner-div', + sizes: [[300, 250]], + mediaTypes:{ + banner: { + sizes: [300,250] + } + }, + bids: [ + { + bidder: 'datablocks', + params: { + sourceId: 12345, + host: 'prebid.datablocks.net' + } + } + ] + }, { + code: 'native-div', + mediaTypes : { + native: { + title:{required:true}, + body:{required:true} + } + }, + bids: [ + { + bidder: 'datablocks', + params: { + sourceId: 12345, + host: 'prebid.datablocks.net' + } + }, { + code: 'video-div', + mediaTypes : { + video: { + playerSize:[500,400], + durationRangeSec:[15,30], + context: "linear" + } + }, + bids: [ + { + bidder: 'datablocks', + params: { + sourceId: 12345, + host: 'prebid.datablocks.net', + video: { + mimes:["video/flv"] + } + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/modules/decenteradsBidAdapter.js b/modules/decenteradsBidAdapter.js deleted file mode 100644 index 65d3032d3f8..00000000000 --- a/modules/decenteradsBidAdapter.js +++ /dev/null @@ -1,90 +0,0 @@ -import { registerBidder } from '../src/adapters/bidderFactory' -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes' -import * as utils from '../src/utils' - -const BIDDER_CODE = 'decenterads' -const URL = '//supply.decenterads.com/?c=o&m=multi' -const URL_SYNC = '//supply.decenterads.com/?c=o&m=cookie' - -export const spec = { - code: BIDDER_CODE, - supportedMediaTypes: [BANNER, VIDEO, NATIVE], - - isBidRequestValid: function (opts) { - return Boolean(opts.bidId && opts.params && !isNaN(opts.params.placementId)) - }, - - buildRequests: function (validBidRequests) { - validBidRequests = validBidRequests || [] - let winTop = window - try { - window.top.location.toString() - winTop = window.top - } catch (e) { utils.logMessage(e) } - - const location = utils.getTopWindowLocation() - const placements = [] - - for (let i = 0; i < validBidRequests.length; i++) { - const p = validBidRequests[i] - - placements.push({ - placementId: p.params.placementId, - bidId: p.bidId, - traffic: p.params.traffic || BANNER - }) - } - - return { - method: 'POST', - url: URL, - data: { - deviceWidth: winTop.screen.width, - deviceHeight: winTop.screen.height, - language: (navigator && navigator.language) ? navigator.language : '', - secure: +(location.protocol === 'https:'), - host: location.host, - page: location.pathname, - placements: placements - } - } - }, - - interpretResponse: function (opts) { - const body = opts.body - const response = [] - - for (let i = 0; i < body.length; i++) { - const item = body[i] - if (isBidResponseValid(item)) { - delete item.mediaType - response.push(item) - } - } - - return response - }, - - getUserSyncs: function (syncOptions, serverResponses) { - return [{ type: 'image', url: URL_SYNC }] - } -} - -registerBidder(spec) - -function isBidResponseValid (bid) { - if (!bid.requestId || !bid.cpm || !bid.creativeId || - !bid.ttl || !bid.currency) { - return false - } - switch (bid['mediaType']) { - case BANNER: - return Boolean(bid.width && bid.height && bid.ad) - case VIDEO: - return Boolean(bid.vastUrl) - case NATIVE: - return Boolean(bid.title && bid.image && bid.impressionTrackers) - default: - return false - } -} diff --git a/modules/deepintentBidAdapter.js b/modules/deepintentBidAdapter.js new file mode 100644 index 00000000000..c4dc23cf912 --- /dev/null +++ b/modules/deepintentBidAdapter.js @@ -0,0 +1,181 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; +const BIDDER_CODE = 'deepintent'; +const BIDDER_ENDPOINT = 'https://prebid.deepintent.com/prebid'; +const USER_SYNC_URL = 'https://cdn.deepintent.com/syncpixel.html'; +const DI_M_V = '1.0.0'; +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + aliases: [], + + // tagId is mandatory param + isBidRequestValid: bid => { + let valid = false; + if (bid && bid.params && bid.params.tagId) { + if (typeof bid.params.tagId === 'string' || bid.params.tagId instanceof String) { + valid = true; + } + } + return valid; + }, + interpretResponse: function(bidResponse, request) { + let responses = []; + if (bidResponse && bidResponse.body) { + let bids = bidResponse.body.seatbid && bidResponse.body.seatbid[0] ? bidResponse.body.seatbid[0].bid : []; + responses = bids.map(bid => formatResponse(bid)) + } + return responses; + }, + buildRequests: function (validBidRequests, bidderRequest) { + var user = validBidRequests.map(bid => buildUser(bid)); + clean(user); + const openRtbBidRequest = { + id: utils.generateUUID(), + at: 1, + imp: validBidRequests.map(bid => buildImpression(bid)), + site: buildSite(bidderRequest), + device: buildDevice(), + user: user && user.length === 1 ? user[0] : {} + }; + + if (bidderRequest && bidderRequest.uspConsent) { + utils.deepSetValue(openRtbBidRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + + if (bidderRequest && bidderRequest.gdprConsent) { + utils.deepSetValue(openRtbBidRequest, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + utils.deepSetValue(openRtbBidRequest, 'regs.ext.gdpr', (bidderRequest.gdprConsent.gdprApplies ? 1 : 0)); + } + + return { + method: 'POST', + url: BIDDER_ENDPOINT, + data: JSON.stringify(openRtbBidRequest), + options: { + contentType: 'application/json' + } + }; + }, + /** + * Register User Sync. + */ + getUserSyncs: syncOptions => { + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: USER_SYNC_URL + }]; + } + } + +}; +function clean(obj) { + for (let propName in obj) { + if (obj[propName] === null || obj[propName] === undefined) { + delete obj[propName]; + } + } +} + +function formatResponse(bid) { + return { + requestId: bid && bid.impid ? bid.impid : undefined, + cpm: bid && bid.price ? bid.price : 0.0, + width: bid && bid.w ? bid.w : 0, + height: bid && bid.h ? bid.h : 0, + ad: bid && bid.adm ? bid.adm : '', + creativeId: bid && bid.crid ? bid.crid : undefined, + netRevenue: false, + currency: bid && bid.cur ? bid.cur : 'USD', + ttl: 300, + dealId: bid && bid.dealId ? bid.dealId : undefined + } +} + +function buildImpression(bid) { + return { + id: bid.bidId, + tagid: bid.params.tagId || '', + secure: window.location.protocol === 'https' ? 1 : 0, + banner: buildBanner(bid), + displaymanager: 'di_prebid', + displaymanagerver: DI_M_V, + ext: buildCustomParams(bid) + }; +} +function buildCustomParams(bid) { + if (bid.params && bid.params.custom) { + return { + deepintent: bid.params.custom + + } + } else { + return {} + } +} +function buildUser(bid) { + if (bid && bid.params && bid.params.user) { + return { + id: bid.params.user.id && typeof bid.params.user.id == 'string' ? bid.params.user.id : undefined, + buyeruid: bid.params.user.buyeruid && typeof bid.params.user.buyeruid == 'string' ? bid.params.user.buyeruid : undefined, + yob: bid.params.user.yob && typeof bid.params.user.yob == 'number' ? bid.params.user.yob : null, + gender: bid.params.user.gender && typeof bid.params.user.gender == 'string' ? bid.params.user.gender : undefined, + keywords: bid.params.user.keywords && typeof bid.params.user.keywords == 'string' ? bid.params.user.keywords : undefined, + customdata: bid.params.user.customdata && typeof bid.params.user.customdata == 'string' ? bid.params.user.customdata : undefined + } + } +} + +function buildBanner(bid) { + if (utils.deepAccess(bid, 'mediaTypes.banner')) { + // Get Sizes from MediaTypes Object, Will always take first size, will be overrided by params for exact w,h + if (utils.deepAccess(bid, 'mediaTypes.banner.sizes') && !bid.params.height && !bid.params.width) { + let sizes = utils.deepAccess(bid, 'mediaTypes.banner.sizes'); + if (utils.isArray(sizes) && sizes.length > 0) { + return { + h: sizes[0][1], + w: sizes[0][0], + pos: bid && bid.params && bid.params.pos ? bid.params.pos : 0 + } + } + } else { + return { + h: bid.params.height, + w: bid.params.width, + pos: bid && bid.params && bid.params.pos ? bid.params.pos : 0 + } + } + } +} + +function buildSite(bidderRequest) { + let site = {}; + if (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { + site.page = bidderRequest.refererInfo.referer; + site.domain = getDomain(bidderRequest.refererInfo.referer); + } + return site; +} + +function getDomain(referer) { + if (referer) { + let domainA = document.createElement('a'); + domainA.href = referer; + return domainA.hostname; + } +} + +function buildDevice() { + return { + ua: navigator.userAgent, + js: 1, + dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack === '1') ? 1 : 0, + h: screen.height, + w: screen.width, + language: navigator.language + } +} + +registerBidder(spec); diff --git a/modules/deepintentBidAdapter.md b/modules/deepintentBidAdapter.md new file mode 100644 index 00000000000..79a6a1679e2 --- /dev/null +++ b/modules/deepintentBidAdapter.md @@ -0,0 +1,54 @@ +# Overview + +``` +Module Name: Deepintent Bidder Adapter +Module Type: Bidder Adapter +Maintainer: prebid@deepintent.com +``` + +# Description + +Deepintent currently supports the BANNER type ads through prebid js + +Module that connects to Deepintent's demand sources. + +# Banner Test Request +``` + var adUnits = [ + { + code: 'di_adUnit1', + mediaTypes: { + banner: { + sizes: [[300, 250]], // a display size, only first one will be picked up since multiple ad sizes are not supported yet + } + } + bids: [ + { + bidder: 'deepintent', + params: { + tagId: '1300', // Required parameter + w: 300, // Width and Height here will override sizes in mediatype + h: 250, + pos: 1, + custom: { // Custom parameters in form of key value pairs + user_min_age: 18 + } + } + } + ] + } + ]; +``` + +###Recommended User Sync Configuration + +```javascript +pbjs.setConfig({ + userSync: { + iframeEnabled: true, + enabledBidders: ['deepintent'], + syncDelay: 3000 + }}); + + +``` diff --git a/modules/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js index d8cd6e099ee..71a8471d554 100644 --- a/modules/dfpAdServerVideo.js +++ b/modules/dfpAdServerVideo.js @@ -2,11 +2,12 @@ * This module adds [DFP support]{@link https://www.doubleclickbygoogle.com/} for Video to Prebid. */ -import { registerVideoSupport } from '../src/adServerManager'; -import { targeting } from '../src/targeting'; -import { formatQS, format as buildUrl, parse } from '../src/url'; -import { deepAccess, isEmpty, logError, parseSizesInput } from '../src/utils'; -import { config } from '../src/config'; +import { registerVideoSupport } from '../src/adServerManager.js'; +import { targeting } from '../src/targeting.js'; +import { deepAccess, isEmpty, logError, parseSizesInput, formatQS, parseUrl, buildUrl } from '../src/utils.js'; +import { config } from '../src/config.js'; +import { getHook, submodule } from '../src/hook.js'; +import { auctionManager } from '../src/auctionManager.js'; /** * @typedef {Object} DfpVideoParams @@ -45,6 +46,8 @@ const defaultParamConstants = { unviewed_position_start: 1, }; +export const adpodUtils = {}; + /** * Merge all the bid data and publisher-supplied options into a single URL, and then return it. * @@ -56,9 +59,9 @@ const defaultParamConstants = { * (or the auction's winning bid for this adUnit, if undefined) compete alongside the rest of the * demand in DFP. */ -export default function buildDfpVideoUrl(options) { +export function buildDfpVideoUrl(options) { if (!options.params && !options.url) { - logError(`A params object or a url is required to use pbjs.adServers.dfp.buildVideoUrl`); + logError(`A params object or a url is required to use $$PREBID_GLOBAL$$.adServers.dfp.buildVideoUrl`); return; } @@ -70,7 +73,7 @@ export default function buildDfpVideoUrl(options) { if (options.url) { // when both `url` and `params` are given, parsed url will be overwriten // with any matching param components - urlComponents = parse(options.url, {noDecodeWholeURL: true}); + urlComponents = parseUrl(options.url, {noDecodeWholeURL: true}); if (isEmpty(options.params)) { return buildUrlFromAdserverUrlComponents(urlComponents, bid, options); @@ -97,12 +100,98 @@ export default function buildDfpVideoUrl(options) { return buildUrl({ protocol: 'https', - host: 'pubads.g.doubleclick.net', + host: 'securepubads.g.doubleclick.net', pathname: '/gampad/ads', search: queryParams }); } +export function notifyTranslationModule(fn) { + fn.call(this, 'dfp'); +} + +getHook('registerAdserver').before(notifyTranslationModule); + +/** + * @typedef {Object} DfpAdpodOptions + * + * @param {string} code Ad Unit code + * @param {Object} params Query params which should be set on the DFP request. + * These will override this module's defaults whenever they conflict. + * @param {function} callback Callback function to execute when master tag is ready + */ + +/** + * Creates master tag url for long-form + * @param {DfpAdpodOptions} options + * @returns {string} A URL which calls DFP with custom adpod targeting key values to compete with rest of the demand in DFP + */ +export function buildAdpodVideoUrl({code, params, callback} = {}) { + if (!params || !callback) { + logError(`A params object and a callback is required to use pbjs.adServers.dfp.buildAdpodVideoUrl`); + return; + } + + const derivedParams = { + correlator: Date.now(), + sz: getSizeForAdUnit(code), + url: encodeURIComponent(location.href), + }; + + function getSizeForAdUnit(code) { + let adUnit = auctionManager.getAdUnits() + .filter((adUnit) => adUnit.code === code) + let sizes = deepAccess(adUnit[0], 'mediaTypes.video.playerSize'); + return parseSizesInput(sizes).join('|'); + } + + adpodUtils.getTargeting({ + 'codes': [code], + 'callback': createMasterTag + }); + + function createMasterTag(err, targeting) { + if (err) { + callback(err, null); + return; + } + + let initialValue = { + [adpodUtils.TARGETING_KEY_PB_CAT_DUR]: undefined, + [adpodUtils.TARGETING_KEY_CACHE_ID]: undefined + } + let customParams = {}; + if (targeting[code]) { + customParams = targeting[code].reduce((acc, curValue) => { + if (Object.keys(curValue)[0] === adpodUtils.TARGETING_KEY_PB_CAT_DUR) { + acc[adpodUtils.TARGETING_KEY_PB_CAT_DUR] = (typeof acc[adpodUtils.TARGETING_KEY_PB_CAT_DUR] !== 'undefined') ? acc[adpodUtils.TARGETING_KEY_PB_CAT_DUR] + ',' + curValue[adpodUtils.TARGETING_KEY_PB_CAT_DUR] : curValue[adpodUtils.TARGETING_KEY_PB_CAT_DUR]; + } else if (Object.keys(curValue)[0] === adpodUtils.TARGETING_KEY_CACHE_ID) { + acc[adpodUtils.TARGETING_KEY_CACHE_ID] = curValue[adpodUtils.TARGETING_KEY_CACHE_ID] + } + return acc; + }, initialValue); + } + + let encodedCustomParams = encodeURIComponent(formatQS(customParams)); + + const queryParams = Object.assign({}, + defaultParamConstants, + derivedParams, + params, + { cust_params: encodedCustomParams } + ); + + const masterTag = buildUrl({ + protocol: 'https', + host: 'securepubads.g.doubleclick.net', + pathname: '/gampad/ads', + search: queryParams + }); + + callback(null, masterTag); + } +} + /** * Builds a video url from a base dfp video url and a winning bid, appending * Prebid-specific key-values. @@ -170,5 +259,9 @@ function getCustParams(bid, options) { } registerVideoSupport('dfp', { - buildVideoUrl: buildDfpVideoUrl + buildVideoUrl: buildDfpVideoUrl, + buildAdpodVideoUrl: buildAdpodVideoUrl, + getAdpodTargeting: (args) => adpodUtils.getTargeting(args) }); + +submodule('adpod', adpodUtils); diff --git a/modules/dgadsBidAdapter.js b/modules/dgadsBidAdapter.js deleted file mode 100644 index c8a97d86990..00000000000 --- a/modules/dgadsBidAdapter.js +++ /dev/null @@ -1,103 +0,0 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; -import * as utils from '../src/utils'; -import { BANNER, NATIVE } from '../src/mediaTypes'; - -const BIDDER_CODE = 'dgads'; -const UID_NAME = 'dgads_uid'; -const ENDPOINT = 'https://ads-tr.bigmining.com/ad/p/bid'; - -export const spec = { - code: BIDDER_CODE, - supportedMediaTypes: [ BANNER, NATIVE ], - isBidRequestValid: function(bid) { - const params = bid.params; - if (!/^\d+$/.test(params.location_id)) { - return false; - } - if (!/^\d+$/.test(params.site_id)) { - return false; - } - return true; - }, - buildRequests: function(bidRequests) { - if (bidRequests.length === 0) { - return {}; - } - - return bidRequests.map(bidRequest => { - const params = bidRequest.params; - const data = {}; - - data['_loc'] = params.location_id; - data['_medium'] = params.site_id; - data['transaction_id'] = bidRequest.transactionId; - data['bid_id'] = bidRequest.bidId; - data['referer'] = utils.getTopWindowUrl(); - data['_uid'] = getCookieUid(UID_NAME); - - return { - method: 'GET', - url: ENDPOINT, - data, - }; - }); - }, - interpretResponse: function(serverResponse, bidRequest) { - const bidResponses = []; - const responseObj = serverResponse.body; - const ads = responseObj.bids; - let bidResponse = {}; - if (utils.isEmpty(ads)) { - return []; - } - utils._each(ads, function(ad) { - bidResponse.requestId = ad.bidId; - bidResponse.bidderCode = BIDDER_CODE; - bidResponse.cpm = ad.cpm; - bidResponse.creativeId = ad.creativeId; - bidResponse.currency = 'JPY'; - bidResponse.netRevenue = true; - bidResponse.ttl = ad.ttl; - bidResponse.referrer = utils.getTopWindowUrl(); - if (ad.isNative == 1) { - bidResponse.mediaType = NATIVE; - bidResponse.native = setNativeResponse(ad); - } else { - bidResponse.width = parseInt(ad.w); - bidResponse.height = parseInt(ad.h); - bidResponse.ad = ad.ad; - } - bidResponses.push(bidResponse); - }); - return bidResponses; - } -}; -function setNativeResponse(ad) { - let nativeResponce = {}; - nativeResponce.image = { - url: ad.image, - width: parseInt(ad.w), - height: parseInt(ad.h) - } - nativeResponce.title = ad.title; - nativeResponce.body = ad.desc; - nativeResponce.sponsoredBy = ad.sponsoredBy; - nativeResponce.clickUrl = ad.clickUrl; - nativeResponce.clickTrackers = ad.clickTrackers || []; - nativeResponce.impressionTrackers = ad.impressionTrackers || []; - return nativeResponce; -} -export function getCookieUid(uidName) { - if (utils.cookiesAreEnabled()) { - let cookies = document.cookie.split(';'); - for (let i = 0; i < cookies.length; i++) { - let value = cookies[i].split('='); - if (value[0].indexOf(uidName) > -1) { - return value[1]; - } - } - } - return ''; -} - -registerBidder(spec); diff --git a/modules/digiTrustIdSystem.js b/modules/digiTrustIdSystem.js new file mode 100644 index 00000000000..d8aa8be9376 --- /dev/null +++ b/modules/digiTrustIdSystem.js @@ -0,0 +1,460 @@ +/** + * This module adds DigiTrust ID support to the User ID module + * The {@link module:modules/userId} module is required + * If the full DigiTrust Id library is included the standard functions + * will be invoked to obtain the user's DigiTrust Id. + * When the full library is not included this will fall back to the + * DigiTrust Identity API and generate a mock DigiTrust object. + * @module modules/digiTrustIdSystem + * @requires module:modules/userId + */ + +import * as utils from '../src/utils.js' +import { ajax } from '../src/ajax.js'; +import { submodule } from '../src/hook.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const DT_VENDOR_ID = 64; // cmp gvlVendorId +const storage = getStorageManager(DT_VENDOR_ID); + +var fallbackTimeout = 1550; // timeout value that allows userId system to execute first +var fallbackTimer = 0; // timer Id for fallback init so we don't double call + +/** + * Checks to see if the DigiTrust framework is initialized. + * @function + */ +function isInitialized() { + if (window.DigiTrust == null) { + return false; + } + // eslint-disable-next-line no-undef + return DigiTrust.isClient; // this is set to true after init +} + +/** + * Tests for presence of the DigiTrust object + * */ +function isPresent() { + return (window.DigiTrust != null); +} + +var noop = function () { +}; + +const MAX_RETRIES = 2; +const DT_ID_SVC = 'https://prebid.digitru.st/id/v1'; + +var isFunc = function (fn) { + return typeof (fn) === 'function'; +} + +var _savedId = null; // closure variable for storing Id to avoid additional requests + +function callApi(options) { + var ajaxOptions = { + method: 'GET', + withCredentials: true + }; + + ajax( + DT_ID_SVC, + { + success: options.success, + error: options.fail + }, + null, + ajaxOptions + ); +} + +/** + * Encode the Id per DigiTrust lib + * @param {any} id + */ +function encId(id) { + try { + if (typeof (id) !== 'string') { + id = JSON.stringify(id); + } + return btoa(id); + } catch (ex) { + return id; + } +} + +/** + * Writes the Identity into the expected DigiTrust cookie + * @param {any} id + */ +function writeDigiId(id) { + var key = 'DigiTrust.v1.identity'; + var date = new Date(); + date.setTime(date.getTime() + 604800000); + storage.setCookie(key, encId(id), date.toUTCString(), 'none'); +} + +/** + * Tests to see if the current browser is FireFox + */ +function isFirefoxBrowser(ua) { + ua = ua || navigator.userAgent; + ua = ua.toLowerCase(); + if (ua.indexOf('firefox') !== -1) { + return true; + } + return false; +} + +/** + * Test to see if the user has a browser that is disallowed for making AJAX + * requests due to the behavior not supported DigiTrust ID Cookie. + */ +function isDisallowedBrowserForApiCall() { + if (utils.isSafariBrowser()) { + return true; + } else if (isFirefoxBrowser()) { + return true; + } + return false; +} + +/** + * Set up a DigiTrust facade object to mimic the API + * + */ +function initDigitrustFacade(config) { + clearTimeout(fallbackTimer); + fallbackTimer = 0; + + var facade = { + isClient: true, + isMock: true, + _internals: { + callCount: 0, + initCallback: null + }, + getUser: function (obj, callback) { + var isAsync = !!isFunc(callback); + var cb = isAsync ? callback : noop; + var errResp = { success: false }; + var inter = facade._internals; + inter.callCount++; + + // wrap the initializer callback, if present + var checkAndCallInitializeCb = function (idResponse) { + if (inter.callCount <= 1 && isFunc(inter.initCallback)) { + try { + inter.initCallback(idResponse); + } catch (ex) { + utils.logError('Exception in passed DigiTrust init callback', ex); + } + } + } + + if (!isMemberIdValid(obj.member)) { + if (!isAsync) { + return errResp + } else { + cb(errResp); + return; + } + } + + if (_savedId != null) { + if (isAsync) { + checkAndCallInitializeCb(_savedId); + // cb(_savedId); + return; + } else { + return _savedId; + } + } + + var opts = { + success: function (respText, result) { + var idResult = { + success: true + } + try { + idResult.identity = JSON.parse(respText); + _savedId = idResult; // Save result to the cache variable + writeDigiId(respText); + } catch (ex) { + idResult.success = false; + delete idResult.identity; + } + checkAndCallInitializeCb(idResult); + }, + fail: function (statusErr, result) { + utils.logError('DigiTrustId API error: ' + statusErr); + } + } + + // check gdpr vendor here. Full DigiTrust library has vendor check built in + gdprConsent.hasConsent(null, function (hasConsent) { + if (hasConsent) { + if (isDisallowedBrowserForApiCall()) { + let resultObj = { + success: false, + err: 'Your browser does not support DigiTrust Identity' + } + checkAndCallInitializeCb(resultObj); + return; + } + callApi(opts); + } + }) + + if (!isAsync) { + return errResp; // even if it will be successful later, without a callback we report a "failure in this moment" + } + } + } + + if (config && isFunc(config.callback)) { + facade._internals.initCallback = config.callback; + } + + if (window && window.DigiTrust == null) { + window.DigiTrust = facade; + } +} + +/** + * Tests to see if a member ID is valid within facade + * @param {any} memberId + */ +var isMemberIdValid = function (memberId) { + if (memberId && memberId.length > 0) { + return true; + } else { + utils.logError('[DigiTrust Prebid Client Error] Missing member ID, add the member ID to the function call options'); + return false; + } +}; + +/** + * DigiTrust consent handler for GDPR and __cmp. + * */ +var gdprConsent = { + hasConsent: function (options, consentCb) { + options = options || { consentTimeout: 1500 }; + var stopTimer; + var processed = false; + var consentAnswer = false; + if (typeof (window.__cmp) !== 'undefined') { + stopTimer = setTimeout(function () { + consentAnswer = false; + processed = true; + consentCb(consentAnswer); + }, options.consentTimeout); + + window.__cmp('ping', null, function(pingAnswer) { + if (pingAnswer.gdprAppliesGlobally) { + window.__cmp('getVendorConsents', [DT_VENDOR_ID], function (result) { + if (processed) { return; } // timeout before cmp answer, cancel + clearTimeout(stopTimer); + var myconsent = result.vendorConsents[DT_VENDOR_ID]; + consentCb(myconsent); + }); + } else { + if (processed) { return; } // timeout before cmp answer, cancel + clearTimeout(stopTimer); + consentAnswer = true; + consentCb(consentAnswer); + } + }); + } else { + // __cmp library is not preset. + // ignore this check and rely on id system GDPR consent management + consentAnswer = true; + consentCb(consentAnswer); + } + } +} + +/** + * Encapsulation of needed info for the callback return. + * + * @param {any} opts + */ +var ResultWrapper = function (opts) { + var me = this; + this.idObj = null; + + var idSystemFn = null; + + /** + * Callback method that is passed back to the userId module. + * + * @param {function} callback + */ + this.userIdCallback = function (callback) { + idSystemFn = callback; + if (me.idObj == null) { + me.idObj = _savedId; + } + + if (me.idObj != null && isFunc(callback)) { + callback(wrapIdResult()); + } + } + + /** + * Return a wrapped result formatted for userId system + */ + function wrapIdResult() { + if (me.idObj == null) { + me.idObj = _savedId; + } + + if (me.idObj == null) { + return null; + } + + var cp = me.configParams; + var exp = (cp && cp.storage && cp.storage.expires) || 60; + + var rslt = { + data: null, + expires: exp + }; + if (me.idObj && me.idObj.success && me.idObj.identity) { + rslt.data = me.idObj.identity; + } else { + rslt.err = 'Failure getting id'; + } + + return rslt; + } + + this.retries = 0; + this.retryId = 0; + + this.executeIdRequest = function (configParams) { + // eslint-disable-next-line no-undef + DigiTrust.getUser({ member: 'prebid' }, function (idResult) { + me.idObj = idResult; + var cb = function () { + if (isFunc(idSystemFn)) { + idSystemFn(wrapIdResult()); + } + } + + cb(); + if (configParams && configParams.callback && isFunc(configParams.callback)) { + try { + configParams.callback(idResult); + } catch (ex) { + utils.logError('Failure in DigiTrust executeIdRequest', ex); + } + } + }); + } +} + +// An instance of the result wrapper object. +var resultHandler = new ResultWrapper(); + +/* + * Internal implementation to get the Id and trigger callback + */ +function getDigiTrustId(configParams) { + if (resultHandler.configParams == null) { + resultHandler.configParams = configParams; + } + + // First see if we should initialize DigiTrust framework + if (isPresent() && !isInitialized()) { + initializeDigiTrust(configParams); + resultHandler.retryId = setTimeout(function () { + getDigiTrustId(configParams); + }, 100 * (1 + resultHandler.retries++)); + return resultHandler.userIdCallback; + } else if (!isInitialized()) { // Second see if we should build a facade object + if (resultHandler.retries >= MAX_RETRIES) { + initDigitrustFacade(configParams); // initialize a facade object that relies on the AJAX call + resultHandler.executeIdRequest(configParams); + } else { + // use expanding envelope + if (resultHandler.retryId != 0) { + clearTimeout(resultHandler.retryId); + } + resultHandler.retryId = setTimeout(function () { + getDigiTrustId(configParams); + }, 100 * (1 + resultHandler.retries++)); + } + return resultHandler.userIdCallback; + } else { // Third get the ID + resultHandler.executeIdRequest(configParams); + return resultHandler.userIdCallback; + } +} + +function initializeDigiTrust(config) { + utils.logInfo('Digitrust Init'); + var dt = window.DigiTrust; + if (dt && !dt.isClient && config != null) { + dt.initialize(config.init, config.callback); + } else if (dt == null) { + // Assume we are already on a delay and DigiTrust is not on page + initDigitrustFacade(config); + } +} + +var testHook = {}; + +/** + * Exposes the test hook object by attaching to the digitrustIdModule. + * This method is called in the unit tests to surface internals. + */ +export function surfaceTestHook() { + digiTrustIdSubmodule['_testHook'] = testHook; + return testHook; +} + +testHook.initDigitrustFacade = initDigitrustFacade; // expose for unit tests +testHook.gdpr = gdprConsent; + +/** @type {Submodule} */ +export const digiTrustIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: 'digitrust', + /** + * decode the stored id value for passing to bid requests + * @function + * @param {string} value + * @returns {{pubcid:string}} + */ + decode: function (idData) { + try { + return { 'digitrustid': idData }; + } catch (e) { + utils.logError('DigiTrust ID submodule decode error'); + } + }, + getId: function (configParams) { + return {callback: getDigiTrustId(configParams)}; + }, + _testInit: surfaceTestHook +}; + +// check for fallback init of DigiTrust +function fallbackInit() { + if (resultHandler.retryId == 0 && !isInitialized()) { + // this triggers an init + var conf = { + member: 'fallback', + callback: noop + }; + getDigiTrustId(conf); + } +} + +fallbackTimer = setTimeout(fallbackInit, fallbackTimeout); + +submodule('userId', digiTrustIdSubmodule); diff --git a/modules/digiTrustIdSystem.md b/modules/digiTrustIdSystem.md new file mode 100644 index 00000000000..c0b274d3292 --- /dev/null +++ b/modules/digiTrustIdSystem.md @@ -0,0 +1,156 @@ +## DigiTrust Universal Id Integration + +Setup +----- +The DigiTrust Id integration for Prebid may be used with or without the full +DigiTrust library. This is an optional module that must be used in conjunction +with the userId module. + +See the [Prebid Integration Guide for DigiTrust](https://github.com/digi-trust/dt-cdn/wiki/Prebid-Integration-for-DigiTrust-Id) +and the [DigiTrust wiki](https://github.com/digi-trust/dt-cdn/wiki) +for further instructions. + + +## Example Prebid Configuration for Digitrust Id +``` + pbjs.que.push(function() { + pbjs.setConfig({ + usersync: { + userIds: [{ + name: "digitrust", + params: { + init: { + member: 'example_member_id', + site: 'example_site_id' + }, + callback: function (digiTrustResult) { + // This callback method is optional and used for error handling + // in many if not most cases. + /* + if (digiTrustResult.success) { + // Success in Digitrust init; + // 'DigiTrust Id (encrypted): ' + digiTrustResult.identity.id; + } + else { + // Digitrust init failed + } + */ + } + }, + storage: { + type: "html5", + name: "pbjsdigitrust", + expires: 60 + } + }] + } + }); + pbjs.addAdUnits(adUnits); + pbjs.requestBids({ + bidsBackHandler: sendAdserverRequest + }); + }); + +``` + + +## Building Prebid with DigiTrust Support +Your Prebid build must include the modules for both **userId** and **digitrustIdLoader**. Follow the build instructions for Prebid as +explained in the top level README.md file of the Prebid source tree. + +ex: $ gulp build --modules=userId,digitrustIdLoader + +### Step by step Prebid build instructions for DigiTrust + +1. Download the Prebid source from [Prebid Git Repo](https://github.com/prebid/Prebid.js) +2. Set up your environment as outlined in the [Readme File](https://github.com/prebid/Prebid.js/blob/master/README.md#Build) +3. Execute the build command either with all modules or with the `userId` and `digitrustIdLoader` modules. + ``` + $ gulp build --modules=userId,digitrustIdLoader + ``` +4. (Optional) Concatenate the DigiTrust source code to the end of your `prebid.js` file for a single source distribution. +5. Upload the resulting source file to your CDN. + + +## Deploying Prebid with DigiTrust ID support +**Precondition:** You must be a DigiTrust member and have registered through the [DigiTrust Signup Process](http://www.digitru.st/signup/). +Your assigned publisher ID will be required in the configuration settings for all deployment scenarios. + +There are three supported approaches to deploying the Prebid-integrated DigiTrust package: + +* "Bare bones" deployment using only the integrated DigiTrust module code. +* Full DigiTrust with CDN referenced DigiTrust.js library. +* Full DigiTrust packaged with Prebid or site js. + +### Bare Bones Deployment + +This deployment results in the smallest Javascript package and is the simplest deployment. +It is appropriate for testing or deployments where simplicity is key. This approach +utilizes the REST API for ID generation. While there is less Javascript in use, +the user may experience more network requests than the scenarios that include the full +DigiTrust library. + +1. Build your Prebid package as above, skipping step 4. +2. Add the DigiTrust initializer section to your Prebid initialization object as below, + using your Member ID and Site ID. +3. Add a reference to your Prebid package and the initialization code on all pages you wish + to utilize Prebid with integrated DigiTrust ID. + + + + +### Full DigiTrust with CDN referenced DigiTrust library + +Both "Full DigiTrust" deployments will result in a larger initial Javascript payload. +The end user may experience fewer overall network requests as the encrypted and anonymous +DigiTrust ID can often be generated fully in client-side code. Utilizing the CDN reference +to the official DigiTrust distribution insures you will be running the latest version of the library. + +The Full DigiTrust deployment is designed to work with both new DigiTrust with Prebid deployments, and with +Prebid deployments by existing DigiTrust members. This allows you to migrate your code more slowly +without losing DigiTrust support in the process. + +1. Deploy your built copy of `prebid.js` to your CDN. +2. On each page reference both your `prebid.js` and a copy of the **DigiTrust** library. + This may either be a copy downloaded from the [DigiTrust CDN](https://cdn.digitru.st/prod/1/digitrust.min.js) to your CDN, + or directly referenced from the URL https://cdn.digitru.st/prod/1/digitrust.min.js. These may be added to the page in any order. +3. Add a configuration section for Prebid that includes the `usersync` settings and the `digitrust` settings. + +### Full DigiTrust packaged with Prebid + + +1. Deploy your built copy of `prebid.js` to your CDN. Be sure to perform *Step 4* of the build to concatenate or + integrate the full DigiTrust library code with your Prebid package. +2. On each page reference your `prebid.js` +3. Add a configuration section for Prebid that includes the `usersync` settings and the `digitrust` settings. + This code may also be appended to your Prebid package or placed in other initialization methods. + + + +## Parameter Descriptions for the `usersync` Configuration Section +The below parameters apply only to the DigiTrust ID integration. + +| Param under usersync.userIds[] | Scope | Type | Description | Example | +| --- | --- | --- | --- | --- | +| name | Required | String | ID value for the DigiTrust module - `"digitrust"` | `"digitrust"` | +| params | Required | Object | Details for DigiTrust initialization. | | +| params.init | Required | Object | Initialization parameters, including the DigiTrust Publisher ID and Site ID. | | +| params.init.member | Required | String | DigiTrust Publisher Id | "A897dTzB" | +| params.init.site | Required | String | DigiTrust Site Id | "MM2123" | +| params.callback | Optional | Function | Callback method to fire after initialization of the DigiTrust framework. The argument indicates failure and success and the identity object upon success. | | +| storage | Required | Object | The publisher must specify the local storage in which to store the results of the call to get the user ID. This can be either cookie or HTML5 storage. | | +| storage.type | Required | String | This is where the results of the user ID will be stored. The recommended method is `localStorage` by specifying `html5`. | `"html5"` | +| storage.name | Required | String | The name of the cookie or html5 local storage where the user ID will be stored. | `"pbjsdigitrust"` | +| storage.expires | Optional | Integer | How long (in days) the user ID information will be stored. Default is 30 for UnifiedId and 1825 for PubCommonID | `365` | +| value | Optional | Object | Used only if the page has a separate mechanism for storing the Unified ID. The value is an object containing the values to be sent to the adapters. In this scenario, no URL is called and nothing is added to local storage | `{"tdid": "D6885E90-2A7A-4E0F-87CB-7734ED1B99A3"}` | + + + +## Further Reading + ++ [DigiTrust Home Page](http://digitru.st) + ++ [DigiTrust integration guide](https://github.com/digi-trust/dt-cdn/wiki/Integration-Guide) + ++ [DigiTrust ID Encryption](https://github.com/digi-trust/dt-cdn/wiki/ID-encryption) + diff --git a/modules/districtmDMXBidAdapter.js b/modules/districtmDMXBidAdapter.js index 12b7ac16c0c..03dca0b607d 100644 --- a/modules/districtmDMXBidAdapter.js +++ b/modules/districtmDMXBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import {config} from '../src/config'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; const BIDDER_CODE = 'districtmDMX'; @@ -22,17 +22,19 @@ export const spec = { if (oBid.price < nBid.price) { const bid = matchRequest(nBid.impid, bidRequest); const {width, height} = defaultSize(bid); - nBid.cpm = nBid.price; + nBid.cpm = parseFloat(nBid.price).toFixed(2); nBid.bidId = nBid.impid; nBid.requestId = nBid.impid; nBid.width = nBid.w || width; nBid.height = nBid.h || height; + if (nBid.dealid) { + nBid.dealId = nBid.dealid; + } nBid.ad = nBid.adm; nBid.netRevenue = true; nBid.creativeId = nBid.crid; nBid.currency = 'USD'; nBid.ttl = 60; - return nBid; } else { oBid.cpm = oBid.price; @@ -60,6 +62,7 @@ export const spec = { }, buildRequests(bidRequest, bidderRequest) { let timeout = config.getConfig('bidderTimeout'); + let schain = null; let dmxRequest = { id: utils.generateUUID(), cur: ['USD'], @@ -69,6 +72,27 @@ export const spec = { publisher: { id: String(bidRequest[0].params.memberid) || null } } } + + try { + let params = config.getConfig('dmx'); + dmxRequest.user = params.user || {}; + let site = params.site || {}; + dmxRequest.site = {...dmxRequest.site, ...site} + } catch (e) { + + } + + let eids = []; + if (bidRequest && bidRequest.userId) { + bindUserId(eids, utils.deepAccess(bidRequest, `userId.idl_env`), 'liveramp.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest, `userId.digitrustid.data.id`), 'digitru.st', 1); + bindUserId(eids, utils.deepAccess(bidRequest, `userId.id5id`), 'id5-sync.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest, `userId.pubcid`), 'pubcid.org', 1); + bindUserId(eids, utils.deepAccess(bidRequest, `userId.tdid`), 'adserver.org', 1); + dmxRequest.user = dmxRequest.user || {}; + dmxRequest.user.ext = dmxRequest.user.ext || {}; + dmxRequest.user.ext.eids = eids; + } if (!dmxRequest.test) { delete dmxRequest.test; } @@ -80,46 +104,166 @@ export const spec = { dmxRequest.user.ext = {}; dmxRequest.user.ext.consent = bidderRequest.gdprConsent.consentString; } + dmxRequest.regs = dmxRequest.regs || {}; + dmxRequest.regs.coppa = config.getConfig('coppa') === true ? 1 : 0; + if (bidderRequest && bidderRequest.uspConsent) { + dmxRequest.regs = dmxRequest.regs || {}; + dmxRequest.regs.ext = dmxRequest.regs.ext || {}; + dmxRequest.regs.ext.us_privacy = bidderRequest.uspConsent; + } + try { + schain = bidRequest[0].schain; + dmxRequest.source = {}; + dmxRequest.source.ext = {}; + dmxRequest.source.ext.schain = schain || {} + } catch (e) {} let tosendtags = bidRequest.map(dmx => { var obj = {}; obj.id = dmx.bidId; obj.tagid = String(dmx.params.dmxid); - obj.secure = window.location.protocol === 'https:' ? 1 : 0; + obj.secure = 1; obj.banner = { topframe: 1, - w: dmx.sizes[0][0] || 0, - h: dmx.sizes[0][1] || 0, - format: dmx.sizes.map(s => { + w: cleanSizes(dmx.sizes, 'w'), + h: cleanSizes(dmx.sizes, 'h'), + format: cleanSizes(dmx.sizes).map(s => { return {w: s[0], h: s[1]}; }).filter(obj => typeof obj.w === 'number' && typeof obj.h === 'number') }; return obj; }); - dmxRequest.imp = tosendtags; - return { - method: 'POST', - url: DMXURI, - data: JSON.stringify(dmxRequest), - options: { - contentType: 'application/json', - withCredentials: true - }, - bidderRequest + + if (tosendtags.length <= 5) { + dmxRequest.imp = tosendtags; + return { + method: 'POST', + url: DMXURI, + data: JSON.stringify(dmxRequest), + bidderRequest + } + } else { + return upto5(tosendtags, dmxRequest, bidderRequest, DMXURI); } }, test() { return window.location.href.indexOf('dmTest=true') !== -1 ? 1 : 0; }, - getUserSyncs(optionsType) { + getUserSyncs(optionsType, serverResponses, gdprConsent, uspConsent) { + let query = []; + let url = 'https://cdn.districtm.io/ids/index.html' + if (gdprConsent && gdprConsent.gdprApplies && typeof gdprConsent.consentString === 'string') { + query.push(['gdpr', gdprConsent.consentString]) + } + if (uspConsent) { + query.push(['ccpa', uspConsent]) + } + if (query.length > 0) { + url += '?' + query.map(q => q.join('=')).join('&') + } if (optionsType.iframeEnabled) { return [{ type: 'iframe', - url: 'https://cdn.districtm.io/ids/index.html' + url: url }]; } } } +export function cleanSizes(sizes, value) { + const supportedSize = [ + { + size: [300, 250], + s: 100 + }, + { + size: [728, 90], + s: 95 + }, + { + size: [320, 50], + s: 90 + }, + { + size: [160, 600], + s: 88 + }, + { + size: [300, 600], + s: 85 + }, + { + size: [300, 50], + s: 80 + }, + { + size: [970, 250], + s: 75 + }, + { + size: [970, 90], + s: 60 + }, + ]; + let newArray = shuffle(sizes, supportedSize); + switch (value) { + case 'w': + return newArray[0][0] || 0; + case 'h': + return newArray[0][1] || 0; + case 'size': + return newArray; + default: + return newArray; + } +} + +export function shuffle(sizes, list) { + let removeSizes = sizes.filter(size => { + return list.map(l => `${l.size[0]}x${l.size[1]}`).indexOf(`${size[0]}x${size[1]}`) === -1 + }) + let reOrder = sizes.reduce((results, current) => { + if (results.length === 0) { + results.push(current); + return results; + } + results.push(current); + results = list.filter(l => results.map(r => `${r[0]}x${r[1]}`).indexOf(`${l.size[0]}x${l.size[1]}`) !== -1); + results = results.sort(function(a, b) { + return b.s - a.s; + }) + return results.map(r => r.size); + }, []) + return removeDuplicate([...reOrder, ...removeSizes]); +} + +export function removeDuplicate(arrayValue) { + return arrayValue.filter((elem, index) => { + return arrayValue.map(e => `${e[0]}x${e[1]}`).indexOf(`${elem[0]}x${elem[1]}`) === index + }) +} + +export function upto5(allimps, dmxRequest, bidderRequest, DMXURI) { + let start = 0; + let step = 5; + let req = []; + while (allimps.length !== 0) { + if (allimps.length >= 5) { + req.push(allimps.splice(start, step)) + } else { + req.push(allimps.splice(start, allimps.length)) + } + } + return req.map(r => { + dmxRequest.imp = r; + return { + method: 'POST', + url: DMXURI, + data: JSON.stringify(dmxRequest), + bidderRequest + } + }) +} + /** * Function matchRequest(id: string, BidRequest: object) * @param id @@ -152,4 +296,18 @@ export function defaultSize(thebidObj) { returnObject.height = checkDeepArray(sizes)[1]; return returnObject; } + +export function bindUserId(eids, value, source, atype) { + if (utils.isStr(value) && Array.isArray(eids)) { + eids.push({ + source, + uids: [ + { + id: value, + atype + } + ] + }) + } +} registerBidder(spec); diff --git a/modules/districtmDmxBidAdapter.md b/modules/districtmDmxBidAdapter.md index 2859bcfa19d..792cf2e7305 100644 --- a/modules/districtmDmxBidAdapter.md +++ b/modules/districtmDmxBidAdapter.md @@ -13,6 +13,8 @@ The `districtmDmxAdapter` module allows publishers to include DMX Exchange deman * Single Request * Multi-Size Support * GDPR Compliant +* CCPA Compliant +* COPPA Compliant * Bids returned in **NET** ## Media Types @@ -23,8 +25,8 @@ The `districtmDmxAdapter` module allows publishers to include DMX Exchange deman | Key | Scope | Type | Description | --- | --- | --- | --- -| dmxid | Mandatory | Integer | Unique identifier of the placement, dmxid can be obtained in the district m Boost platform. -| memberid | Mandatory | Integer | Unique identifier for your account, memberid can be obtained in the district m Boost platform. +| `dmxid` | Mandatory | Integer | Unique identifier of the placement, dmxid can be obtained in the district m Boost platform. +| `memberid` | Mandatory | Integer | Unique identifier for your account, memberid can be obtained in the district m Boost platform. # Ad Unit Configuration Example @@ -47,6 +49,9 @@ The `districtmDmxAdapter` module allows publishers to include DMX Exchange deman ``` +# Ad Unit Configuration when COPPA is needed + + # Quick Start Guide ###### 1. Including the `districtmDmxAdapter` in your build process. @@ -115,3 +120,25 @@ Our demand and adapter supports multiple sizes per placement, as such a single d ###### 4. Implementation Checking Once the bidder is live in your Prebid configuration you may confirm it is making requests to our end point by looking for requests to `https://dmx.districtm.io/b/v1`. + + +###### 5. Setting first party data + +```code +pbjs.setConfig({ + dmx: { + user: { + 'gender': 'M', + 'yob': 1992, + // keywords example + 'keywords': 'automotive,dodge,engine,car' + + }, + site: { + cat: ['IAB-12'], + pagecat: ['IAB-14'], + sectioncat: ['IAB-24'] + } + } +}); +``` diff --git a/modules/djaxBidAdapter.js b/modules/djaxBidAdapter.js new file mode 100644 index 00000000000..ffaf61a3f15 --- /dev/null +++ b/modules/djaxBidAdapter.js @@ -0,0 +1,129 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import * as utils from '../src/utils.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import { ajax } from '../src/ajax.js'; +import {Renderer} from '../src/Renderer.js'; + +const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; +const BIDDER_CODE = 'djax'; +const DOMAIN = 'https://demo.reviveadservermod.com/headerbidding_adminshare/'; +const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; + +function isBidRequestValid(bid) { + return (typeof bid.params !== 'undefined' && parseInt(utils.getValue(bid.params, 'publisherId')) > 0); +} + +function buildRequests(validBidRequests) { + return { + method: 'POST', + url: DOMAIN + 'www/admin/plugins/Prebid/getAd.php', + options: { + withCredentials: false, + crossOrigin: true + }, + data: validBidRequests, + }; +} + +function interpretResponse(serverResponse, request) { + const response = serverResponse.body; + const bidResponses = []; + var bidRequestResponses = []; + + utils._each(response, function(bidAd) { + bidAd.adResponse = { + content: bidAd.vastXml, + height: bidAd.height, + width: bidAd.width + }; + bidAd.ttl = config.getConfig('_bidderTimeout') + bidAd.renderer = bidAd.context === 'outstream' ? createRenderer(bidAd, { + id: bidAd.adUnitCode, + url: RENDERER_URL + }, bidAd.adUnitCode) : undefined; + bidResponses.push(bidAd); + }); + + bidRequestResponses.push({ + function: 'saveResponses', + request: request, + response: bidResponses + }); + sendResponseToServer(bidRequestResponses); + return bidResponses; +} + +function outstreamRender(bidAd) { + bidAd.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + sizes: [bidAd.width, bidAd.height], + width: bidAd.width, + height: bidAd.height, + targetId: bidAd.adUnitCode, + adResponse: bidAd.adResponse, + rendererOptions: { + showVolume: false, + allowFullscreen: false + } + }); + }); +} + +function createRenderer(bidAd, rendererParams, adUnitCode) { + const renderer = Renderer.install({ + id: rendererParams.id, + url: rendererParams.url, + loaded: false, + config: {'player_height': bidAd.height, 'player_width': bidAd.width}, + adUnitCode + }); + try { + renderer.setRender(outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on renderer', err); + } + return renderer; +} + +function onBidWon(bid) { + let wonBids = []; + wonBids.push(bid); + wonBids[0].function = 'onBidWon'; + sendResponseToServer(wonBids); +} + +function onTimeout(details) { + details.unshift({ 'function': 'onTimeout' }); + sendResponseToServer(details); +} + +function sendResponseToServer(data) { + ajax(DOMAIN + 'www/admin/plugins/Prebid/tracking/track.php', null, JSON.stringify(data), { + withCredentials: false, + method: 'POST', + crossOrigin: true + }); +} + +function getUserSyncs(syncOptions) { + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: DOMAIN + 'www/admin/plugins/Prebid/userSync.php' + }]; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: SUPPORTED_AD_TYPES, + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs, + onBidWon, + onTimeout +}; + +registerBidder(spec); diff --git a/modules/djaxBidAdapter.md b/modules/djaxBidAdapter.md new file mode 100644 index 00000000000..d597eb59b58 --- /dev/null +++ b/modules/djaxBidAdapter.md @@ -0,0 +1,50 @@ +# Overview + +``` +Module Name: djax Bid Adapter +Module Type: Bidder Adapter +Maintainer : support@djaxtech.com +``` + +# Description + +Connects to Djax Ad Server for bids. + +djax bid adapter supports Banner and Video. + +# Test Parameters +``` + var adUnits = [ + //bannner object + { + code: 'banner-ad-slot', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]], + } + }, + bids: [{ + bidder: 'djax', + params: { + publisherId: 2 + } + }] + + }, + //video object + { + code: 'video-ad-slot', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480], + }, + }, + bids: [{ + bidder: "djax", + params: { + publisherId: 2 + } + }] + }]; +``` \ No newline at end of file diff --git a/modules/dspxBidAdapter.js b/modules/dspxBidAdapter.js index 8b763202b7c..d05549601e1 100644 --- a/modules/dspxBidAdapter.js +++ b/modules/dspxBidAdapter.js @@ -1,50 +1,94 @@ -import * as utils from '../src/utils'; -import {config} from '../src/config'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; const BIDDER_CODE = 'dspx'; const ENDPOINT_URL = 'https://buyer.dspx.tv/request/'; +const ENDPOINT_URL_DEV = 'https://dcbuyer.dspx.tv/request/'; +const DEFAULT_VAST_FORMAT = 'vast2'; export const spec = { code: BIDDER_CODE, aliases: ['dspx'], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: function(bid) { return !!(bid.params.placement); }, buildRequests: function(validBidRequests, bidderRequest) { return validBidRequests.map(bidRequest => { const params = bidRequest.params; - const sizes = utils.parseSizesInput(bidRequest.sizes)[0]; - const width = sizes.split('x')[0]; - const height = sizes.split('x')[1]; - const placementId = params.placement; + const videoData = utils.deepAccess(bidRequest, 'mediaTypes.video') || {}; + const sizes = utils.parseSizesInput(videoData.playerSize || bidRequest.sizes)[0]; + const [width, height] = sizes.split('x'); + + const placementId = params.placement; const rnd = Math.floor(Math.random() * 99999999999); - const referrer = encodeURIComponent(bidderRequest.refererInfo.referer); + const referrer = bidderRequest.refererInfo.referer; const bidId = bidRequest.bidId; - const payload = { - _f: 'html', - alternative: 'prebid_js', - inventory_item_id: placementId, - srw: width, - srh: height, - idt: 100, - rnd: rnd, - ref: referrer, - bid_id: bidId, - }; + const isDev = params.devMode || false; + + let endpoint = isDev ? ENDPOINT_URL_DEV : ENDPOINT_URL; + let payload = {}; + + if (isVideoRequest(bidRequest)) { + let vastFormat = params.vastFormat || DEFAULT_VAST_FORMAT; + payload = { + _f: vastFormat, + alternative: 'prebid_js', + inventory_item_id: placementId, + srw: width, + srh: height, + idt: 100, + rnd: rnd, + ref: referrer, + bid_id: bidId, + }; + } else { + payload = { + _f: 'html', + alternative: 'prebid_js', + inventory_item_id: placementId, + srw: width, + srh: height, + idt: 100, + rnd: rnd, + ref: referrer, + bid_id: bidId, + }; + } + if (params.pfilter !== undefined) { payload.pfilter = params.pfilter; } + + if (bidderRequest && bidderRequest.gdprConsent) { + if (payload.pfilter !== undefined) { + if (!payload.pfilter.gdpr_consent) { + payload.pfilter.gdpr_consent = bidderRequest.gdprConsent.consentString; + payload.pfilter.gdpr = bidderRequest.gdprConsent.gdprApplies; + } + } else { + payload.pfilter = { + 'gdpr_consent': bidderRequest.gdprConsent.consentString, + 'gdpr': bidderRequest.gdprConsent.gdprApplies + }; + } + } + if (params.bcat !== undefined) { payload.bcat = params.bcat; } if (params.dvt !== undefined) { payload.dvt = params.dvt; } + if (isDev) { + payload.prebidDevMode = 1; + } return { method: 'GET', - url: ENDPOINT_URL, + url: endpoint, data: objectToQueryString(payload), } }); @@ -58,7 +102,6 @@ export const spec = { const dealId = response.dealid || ''; const currency = response.currency || 'EUR'; const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue; - const referrer = utils.getTopWindowUrl(); const bidResponse = { requestId: response.bid_id, cpm: cpm, @@ -68,10 +111,15 @@ export const spec = { dealId: dealId, currency: currency, netRevenue: netRevenue, - ttl: config.getConfig('_bidderTimeout'), - referrer: referrer, - ad: response.adTag + type: response.type, + ttl: config.getConfig('_bidderTimeout') }; + if (response.vastXml) { + bidResponse.vastXml = response.vastXml; + bidResponse.mediaType = 'video'; + } else { + bidResponse.ad = response.adTag; + } bidResponses.push(bidResponse); } return bidResponses; @@ -93,4 +141,14 @@ function objectToQueryString(obj, prefix) { return str.join('&'); } +/** + * Check if it's a video bid request + * + * @param {BidRequest} bid - Bid request generated from ad slots + * @returns {boolean} True if it's a video bid + */ +function isVideoRequest(bid) { + return bid.mediaType === 'video' || !!utils.deepAccess(bid, 'mediaTypes.video'); +} + registerBidder(spec); diff --git a/modules/dspxBidAdapter.md b/modules/dspxBidAdapter.md index 362f4fbcb69..8733aff698c 100644 --- a/modules/dspxBidAdapter.md +++ b/modules/dspxBidAdapter.md @@ -1,14 +1,14 @@ # Overview ``` -Module Name: Dspx Bidder Adapter +Module Name: DSPx Bidder Adapter Module Type: Bidder Adapter Maintainer: prebid@dspx.tv ``` # Description -Dspx adapter for Prebid.js 1.0 +DSPx adapter for Prebid. # Test Parameters ``` @@ -20,54 +20,46 @@ Dspx adapter for Prebid.js 1.0 sizes: [ [300, 250], [300, 600], - ], // a display size + ] } }, bids: [ { bidder: "dspx", params: { - placement: '101', - pfilter: { - floorprice: 1000000, // EUR * 1,000,000 - private_auction: 1, // Is private auction? 0 - no, 1 - yes - deals: [ - "666-9315-d58a7f9a-bdb9-4450-a3a2-046ba8ab2489;3;25000000;dspx-tv",// DEAL_ID;at;bidfloor;wseat1,wseat2;wadomain1,wadomain2" - "666-9315-d58a7f9a-bdb9-4450-a6a2-046ba8ab2489;3;25000000;dspx-tv",// DEAL_ID;at;bidfloor;wseat1,wseat2;wadomain1,wadomain2" - ], - geo: { // set client geo info manually (empty for auto detect) - lat: 52.52437, // Latitude from -90.0 to +90.0, where negative is south. - lon: 13.41053, // Longitude from -180.0 to +180.0, where negative is west - type: 1, // Source of location data: 1 - GPS/Location Services, 2 - IP Address, 3 - User provided (e.g. registration form) - country: 'DE', // Region of a country using FIPS 10-4 notation - region: 'DE-BE', // Region code using ISO-3166-2; 2-letter state code if USA. - regionfips104: 'GM', // Region of a country using FIPS 10-4 notation - city: 'BER', // City using United Nations Code for Trade and Transport Locations - zip: '10115' // Zip or postal code. - } + placement: '101', // [required] info available from your contact with DSPx team + /* + bcat: "IAB2,IAB4", // [optional] list of blocked advertiser categories (IAB), comma separated + */ + /* + pfilter: { // [optional] + // [optional] only required if a deal is negotiated + deals: [ // [optional] + "123-4567-d58a7f9a-..."// DEAL_ID from DSPx contact + ], + private_auction: 1 // [optional] 0 - no, 1 - yes + // usually managed on DSPx side + floorprice: 1000000 // input min_cpm_micros, CPM in EUR * 1000000 }, - bcat: "IAB2,IAB4", // List of Blocked Categories (IAB) - comma separated - dvt: "desktop|smartphone|tv|tablet" // DeVice Type (autodetect if not exists) + */ } } ] - },{ - code: 'test-div', + }, + { + code: 'video1', mediaTypes: { - banner: { - sizes: [[320, 50]], // a mobile size + video: { + playerSize: [640, 480], + context: 'instream' } }, - bids: [ - { - bidder: "dspx", - params: { - placement: 101 - } + bids: [{ + bidder: 'dspx', + params: { + placement: '106' } - ] + }] } ]; ``` - -Required param field is only `placement`. \ No newline at end of file diff --git a/modules/e_volutionBidAdapter.js b/modules/e_volutionBidAdapter.js new file mode 100644 index 00000000000..9fc7035db32 --- /dev/null +++ b/modules/e_volutionBidAdapter.js @@ -0,0 +1,111 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; + +const BIDDER_CODE = 'e_volution'; +const AD_URL = 'https://service.e-volution.ai/?c=o&m=multi'; +const URL_SYNC = 'https://service.e-volution.ai/?c=o&m=sync'; +const NO_SYNC = true; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || + !bid.ttl || !bid.currency) { + return false; + } + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + case VIDEO: + return Boolean(bid.vastUrl); + case NATIVE: + return Boolean(bid.native && bid.native.title && bid.native.image && bid.native.impressionTrackers); + default: + return false; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + noSync: NO_SYNC, + + isBidRequestValid: (bid) => { + return Boolean(bid.bidId && bid.params && !isNaN(parseInt(bid.params.placementId))); + }, + + buildRequests: (validBidRequests = [], bidderRequest) => { + let winTop = window; + let location; + try { + location = new URL(bidderRequest.refererInfo.referer) + winTop = window.top; + } catch (e) { + location = winTop.location; + utils.logMessage(e); + }; + let placements = []; + let request = { + 'deviceWidth': winTop.screen.width, + 'deviceHeight': winTop.screen.height, + 'language': (navigator && navigator.language) ? navigator.language.split('-')[0] : '', + 'secure': 1, + 'host': location.host, + 'page': location.pathname, + 'placements': placements + }; + if (bidderRequest) { + if (bidderRequest.uspConsent) { + request.ccpa = bidderRequest.uspConsent; + } + if (bidderRequest.gdprConsent) { + request.gdpr = bidderRequest.gdprConsent + } + } + const len = validBidRequests.length; + + for (let i = 0; i < len; i++) { + let bid = validBidRequests[i]; + let traff = bid.params.traffic || BANNER + + placements.push({ + placementId: bid.params.placementId, + bidId: bid.bidId, + sizes: bid.mediaTypes && bid.mediaTypes[traff] && bid.mediaTypes[traff].sizes ? bid.mediaTypes[traff].sizes : [], + traffic: traff + }); + if (bid.schain) { + placements.schain = bid.schain; + } + } + return { + method: 'POST', + url: AD_URL, + data: request + }; + }, + + interpretResponse: (serverResponse) => { + let response = []; + for (let i = 0; i < serverResponse.body.length; i++) { + let resItem = serverResponse.body[i]; + if (isBidResponseValid(resItem)) { + response.push(resItem); + } + } + return response; + }, + + getUserSyncs: (syncOptions, serverResponses) => { + if (NO_SYNC) { + return false + } else { + return [{ + type: 'image', + url: URL_SYNC + }]; + } + } + +}; + +registerBidder(spec); diff --git a/modules/e_volutionBidAdapter.md b/modules/e_volutionBidAdapter.md new file mode 100644 index 00000000000..ff5b2860e05 --- /dev/null +++ b/modules/e_volutionBidAdapter.md @@ -0,0 +1,53 @@ +# Overview + +``` +Module Name: e_volution Bidder Adapter +Module Type: Bidder Adapter +``` + +# Description + +Module that connects to e-volution-tech demand sources + +# Test Parameters +``` + var adUnits = [ + // Will return static test banner + { + code: 'placementId_0', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: 'e_volution', + params: { + placementId: 0, + traffic: 'banner' + } + } + ] + }, + // Will return test vast xml. All video params are stored under placement in publishers UI + { + code: 'placementId_0', + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'instream' + } + }, + bids: [ + { + bidder: 'e_volution', + params: { + placementId: 0, + traffic: 'video' + } + } + ] + } + ]; +``` diff --git a/modules/ebdrBidAdapter.js b/modules/ebdrBidAdapter.js index 79bf4bb1004..c30c10d8a90 100644 --- a/modules/ebdrBidAdapter.js +++ b/modules/ebdrBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import { VIDEO, BANNER } from '../src/mediaTypes'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'ebdr'; export const spec = { code: BIDDER_CODE, @@ -57,7 +57,7 @@ export const spec = { }; return { method: 'GET', - url: '//' + rtbServerDomain + '/hb?' + '&zoneid=' + zoneid + '&br=' + encodeURIComponent(JSON.stringify(ebdrBidReq)), + url: 'https://' + rtbServerDomain + '/hb?' + '&zoneid=' + zoneid + '&br=' + encodeURIComponent(JSON.stringify(ebdrBidReq)), bids: ebdrReq }; }, diff --git a/modules/edgequeryxBidAdapter.js b/modules/edgequeryxBidAdapter.js new file mode 100644 index 00000000000..ee50946ee18 --- /dev/null +++ b/modules/edgequeryxBidAdapter.js @@ -0,0 +1,98 @@ +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'edgequeryx'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['eqx'], // short code + supportedMediaTypes: [BANNER, VIDEO], + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + return !!(bid.params && bid.params.accountId && bid.params.widgetId); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests an array of bids + * @param {BidderRequest} bidderRequest bidder request object + * @return {ServerRequest[]} Info describing the request to the server. + */ + buildRequests: function (validBidRequests, bidderRequest) { + // use bidderRequest.bids[] to get bidder-dependent request info + // if your bidder supports multiple currencies, use config.getConfig(currency) + // to find which one the ad server needs + + // pull requested transaction ID from bidderRequest.bids[].transactionId + return validBidRequests.map(bid => { + // Common bid request attributes for banner, outstream and instream. + let payload = { + accountId: bid.params.accountId, + widgetId: bid.params.widgetId, + currencyCode: 'EUR', + tagId: bid.adUnitCode, + transactionId: bid.transactionId, + timeout: config.getConfig('bidderTimeout'), + bidId: bid.bidId, + prebidVersion: '$prebid.version$' + }; + + const bannerMediaType = utils.deepAccess(bid, 'mediaTypes.banner'); + payload.sizes = bannerMediaType.sizes.map(size => ({ + w: size[0], + h: size[1] + })); + + var payloadString = JSON.stringify(payload); + + return { + method: 'POST', + url: (bid.params.domain !== undefined ? bid.params.domain : 'https://deep.edgequery.io') + '/prebid/x', + data: payloadString, + }; + }); + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @param {*} bidRequestString + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, bidRequestString) { + const bidResponses = []; + let response = serverResponse.body; + try { + if (response) { + let bidResponse = { + requestId: response.requestId, + cpm: response.cpm, + currency: response.currency, + width: response.width, + height: response.height, + ad: response.ad, + ttl: response.ttl, + creativeId: response.creativeId, + netRevenue: response.netRevenue + }; + + bidResponses.push(bidResponse); + } + } catch (error) { + utils.logError('Error while parsing Edge Query X response', error); + } + return bidResponses; + } + +}; + +registerBidder(spec); diff --git a/modules/edgequeryxBidAdapter.md b/modules/edgequeryxBidAdapter.md new file mode 100644 index 00000000000..265120dfaba --- /dev/null +++ b/modules/edgequeryxBidAdapter.md @@ -0,0 +1,39 @@ +# Overview + +``` +Module Name: Edge Query X Bidder Adapter +Module Type: Bidder Adapter +Maintainer: contact@edgequery.com +``` + +# Description + +Connect to Edge Query X for bids. + +The Edge Query X adapter requires setup and approval from the Edge Query team. +Please reach out to your Technical account manager for more information. + +# Test Parameters + +## Web +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[1, 1]] + } + }, + bids: [ + { + bidder: "edgequeryx", + params: { + accountId: "test", + widgetId: "test" + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/modules/emoteevBidAdapter.js b/modules/emoteevBidAdapter.js index 4436d39bb70..e0f88725d8a 100644 --- a/modules/emoteevBidAdapter.js +++ b/modules/emoteevBidAdapter.js @@ -14,19 +14,22 @@ * @author Emoteev Engineering . */ -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER} from '../src/mediaTypes'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; import { triggerPixel, getUniqueIdentifierStr, contains, deepAccess, isArray, - getParameterByName -} from '../src/utils'; -import {config} from '../src/config'; -import * as url from '../src/url'; -import {getCookie} from './pubCommonId'; + isInteger, + getParameterByName, + buildUrl +} from '../src/utils.js'; +import {config} from '../src/config.js'; +import { getStorageManager } from '../src/storageManager.js'; + +export const storage = getStorageManager(); export const BIDDER_CODE = 'emoteev'; @@ -35,8 +38,8 @@ export const BIDDER_CODE = 'emoteev'; */ export const ADAPTER_VERSION = '1.35.0'; -export const DOMAIN = 'prebid.emoteev.io'; -export const DOMAIN_STAGING = 'prebid-staging.emoteev.io'; +export const DOMAIN = 'prebid.emoteev.xyz'; +export const DOMAIN_STAGING = 'prebid-staging.emoteev.xyz'; export const DOMAIN_DEVELOPMENT = 'localhost:3000'; /** @@ -60,6 +63,19 @@ export const ON_ADAPTER_CALLED = 'on_adapter_called'; export const ON_BID_WON = 'on_bid_won'; export const ON_BIDDER_TIMEOUT = 'on_bidder_timeout'; +export const IN_CONTENT = 'content'; +export const FOOTER = 'footer'; +export const OVERLAY = 'overlay'; +export const WALLPAPER = 'wallpaper'; + +/** + * Vendor ID assigned to Emoteev from the Global Vendor & CMP List. + * + * See https://vendorlist.consensu.org/vendorinfo.json for more information. + * @type {number} + */ +export const VENDOR_ID = 15; + /** * Pure function. See http://prebid.org/dev-docs/bidder-adaptor.html#valid-build-requests-array for detailed semantic. * @@ -71,6 +87,8 @@ export const isBidRequestValid = (bidRequest) => { bidRequest && bidRequest.params && deepAccess(bidRequest, 'params.adSpaceId') && + validateContext(deepAccess(bidRequest, 'params.context')) && + validateExternalId(deepAccess(bidRequest, 'params.externalId')) && bidRequest.bidder === BIDDER_CODE && validateSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes'))); }; @@ -89,7 +107,7 @@ export const buildRequests = (env, debug, currency, validBidRequests, bidderRequ return { method: 'POST', url: bidderUrl(env), - data: JSON.stringify(requestsPayload(debug, currency, validBidRequests, bidderRequest)) + data: JSON.stringify(requestsPayload(debug, currency, validBidRequests, bidderRequest)) // Keys with undefined values will be filtered out. }; }; @@ -216,7 +234,7 @@ export const domain = (env) => { * @param {string} env Emoteev environment parameter * @returns {string} The full URL which events is sent to. */ -export const eventsUrl = env => url.format({ +export const eventsUrl = env => buildUrl({ protocol: (env === DEVELOPMENT) ? 'http' : 'https', hostname: domain(env), pathname: EVENTS_PATH @@ -228,7 +246,7 @@ export const eventsUrl = env => url.format({ * @param {string} env Emoteev environment parameter * @returns {string} The full URL which bidderRequest is sent to. */ -export const bidderUrl = env => url.format({ +export const bidderUrl = env => buildUrl({ protocol: (env === DEVELOPMENT) ? 'http' : 'https', hostname: domain(env), pathname: BIDDER_PATH @@ -240,7 +258,7 @@ export const bidderUrl = env => url.format({ * @param {string} env Emoteev environment parameter * @returns {string} The full URL called for iframe-based user sync */ -export const userSyncIframeUrl = env => url.format({ +export const userSyncIframeUrl = env => buildUrl({ protocol: (env === DEVELOPMENT) ? 'http' : 'https', hostname: domain(env), pathname: USER_SYNC_IFRAME_PATH @@ -252,7 +270,7 @@ export const userSyncIframeUrl = env => url.format({ * @param {string} env Emoteev environment parameter * @returns {string} The full URL called for image-based user sync */ -export const userSyncImageUrl = env => url.format({ +export const userSyncImageUrl = env => buildUrl({ protocol: (env === DEVELOPMENT) ? 'http' : 'https', hostname: domain(env), pathname: USER_SYNC_IMAGE_PATH @@ -264,7 +282,23 @@ export const userSyncImageUrl = env => url.format({ * @param {Array>} sizes * @returns {boolean} are sizes valid? */ -const validateSizes = sizes => isArray(sizes) && sizes.some(size => isArray(size) && size.length === 2); +export const validateSizes = sizes => isArray(sizes) && sizes.length > 0 && sizes.every(size => isArray(size) && size.length === 2); + +/** + * Pure function. + * + * @param {string} context + * @returns {boolean} is param `context` valid? + */ +export const validateContext = context => contains([IN_CONTENT, FOOTER, OVERLAY, WALLPAPER], context); + +/** + * Pure function. + * + * @param {(number|null|undefined)} externalId + * @returns {boolean} is param `externalId` valid? + */ +export const validateExternalId = externalId => externalId === undefined || externalId === null || (isInteger(externalId) && externalId > 0); /** * Pure function. @@ -282,6 +316,14 @@ export const conformBidRequest = bidRequest => { }; }; +/** + * Pure function. + * + * @param {object} bidderRequest + * @returns {(boolean|undefined)} raw consent data. + */ +export const gdprConsent = (bidderRequest) => (deepAccess(bidderRequest, 'gdprConsent.vendorData.vendorConsents') || {})[VENDOR_ID]; + /** * Pure function. * @@ -306,7 +348,7 @@ export const requestsPayload = (debug, currency, validBidRequests, bidderRequest isWebGLEnabled(document)), userAgent: navigator.userAgent, gdprApplies: deepAccess(bidderRequest, 'gdprConsent.gdprApplies'), - gdprConsent: deepAccess(bidderRequest, 'gdprConsent.consentString'), + gdprConsent: gdprConsent(bidderRequest), }; }; @@ -426,7 +468,7 @@ export const getDeviceInfo = (deviceDimensions, viewDimensions, documentDimensio * Pure function * @param {object} config pbjs config value * @param {string} parameter Environment override from URL query param. - * @returns One of [PRODUCTION, STAGING, DEVELOPMENT]. + * @returns {string} One of [PRODUCTION, STAGING, DEVELOPMENT]. */ export const resolveEnv = (config, parameter) => { const configEnv = deepAccess(config, 'emoteev.env'); @@ -466,12 +508,12 @@ export const spec = { bidderRequest), interpretResponse: interpretResponse, onBidWon: (bidObject) => - triggerPixel(url.format(onBidWon( + triggerPixel(buildUrl(onBidWon( resolveEnv(config.getConfig(), getParameterByName('emoteevEnv')), - getCookie('_pubcid'), + storage.getCookie('_pubcid'), bidObject))), onTimeout: (bidRequest) => - triggerPixel(url.format(onTimeout( + triggerPixel(buildUrl(onTimeout( resolveEnv(config.getConfig(), getParameterByName('emoteevEnv')), bidRequest))), getUserSyncs: (syncOptions) => diff --git a/modules/emoteevBidAdapter.md b/modules/emoteevBidAdapter.md index 88b0b21a96f..226a8374369 100644 --- a/modules/emoteevBidAdapter.md +++ b/modules/emoteevBidAdapter.md @@ -18,14 +18,16 @@ Module that connects to Emoteev's demand sources code: 'test-div', mediaTypes: { banner: { - sizes: [[300, 250]], + sizes: [[720, 90]], } }, bids: [ { bidder: 'emoteev', params: { - adSpaceId: 5084 + adSpaceId: 5084, + context: 'footer', + externalId: 42, } } ] diff --git a/modules/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js index 75ce47aae0a..6688d15d8e9 100644 --- a/modules/emx_digitalBidAdapter.js +++ b/modules/emx_digitalBidAdapter.js @@ -1,13 +1,15 @@ -import * as utils from 'src/utils'; -import { registerBidder } from 'src/adapters/bidderFactory'; -import { BANNER, VIDEO } from 'src/mediaTypes'; -import { config } from 'src/config'; -import { Renderer } from 'src/Renderer'; -import includes from 'core-js/library/fn/array/includes'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { Renderer } from '../src/Renderer.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import find from 'core-js-pure/features/array/find.js'; const BIDDER_CODE = 'emx_digital'; const ENDPOINT = 'hb.emxdgt.com'; -const RENDERER_URL = '//js.brealtime.com/outstream/1.30.0/bundle.js'; +const RENDERER_URL = 'https://js.brealtime.com/outstream/1.30.0/bundle.js'; +const ADAPTER_VERSION = '1.5.1'; +const DEFAULT_CUR = 'USD'; export const emxAdapter = { validateSizes: (sizes) => { @@ -38,16 +40,36 @@ export const emxAdapter = { h: sizes[0][1] }; }, - formatVideoResponse: (bidResponse, emxBid) => { + formatVideoResponse: (bidResponse, emxBid, bidRequest) => { bidResponse.vastXml = emxBid.adm; - if (!emxBid.renderer && (!emxBid.mediaTypes || !emxBid.mediaTypes.video || !emxBid.mediaTypes.video.context || emxBid.mediaTypes.video.context === 'outstream')) { - bidResponse.renderer = emxAdapter.createRenderer(bidResponse, { - id: emxBid.bidId, - url: RENDERER_URL - }); + if (bidRequest.bidderRequest && bidRequest.bidderRequest.bids && bidRequest.bidderRequest.bids.length > 0) { + const matchingBid = find(bidRequest.bidderRequest.bids, bid => bidResponse.requestId && bid.bidId && bidResponse.requestId === bid.bidId && bid.mediaTypes && bid.mediaTypes.video && bid.mediaTypes.video.context === 'outstream'); + if (matchingBid) { + bidResponse.renderer = emxAdapter.createRenderer(bidResponse, { + id: emxBid.id, + url: RENDERER_URL + }); + } } return bidResponse; }, + isMobile: () => { + return (/(ios|ipod|ipad|iphone|android)/i).test(navigator.userAgent); + }, + isConnectedTV: () => { + return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(navigator.userAgent); + }, + getDevice: () => { + return { + ua: navigator.userAgent, + js: 1, + dnt: (navigator.doNotTrack === 'yes' || navigator.doNotTrack === '1' || navigator.msDoNotTrack === '1') ? 1 : 0, + h: screen.height, + w: screen.width, + devicetype: emxAdapter.isMobile() ? 1 : emxAdapter.isConnectedTV() ? 3 : 2, + language: (navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage), + }; + }, cleanProtocols: (video) => { if (video.protocols && includes(video.protocols, 7)) { // not supporting VAST protocol 7 (VAST 4.0); @@ -85,10 +107,38 @@ export const emxAdapter = { return renderer; }, buildVideo: (bid) => { - bid.params.video = bid.params.video || {}; - bid.params.video.h = bid.mediaTypes.video.playerSize[0][0]; - bid.params.video.w = bid.mediaTypes.video.playerSize[0][1]; - return emxAdapter.cleanProtocols(bid.params.video); + let videoObj = Object.assign(bid.mediaTypes.video, bid.params.video); + + if (utils.isArray(bid.mediaTypes.video.playerSize[0])) { + videoObj['w'] = bid.mediaTypes.video.playerSize[0][0]; + videoObj['h'] = bid.mediaTypes.video.playerSize[0][1]; + } else { + videoObj['w'] = bid.mediaTypes.video.playerSize[0]; + videoObj['h'] = bid.mediaTypes.video.playerSize[1]; + } + return emxAdapter.cleanProtocols(videoObj); + }, + parseResponse: (bidResponseAdm) => { + try { + return decodeURIComponent(bidResponseAdm.replace(/%(?![0-9][0-9a-fA-F]+)/g, '%25')); + } catch (err) { + utils.logError('emx_digitalBidAdapter', 'error', err); + } + }, + getReferrer: () => { + try { + return window.top.document.referrer; + } catch (err) { + return document.referrer; + } + }, + getSite: (refInfo) => { + let url = utils.parseUrl(refInfo.referer); + return { + domain: url.hostname, + page: refInfo.referer, + ref: emxAdapter.getReferrer() + } }, getGdpr: (bidRequests, emxData) => { if (bidRequests.gdprConsent) { @@ -151,59 +201,62 @@ export const spec = { return true; }, buildRequests: function (validBidRequests, bidderRequest) { - const page = bidderRequest.refererInfo.referer; - let emxImps = []; - const timeout = config.getConfig('bidderTimeout'); + const emxImps = []; + const timeout = bidderRequest.timeout || ''; const timestamp = Date.now(); - const url = location.protocol + '//' + ENDPOINT + ('?t=' + timeout + '&ts=' + timestamp); - const networkProtocol = location.protocol.indexOf('https') > -1 ? 1 : 0; + const url = 'https://' + ENDPOINT + ('?t=' + timeout + '&ts=' + timestamp + '&src=pbjs'); + const secure = location.protocol.indexOf('https') > -1 ? 1 : 0; + const device = emxAdapter.getDevice(); + const site = emxAdapter.getSite(bidderRequest.refererInfo); utils._each(validBidRequests, function (bid) { - let tagId = utils.getBidIdParameter('tagid', bid.params); - let bidFloor = parseFloat(utils.getBidIdParameter('bidfloor', bid.params)) || 0; + let tagid = utils.getBidIdParameter('tagid', bid.params); + let bidfloor = parseFloat(utils.getBidIdParameter('bidfloor', bid.params)) || 0; let isVideo = !!bid.mediaTypes.video; let data = { id: bid.bidId, tid: bid.transactionId, - tagid: tagId, - secure: networkProtocol + tagid, + secure }; let typeSpecifics = isVideo ? { video: emxAdapter.buildVideo(bid) } : { banner: emxAdapter.buildBanner(bid) }; - let emxBid = Object.assign(data, typeSpecifics); + let bidfloorObj = bidfloor > 0 ? { bidfloor, bidfloorcur: DEFAULT_CUR } : {}; + let emxBid = Object.assign(data, typeSpecifics, bidfloorObj); - if (bidFloor > 0) { - emxBid.bidfloor = bidFloor - } emxImps.push(emxBid); }); let emxData = { id: bidderRequest.auctionId, imp: emxImps, - site: { - domain: window.top.document.location.host, - page: page - }, - version: '1.30.0' + device, + site, + cur: DEFAULT_CUR, + version: ADAPTER_VERSION }; emxData = emxAdapter.getGdpr(bidderRequest, Object.assign({}, emxData)); + if (bidderRequest && bidderRequest.uspConsent) { + emxData.us_privacy = bidderRequest.uspConsent + } return { method: 'POST', - url: url, + url, data: JSON.stringify(emxData), options: { withCredentials: true - } + }, + bidderRequest }; }, - interpretResponse: function (serverResponse) { + interpretResponse: function (serverResponse, bidRequest) { let emxBidResponses = []; let response = serverResponse.body || {}; if (response.seatbid && response.seatbid.length > 0 && response.seatbid[0].bid) { response.seatbid.forEach(function (emxBid) { emxBid = emxBid.bid[0]; let isVideo = false; + let adm = emxAdapter.parseResponse(emxBid.adm) || ''; let bidResponse = { requestId: emxBid.id, cpm: emxBid.price, @@ -214,11 +267,11 @@ export const spec = { currency: 'USD', netRevenue: true, ttl: emxBid.ttl, - ad: decodeURIComponent(emxBid.adm) + ad: adm }; if (emxBid.adm && emxBid.adm.indexOf(' -1) { isVideo = true; - bidResponse = emxAdapter.formatVideoResponse(bidResponse, Object.assign({}, emxBid)); + bidResponse = emxAdapter.formatVideoResponse(bidResponse, Object.assign({}, emxBid), bidRequest); } bidResponse.mediaType = (isVideo ? VIDEO : BANNER); emxBidResponses.push(bidResponse); @@ -231,13 +284,7 @@ export const spec = { if (syncOptions.iframeEnabled) { syncs.push({ type: 'iframe', - url: '//biddr.brealtime.com/check.html' - }); - } - if (syncOptions.pixelEnabled) { - syncs.push({ - type: 'image', - url: '//edba.brealtime.com/' + url: 'https://biddr.brealtime.com/check.html' }); } return syncs; diff --git a/modules/envivoBidAdapter.js b/modules/envivoBidAdapter.js new file mode 100644 index 00000000000..b9c80ffd468 --- /dev/null +++ b/modules/envivoBidAdapter.js @@ -0,0 +1,129 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import * as utils from '../src/utils.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import { ajax } from '../src/ajax.js'; +import {Renderer} from '../src/Renderer.js'; + +const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; +const BIDDER_CODE = 'envivo'; +const DOMAIN = 'https://ad.nvivo.tv/'; +const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; + +function isBidRequestValid(bid) { + return (typeof bid.params !== 'undefined' && parseInt(utils.getValue(bid.params, 'publisherId')) > 0); +} + +function buildRequests(validBidRequests) { + return { + method: 'POST', + url: DOMAIN + 'ads/www/admin/plugins/Prebid/getAd.php', + options: { + withCredentials: false, + crossOrigin: true + }, + data: validBidRequests, + }; +} + +function interpretResponse(serverResponse, request) { + const response = serverResponse.body; + const bidResponses = []; + var bidRequestResponses = []; + + utils._each(response, function(bidAd) { + bidAd.adResponse = { + content: bidAd.vastXml, + height: bidAd.height, + width: bidAd.width + }; + bidAd.ttl = config.getConfig('_bidderTimeout') + bidAd.renderer = bidAd.context === 'outstream' ? createRenderer(bidAd, { + id: bidAd.adUnitCode, + url: RENDERER_URL + }, bidAd.adUnitCode) : undefined; + bidResponses.push(bidAd); + }); + + bidRequestResponses.push({ + function: 'saveResponses', + request: request, + response: bidResponses + }); + sendResponseToServer(bidRequestResponses); + return bidResponses; +} + +function outstreamRender(bidAd) { + bidAd.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + sizes: [bidAd.width, bidAd.height], + width: bidAd.width, + height: bidAd.height, + targetId: bidAd.adUnitCode, + adResponse: bidAd.adResponse, + rendererOptions: { + showVolume: false, + allowFullscreen: false + } + }); + }); +} + +function createRenderer(bidAd, rendererParams, adUnitCode) { + const renderer = Renderer.install({ + id: rendererParams.id, + url: rendererParams.url, + loaded: false, + config: {'player_height': bidAd.height, 'player_width': bidAd.width}, + adUnitCode + }); + try { + renderer.setRender(outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on renderer', err); + } + return renderer; +} + +function onBidWon(bid) { + let wonBids = []; + wonBids.push(bid); + wonBids[0].function = 'onBidWon'; + sendResponseToServer(wonBids); +} + +function onTimeout(details) { + details.unshift({ 'function': 'onTimeout' }); + sendResponseToServer(details); +} + +function sendResponseToServer(data) { + ajax(DOMAIN + 'ads/www/admin/plugins/Prebid/tracking/track.php', null, JSON.stringify(data), { + withCredentials: false, + method: 'POST', + crossOrigin: true + }); +} + +function getUserSyncs(syncOptions) { + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: DOMAIN + 'ads/www/admin/plugins/Prebid/userSync.php' + }]; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: SUPPORTED_AD_TYPES, + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs, + onBidWon, + onTimeout +}; + +registerBidder(spec); diff --git a/modules/envivoBidAdapter.md b/modules/envivoBidAdapter.md new file mode 100644 index 00000000000..3ecc8a251f3 --- /dev/null +++ b/modules/envivoBidAdapter.md @@ -0,0 +1,50 @@ +# Overview + +``` +Module Name: envivo Bid Adapter +Module Type: Bidder Adapter +Maintainer : adtech@nvivo.tv +``` + +# Description + +Connects to Envivo Ad Server for bids. + +envivo bid adapter supports Banner and Video. + +# Test Parameters +``` + var adUnits = [ + //bannner object + { + code: 'banner-ad-slot', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [{ + bidder: 'envivo', + params: { + publisherId: 14 + } + }] + + }, + //video object + { + code: 'video-ad-slot', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480], + }, + }, + bids: [{ + bidder: "envivo", + params: { + publisherId: 14 + } + }] + }]; +``` diff --git a/modules/eplanningAnalyticsAdapter.js b/modules/eplanningAnalyticsAdapter.js index 21ecddfbc3a..08db2f2ca9d 100644 --- a/modules/eplanningAnalyticsAdapter.js +++ b/modules/eplanningAnalyticsAdapter.js @@ -1,7 +1,7 @@ -import {ajax} from '../src/ajax'; -import adapter from '../src/AnalyticsAdapter'; -import adapterManager from '../src/adapterManager'; -import * as utils from '../src/utils'; +import {ajax} from '../src/ajax.js'; +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; const CONSTANTS = require('../src/constants.json'); diff --git a/modules/eplanningBidAdapter.js b/modules/eplanningBidAdapter.js index 01a956d1bd8..a4b4f2d6728 100644 --- a/modules/eplanningBidAdapter.js +++ b/modules/eplanningBidAdapter.js @@ -1,24 +1,30 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { getStorageManager } from '../src/storageManager.js'; + +export const storage = getStorageManager(); const BIDDER_CODE = 'eplanning'; const rnd = Math.random(); const DEFAULT_SV = 'ads.us.e-planning.net'; const DEFAULT_ISV = 'i.e-planning.net'; -const PARAMS = ['ci', 'sv', 't']; +const PARAMS = ['ci', 'sv', 't', 'ml']; const DOLLARS = 'USD'; const NET_REVENUE = true; const TTL = 120; const NULL_SIZE = '1x1'; const FILE = 'file'; +const STORAGE_RENDER_PREFIX = 'pbsr_'; +const STORAGE_VIEW_PREFIX = 'pbvi_'; export const spec = { code: BIDDER_CODE, + isBidRequestValid: function(bid) { return Boolean(bid.params.ci) || Boolean(bid.params.t); }, - buildRequests: function(bidRequests) { + buildRequests: function(bidRequests, bidderRequest) { const method = 'GET'; const dfpClientId = '1'; const sec = 'ROS'; @@ -26,23 +32,33 @@ export const spec = { let params; const urlConfig = getUrlConfig(bidRequests); const pcrs = getCharset(); - + const spaces = getSpaces(bidRequests, urlConfig.ml); + const pageUrl = bidderRequest.refererInfo.referer; + const getDomain = (url) => { + let anchor = document.createElement('a'); + anchor.href = url; + return anchor.hostname; + } if (urlConfig.t) { - url = urlConfig.isv + '/layers/t_pbjs_2.json'; + url = 'https://' + urlConfig.isv + '/layers/t_pbjs_2.json'; params = {}; } else { - url = '//' + (urlConfig.sv || DEFAULT_SV) + '/hb/1/' + urlConfig.ci + '/' + dfpClientId + '/' + (utils.getTopWindowLocation().hostname || FILE) + '/' + sec; - const referrerUrl = utils.getTopWindowReferrer(); - const spacesString = getSpacesString(bidRequests); + url = 'https://' + (urlConfig.sv || DEFAULT_SV) + '/hb/1/' + urlConfig.ci + '/' + dfpClientId + '/' + getDomain(pageUrl) + '/' + sec; + const referrerUrl = bidderRequest.refererInfo.referer.reachedTop ? encodeURIComponent(window.top.document.referrer) : encodeURIComponent(bidderRequest.refererInfo.referer); + + if (storage.hasLocalStorage()) { + registerViewabilityAllBids(bidRequests); + } + params = { rnd: rnd, - e: spacesString, - ur: utils.getTopWindowUrl() || FILE, + e: spaces.str, + ur: encodeURIComponent(pageUrl || FILE), r: 'pbjs', pbv: '$prebid.version$', - ncb: '1' + ncb: '1', + vs: spaces.vs }; - if (pcrs) { params.crs = pcrs; } @@ -50,13 +66,26 @@ export const spec = { if (referrerUrl) { params.fr = referrerUrl; } + + if (bidderRequest && bidderRequest.gdprConsent) { + if (typeof bidderRequest.gdprConsent.gdprApplies !== 'undefined') { + params.gdpr = bidderRequest.gdprConsent.gdprApplies ? '1' : '0'; + if (typeof bidderRequest.gdprConsent.consentString !== 'undefined') { + params.gdprcs = bidderRequest.gdprConsent.consentString; + } + } + } + + if (bidderRequest && bidderRequest.uspConsent) { + params.ccpa = bidderRequest.uspConsent; + } } return { method: method, url: url, data: params, - adUnitToBidId: getBidIdMap(bidRequests), + adUnitToBidId: spaces.map, }; }, interpretResponse: function(serverResponse, request) { @@ -111,9 +140,6 @@ export const spec = { }, } -function cleanName(name) { - return name.replace(/_|\.|-|\//g, '').replace(/\)\(|\(|\)|:/g, '_').replace(/^_+|_+$/g, ''); -} function getUrlConfig(bidRequests) { if (isTestRequest(bidRequests)) { return getTestConfig(bidRequests.filter(br => br.params.t)); @@ -128,31 +154,76 @@ function getUrlConfig(bidRequests) { }); }); - if (config.sv) { - config.sv = '//' + config.sv; - } - return config; } function isTestRequest(bidRequests) { - let isTest = false; - bidRequests.forEach(bid => isTest = bid.params.t); - return isTest; + for (let i = 0; i < bidRequests.length; i++) { + if (bidRequests[i].params.t) { + return true; + } + } + return false; } function getTestConfig(bidRequests) { let isv; bidRequests.forEach(br => isv = isv || br.params.isv); return { t: true, - isv: '//' + (isv || DEFAULT_ISV) + isv: (isv || DEFAULT_ISV) }; } -function getSpacesString(bids) { - const spacesString = bids.map(bid => - cleanName(bid.adUnitCode) + ':' + (bid.sizes && bid.sizes.length ? utils.parseSizesInput(bid.sizes).join(',') : NULL_SIZE) - ).join('+'); - return spacesString; +function getSize(bid, first) { + return bid.sizes && bid.sizes.length ? utils.parseSizesInput(first ? bid.sizes[0] : bid.sizes).join(',') : NULL_SIZE; +} + +function getSpacesStruct(bids) { + let e = {}; + bids.forEach(bid => { + let size = getSize(bid, true); + e[size] = e[size] ? e[size] : []; + e[size].push(bid); + }); + + return e; +} + +function cleanName(name) { + return name.replace(/_|\.|-|\//g, '').replace(/\)\(|\(|\)|:/g, '_').replace(/^_+|_+$/g, ''); +} + +function getSpaces(bidRequests, ml) { + let spacesStruct = getSpacesStruct(bidRequests); + let es = {str: '', vs: '', map: {}}; + es.str = Object.keys(spacesStruct).map(size => spacesStruct[size].map((bid, i) => { + es.vs += getVs(bid); + let name = ml ? cleanName(bid.adUnitCode) : getSize(bid, true) + '_' + i; + es.map[name] = bid.bidId; + return name + ':' + getSize(bid); + }).join('+')).join('+'); + return es; +} + +function getVs(bid) { + let s; + let vs = ''; + if (storage.hasLocalStorage()) { + s = getViewabilityData(bid); + vs += s.render >= 4 ? s.ratio.toString(16) : 'F'; + } else { + vs += 'F'; + } + return vs; +} + +function getViewabilityData(bid) { + let r = storage.getDataFromLocalStorage(STORAGE_RENDER_PREFIX + bid.adUnitCode) || 0; + let v = storage.getDataFromLocalStorage(STORAGE_VIEW_PREFIX + bid.adUnitCode) || 0; + let ratio = r > 0 ? (v / r) : 0; + return { + render: r, + ratio: window.parseInt(ratio * 10, 10) + }; } function getCharset() { @@ -163,10 +234,190 @@ function getCharset() { } } -function getBidIdMap(bidRequests) { - let map = {}; - bidRequests.forEach(bid => map[cleanName(bid.adUnitCode)] = bid.bidId); - return map; +function waitForElementsPresent(elements) { + const observer = new MutationObserver(function (mutationList, observer) { + if (mutationList && Array.isArray(mutationList)) { + mutationList.forEach(mr => { + if (mr && mr.addedNodes && Array.isArray(mr.addedNodes)) { + mr.addedNodes.forEach(ad => { + let index = elements.indexOf(ad.id); + if (index >= 0) { + registerViewability(ad); + elements.splice(index, 1); + if (!elements.length) { + observer.disconnect(); + } + } + }); + } + }); + } + }); + document.addEventListener('DOMContentLoaded', function (event) { + var config = { + childList: true, + subtree: true, + characterData: true + }; + observer.observe(document.body, config); + }); +} + +function registerViewability(div) { + visibilityHandler({ + name: div.id, + div: div + }); +} + +function registerViewabilityAllBids(bids) { + let elementsNotPresent = []; + bids.forEach(bid => { + let div = document.getElementById(bid.adUnitCode); + if (div) { + registerViewability(div); + } else { + elementsNotPresent.push(bid.adUnitCode); + } + }); + if (elementsNotPresent.length) { + waitForElementsPresent(elementsNotPresent); + } +} + +function getViewabilityTracker() { + let TIME_PARTITIONS = 5; + let VIEWABILITY_TIME = 1000; + let VIEWABILITY_MIN_RATIO = 0.5; + let publicApi; + let context; + + function segmentIsOutsideTheVisibleRange(visibleRangeEnd, p1, p2) { + return p1 > visibleRangeEnd || p2 < 0; + } + + function segmentBeginsBeforeTheVisibleRange(p1) { + return p1 < 0; + } + + function segmentEndsAfterTheVisibleRange(visibleRangeEnd, p2) { + return p2 < visibleRangeEnd; + } + + function axialVisibilityRatio(visibleRangeEnd, p1, p2) { + let visibilityRatio = 0; + if (!segmentIsOutsideTheVisibleRange(visibleRangeEnd, p1, p2)) { + if (segmentBeginsBeforeTheVisibleRange(p1)) { + visibilityRatio = p2 / (p2 - p1); + } else { + visibilityRatio = segmentEndsAfterTheVisibleRange(visibleRangeEnd, p2) ? 1 : (visibleRangeEnd - p1) / (p2 - p1); + } + } + return visibilityRatio; + } + + function isNotHiddenByNonFriendlyIframe() { + return (window === window.top) || window.frameElement; + } + + function defineContext(e) { + context = e && window.document.body.contains(e) ? window : (window.top.document.body.contains(e) ? top : undefined); + return context; + } + + function getContext(e) { + return context; + } + + function verticalVisibilityRatio(position) { + return axialVisibilityRatio(getContext().innerHeight, position.top, position.bottom); + } + + function horizontalVisibilityRatio(position) { + return axialVisibilityRatio(getContext().innerWidth, position.left, position.right); + } + + function itIsNotHiddenByBannerAreaPosition(e) { + let position = e.getBoundingClientRect(); + return (verticalVisibilityRatio(position) * horizontalVisibilityRatio(position)) > VIEWABILITY_MIN_RATIO; + } + + function itIsNotHiddenByDisplayStyleCascade(e) { + return e.offsetHeight > 0 && e.offsetWidth > 0; + } + + function itIsNotHiddenByOpacityStyleCascade(e) { + let s = e.style; + let p = e.parentNode; + return !(s && parseFloat(s.opacity) === 0) && (!p || itIsNotHiddenByOpacityStyleCascade(p)); + } + + function itIsNotHiddenByVisibilityStyleCascade(e) { + return getContext().getComputedStyle(e).visibility !== 'hidden'; + } + + function itIsNotHiddenByTabFocus() { + return getContext().top.document.hasFocus(); + } + + function isDefined(e) { + return (e !== null) && (typeof e !== 'undefined'); + } + + function itIsNotHiddenByOrphanBranch() { + return isDefined(getContext()); + } + + function isContextInAnIframe() { + return isDefined(getContext().frameElement); + } + + function processIntervalVisibilityStatus(elapsedVisibleIntervals, element, callback) { + let visibleIntervals = isVisible(element) ? (elapsedVisibleIntervals + 1) : 0; + if (visibleIntervals === TIME_PARTITIONS) { + callback(); + } else { + setTimeout(processIntervalVisibilityStatus.bind(this, visibleIntervals, element, callback), VIEWABILITY_TIME / TIME_PARTITIONS); + } + } + + function isVisible(element) { + defineContext(element); + return isNotHiddenByNonFriendlyIframe() && + itIsNotHiddenByOrphanBranch() && + itIsNotHiddenByTabFocus() && + itIsNotHiddenByDisplayStyleCascade(element) && + itIsNotHiddenByVisibilityStyleCascade(element) && + itIsNotHiddenByOpacityStyleCascade(element) && + itIsNotHiddenByBannerAreaPosition(element) && + (!isContextInAnIframe() || isVisible(getContext().frameElement)); + } + + publicApi = { + isVisible: isVisible, + onView: processIntervalVisibilityStatus.bind(this, 0) + }; + + return publicApi; +}; + +function visibilityHandler(obj) { + if (obj.div) { + registerAuction(STORAGE_RENDER_PREFIX + obj.name); + getViewabilityTracker().onView(obj.div, registerAuction.bind(undefined, STORAGE_VIEW_PREFIX + obj.name)); + } } +function registerAuction(storageID) { + let value; + try { + value = storage.getDataFromLocalStorage(storageID); + value = value ? window.parseInt(value, 10) + 1 : 1; + storage.setDataInLocalStorage(storageID, value); + } catch (exc) { + return false; + } + + return true; +} registerBidder(spec); diff --git a/modules/etargetBidAdapter.js b/modules/etargetBidAdapter.js index bdf07742497..5e07561044a 100644 --- a/modules/etargetBidAdapter.js +++ b/modules/etargetBidAdapter.js @@ -1,7 +1,7 @@ 'use strict'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; const BIDDER_CODE = 'etarget'; const countryMap = { @@ -39,7 +39,7 @@ export const spec = { request.push(formRequestUrl(reqParams)); } - request.unshift('//' + lastCountry + '.search.etargetnet.com/hb/?hbget=1'); + request.unshift('https://' + lastCountry + '.search.etargetnet.com/hb/?hbget=1'); netRevenue = 'net'; if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { diff --git a/modules/express.js b/modules/express.js index 1249822f587..f4a76daefdf 100644 --- a/modules/express.js +++ b/modules/express.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; +import * as utils from '../src/utils.js'; const MODULE_NAME = 'express'; @@ -61,6 +61,7 @@ $$PREBID_GLOBAL$$.express = function(adUnits = $$PREBID_GLOBAL$$.adUnits) { function defaultSlots(slots) { return Array.isArray(slots) ? slots.slice() + // eslint-disable-next-line no-undef : googletag.pubads().getSlots().slice(); } @@ -116,6 +117,7 @@ $$PREBID_GLOBAL$$.express = function(adUnits = $$PREBID_GLOBAL$$.adUnits) { // if not SRA mode, get only the gpt slot corresponding to sEementId var aGptSlots; if (!bEnabledSRA) { + // eslint-disable-next-line no-undef aGptSlots = googletag.pubads().getSlots().filter(function (oGptSlot) { return oGptSlot.getSlotElementId() === sElementId; }); diff --git a/modules/eywamediaBidAdapter.md b/modules/eywamediaBidAdapter.md new file mode 100644 index 00000000000..76b9b032c1b --- /dev/null +++ b/modules/eywamediaBidAdapter.md @@ -0,0 +1,37 @@ +# Overview + +``` +Module Name: Eywamedia Bid Adapter +Module Type: Bidder Adapter +Maintainer: sharath@eywamedia.com +Note: Our ads will only render in mobile and desktop +``` + +# Description + +Connects to Eywamedia Ad Server for bids. + +Eywamedia bid adapter supports Banners. + +# Test Parameters +``` +var adUnits = [ + // Banner adUnit + { + code: 'div-gpt-ad-1460505748561-0', + sizes: [[300, 250], [300,600]], + bids: [{ + bidder: 'eywamedia', + params: { + publisherId: 'f63a2362-5aa4-4829-bbd2-2678ced8b63e', //Required - GUID (may include numbers and characters) + bidFloor: 0.50, // optional + cats: ["iab1-1","iab23-2"], // optional + keywords: ["sports", "cricket"], // optional + lat: 12.33333, // optional + lon: 77.32322, // optional + locn: "country$region$city$zip" // optional + } + }] + } +]; +``` diff --git a/modules/fairtradeBidAdapter.js b/modules/fairtradeBidAdapter.js deleted file mode 100644 index 55f24ab8906..00000000000 --- a/modules/fairtradeBidAdapter.js +++ /dev/null @@ -1,150 +0,0 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -const BIDDER_CODE = 'fairtrade'; -const ENDPOINT_URL = '//pool.fair-trademedia.com/hb'; -const TIME_TO_LIVE = 360; -const ADAPTER_SYNC_URL = '//pool.fair-trademedia.com/push_sync'; -const LOG_ERROR_MESS = { - noAuid: 'Bid from response has no auid parameter - ', - noAdm: 'Bid from response has no adm parameter - ', - noBid: 'Array of bid objects is empty', - noPlacementCode: 'Can\'t find in requested bids the bid with auid - ', - emptyUids: 'Uids should be not empty', - emptySeatbid: 'Seatbid array from response has empty item', - emptyResponse: 'Response is empty', - hasEmptySeatbidArray: 'Response has empty seatbid array', - hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' -}; -export const spec = { - code: BIDDER_CODE, - /** - * Determines whether or not the given bid request is valid. - * - * @param {BidRequest} bid The bid params to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ - isBidRequestValid: function(bid) { - return !!bid.params.uid; - }, - /** - * Make a server request from the list of BidRequests. - * - * @param {BidRequest[]} validBidRequests - an array of bids - * @return ServerRequest Info describing the request to the server. - */ - buildRequests: function(validBidRequests) { - const auids = []; - const bidsMap = {}; - const bids = validBidRequests || []; - let priceType = 'net'; - let reqId; - - bids.forEach(bid => { - if (bid.params.priceType === 'gross') { - priceType = 'gross'; - } - reqId = bid.bidderRequestId; - if (!bidsMap[bid.params.uid]) { - bidsMap[bid.params.uid] = [bid]; - auids.push(bid.params.uid); - } else { - bidsMap[bid.params.uid].push(bid); - } - }); - - const payload = { - u: utils.getTopWindowUrl(), - pt: priceType, - auids: auids.join(','), - r: reqId - }; - - return { - method: 'GET', - url: ENDPOINT_URL, - data: payload, - bidsMap: bidsMap, - }; - }, - /** - * Unpack the response from the server into a list of bids. - * - * @param {*} serverResponse A successful response from the server. - * @param {*} bidRequest - * @return {Bid[]} An array of bids which were nested inside the server. - */ - interpretResponse: function(serverResponse, bidRequest) { - serverResponse = serverResponse && serverResponse.body - const bidResponses = []; - const bidsMap = bidRequest.bidsMap; - const priceType = bidRequest.data.pt; - - let errorMessage; - - if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse; - else if (serverResponse.seatbid && !serverResponse.seatbid.length) { - errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; - } - - if (!errorMessage && serverResponse.seatbid) { - serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses); - }); - } - if (errorMessage) utils.logError(errorMessage); - return bidResponses; - }, - getUserSyncs: function(syncOptions) { - if (syncOptions.pixelEnabled) { - return [{ - type: 'image', - url: ADAPTER_SYNC_URL - }]; - } - } -} - -function _getBidFromResponse(respItem) { - if (!respItem) { - utils.logError(LOG_ERROR_MESS.emptySeatbid); - } else if (!respItem.bid) { - utils.logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(respItem)); - } else if (!respItem.bid[0]) { - utils.logError(LOG_ERROR_MESS.noBid); - } - return respItem && respItem.bid && respItem.bid[0]; -} - -function _addBidResponse(serverBid, bidsMap, priceType, bidResponses) { - if (!serverBid) return; - let errorMessage; - if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); - if (!serverBid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid); - else { - const awaitingBids = bidsMap[serverBid.auid]; - if (awaitingBids) { - awaitingBids.forEach(bid => { - const bidResponse = { - requestId: bid.bidId, // bid.bidderRequestId, - cpm: serverBid.price, - width: serverBid.w, - height: serverBid.h, - creativeId: serverBid.auid, // bid.bidId, - currency: 'USD', - netRevenue: priceType !== 'gross', - ttl: TIME_TO_LIVE, - ad: serverBid.adm, - dealId: serverBid.dealid - }; - bidResponses.push(bidResponse); - }); - } else { - errorMessage = LOG_ERROR_MESS.noPlacementCode + serverBid.auid; - } - } - if (errorMessage) { - utils.logError(errorMessage); - } -} - -registerBidder(spec); diff --git a/modules/fairtradeBidAdapter.md b/modules/fairtradeBidAdapter.md old mode 100755 new mode 100644 diff --git a/modules/feedadBidAdapter.js b/modules/feedadBidAdapter.js new file mode 100644 index 00000000000..3992f2db5e0 --- /dev/null +++ b/modules/feedadBidAdapter.js @@ -0,0 +1,290 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {ajax} from '../src/ajax.js'; + +/** + * Version of the FeedAd bid adapter + * @type {string} + */ +const VERSION = '1.0.0'; + +/** + * @typedef {object} FeedAdApiBidRequest + * @inner + * + * @property {number} ad_type + * @property {string} client_token + * @property {string} placement_id + * @property {string} sdk_version + * @property {boolean} app_hybrid + * + * @property {string} [app_bundle_id] + * @property {string} [app_name] + * @property {object} [custom_params] + * @property {number} [connectivity] + * @property {string} [device_adid] + * @property {string} [device_platform] + */ + +/** + * @typedef {object} FeedAdApiBidResponse + * @inner + * + * @property {string} ad - Ad HTML payload + * @property {number} cpm - number / float + * @property {string} creativeId - ID of creative for tracking + * @property {string} currency - 3-letter ISO 4217 currency-code + * @property {number} height - Height of creative returned in [].ad + * @property {boolean} netRevenue - Is the CPM net (true) or gross (false)? + * @property {string} requestId - bids[].bidId + * @property {number} ttl - Time to live for this ad + * @property {number} width - Width of creative returned in [].ad + */ + +/** + * @typedef {object} FeedAdApiTrackingParams + * @inner + * + * @property app_hybrid {boolean} + * @property client_token {string} + * @property klass {'prebid_bidWon'|'prebid_bidTimeout'} + * @property placement_id {string} + * @property prebid_auction_id {string} + * @property prebid_bid_id {string} + * @property prebid_transaction_id {string} + * @property referer {string} + * @property sdk_version {string} + * @property [app_bundle_id] {string} + * @property [app_name] {string} + * @property [device_adid] {string} + * @property [device_platform] {1|2|3} 1 - Android | 2 - iOS | 3 - Windows + */ + +/** + * Bidder network identity code + * @type {string} + */ +const BIDDER_CODE = 'feedad'; + +/** + * The media types supported by FeedAd + * @type {MediaType[]} + */ +const MEDIA_TYPES = [VIDEO, BANNER]; + +/** + * Tag for logging + * @type {string} + */ +const TAG = '[FeedAd]'; + +/** + * Pattern for valid placement IDs + * @type {RegExp} + */ +const PLACEMENT_ID_PATTERN = /^[a-z0-9][a-z0-9_-]+[a-z0-9]$/; + +const API_ENDPOINT = 'https://api.feedad.com'; +const API_PATH_BID_REQUEST = '/1/prebid/web/bids'; +const API_PATH_TRACK_REQUEST = '/1/prebid/web/events'; + +/** + * Stores temporary auction metadata + * @type {Object.} + */ +const BID_METADATA = {}; + +/** + * Checks if the bid is compatible with FeedAd. + * + * @param {BidRequest} bid - the bid to check + * @return {boolean} true if the bid is valid + */ +function isBidRequestValid(bid) { + const clientToken = utils.deepAccess(bid, 'params.clientToken'); + if (!clientToken || !isValidClientToken(clientToken)) { + utils.logWarn(TAG, "missing or invalid parameter 'clientToken'. found value:", clientToken); + return false; + } + + const placementId = utils.deepAccess(bid, 'params.placementId'); + if (!placementId || !isValidPlacementId(placementId)) { + utils.logWarn(TAG, "missing or invalid parameter 'placementId'. found value:", placementId); + return false; + } + + return true; +} + +/** + * Checks if a client token is valid + * @param {string} clientToken - the client token + * @return {boolean} true if the token is valid + */ +function isValidClientToken(clientToken) { + return typeof clientToken === 'string' && clientToken.length > 0; +} + +/** + * Checks if the given placement id is of a correct format. + * Valid IDs are words of lowercase letters from a to z and numbers from 0 to 9. + * The words can be separated by hyphens or underscores. + * Multiple separators must not follow each other. + * The whole placement ID must not be larger than 256 characters. + * + * @param placementId - the placement id to verify + * @returns if the placement ID is valid. + */ +function isValidPlacementId(placementId) { + return typeof placementId === 'string' && + placementId.length > 0 && + placementId.length <= 256 && + PLACEMENT_ID_PATTERN.test(placementId); +} + +/** + * Checks if the given media types contain unsupported settings + * @param {MediaTypes} mediaTypes - the media types to check + * @return {MediaTypes} the unsupported settings, empty when all types are supported + */ +function filterSupportedMediaTypes(mediaTypes) { + return { + banner: mediaTypes.banner, + video: mediaTypes.video && mediaTypes.video.context === 'outstream' ? mediaTypes.video : undefined, + native: undefined + }; +} + +/** + * Checks if the given media types are empty + * @param {MediaTypes} mediaTypes - the types to check + * @return {boolean} true if the types are empty + */ +function isMediaTypesEmpty(mediaTypes) { + return Object.keys(mediaTypes).every(type => mediaTypes[type] === undefined); +} + +/** + * Creates the bid request params the api expects from the prebid bid request + * @param {BidRequest} request - the validated prebid bid request + * @return {FeedAdApiBidRequest} + */ +function createApiBidRParams(request) { + return { + ad_type: 0, + client_token: request.params.clientToken, + placement_id: request.params.placementId, + sdk_version: `prebid_${VERSION}`, + app_hybrid: false, + }; +} + +/** + * Builds the bid request to the FeedAd Server + * @param {BidRequest[]} validBidRequests - all validated bid requests + * @param {object} bidderRequest - meta information + * @return {ServerRequest|ServerRequest[]} + */ +function buildRequests(validBidRequests, bidderRequest) { + if (!bidderRequest) { + return []; + } + let acceptableRequests = validBidRequests.filter(request => !isMediaTypesEmpty(filterSupportedMediaTypes(request.mediaTypes))); + if (acceptableRequests.length === 0) { + return []; + } + let data = Object.assign({}, bidderRequest, { + bids: acceptableRequests.map(req => { + req.params = createApiBidRParams(req); + return req; + }) + }); + data.bids.forEach(bid => BID_METADATA[bid.bidId] = { + referer: data.refererInfo.referer, + transactionId: bid.transactionId + }); + return { + method: 'POST', + url: `${API_ENDPOINT}${API_PATH_BID_REQUEST}`, + data, + options: { + contentType: 'application/json' + } + }; +} + +/** + * Adapts the FeedAd server response to Prebid format + * @param {ServerResponse} serverResponse - the FeedAd server response + * @param {BidRequest} request - the initial bid request + * @returns {Bid[]} the FeedAd bids + */ +function interpretResponse(serverResponse, request) { + /** + * @type FeedAdApiBidResponse[] + */ + return typeof serverResponse.body === 'string' ? JSON.parse(serverResponse.body) : serverResponse.body; +} + +/** + * Creates the parameters for the FeedAd tracking call + * @param {object} data - prebid data + * @param {'prebid_bidWon'|'prebid_bidTimeout'} klass - type of tracking call + * @return {FeedAdApiTrackingParams|null} + */ +function createTrackingParams(data, klass) { + const bidId = data.bidId || data.requestId; + if (!BID_METADATA.hasOwnProperty(bidId)) { + return null; + } + const {referer, transactionId} = BID_METADATA[bidId]; + delete BID_METADATA[bidId]; + return { + app_hybrid: false, + client_token: data.params[0].clientToken, + placement_id: data.params[0].placementId, + klass, + prebid_auction_id: data.auctionId, + prebid_bid_id: bidId, + prebid_transaction_id: transactionId, + referer, + sdk_version: VERSION + }; +} + +/** + * Creates a tracking handler for the given event type + * @param klass - the event type + * @return {Function} the tracking handler function + */ +function trackingHandlerFactory(klass) { + return (data) => { + if (!data) { + return; + } + let params = createTrackingParams(data, klass); + if (params) { + ajax(`${API_ENDPOINT}${API_PATH_TRACK_REQUEST}`, null, JSON.stringify(params), { + withCredentials: true, + method: 'POST', + contentType: 'application/json' + }); + } + } +} + +/** + * @type {BidderSpec} + */ +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: MEDIA_TYPES, + isBidRequestValid, + buildRequests, + interpretResponse, + onTimeout: trackingHandlerFactory('prebid_bidTimeout'), + onBidWon: trackingHandlerFactory('prebid_bidWon') +}; + +registerBidder(spec); diff --git a/modules/feedadBidAdapter.md b/modules/feedadBidAdapter.md new file mode 100644 index 00000000000..fd57025c29e --- /dev/null +++ b/modules/feedadBidAdapter.md @@ -0,0 +1,44 @@ +# Overview + +``` +Module Name: FeedAd Adapter +Module Type: Bidder Adapter +Maintainer: mail@feedad.com +``` + +# Description + +Prebid.JS adapter that connects to the FeedAd demand sources. + +# Test Parameters +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { // supports all banner sizes + sizes: [[300, 250]], + }, + video: { // supports only outstream video + context: 'outstream' + } + }, + bids: [ + { + bidder: "feedad", + params: { + clientToken: 'your-client-token' // see below for more info + placementId: 'your-placement-id' // see below for more info + } + } + ] + } + ]; +``` + +# Required Parameters + +| Parameter | Description | +| --------- | ----------- | +| `clientToken` | Your FeedAd web client token. You can view your client token inside the FeedAd admin panel. | +| `placementId` | You can choose placement IDs yourself. A placement ID should be named after the ad position inside your product. For example, if you want to display an ad inside a list of news articles, you could name it "ad-news-overview".
A placement ID may consist of lowercase `a-z`, `0-9`, `-` and `_`. You do not have to manually create the placement IDs before using them. Just specify them within the code, and they will appear in the FeedAd admin panel after the first request.
[Learn more](/concept/feed_ad/index.html) about Placement IDs and how they are grouped to play the same Creative. | diff --git a/modules/fidelityBidAdapter.js b/modules/fidelityBidAdapter.js index 078e9d2fcce..baf5384fbfe 100644 --- a/modules/fidelityBidAdapter.js +++ b/modules/fidelityBidAdapter.js @@ -1,15 +1,17 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'fidelity'; const BIDDER_SERVER = 'x.fidelity-media.com'; const FIDELITY_VENDOR_ID = 408; export const spec = { code: BIDDER_CODE, - isBidRequestValid: function(bid) { + aliases: ['kubient'], + gvlid: 408, + isBidRequestValid: function isBidRequestValid(bid) { return !!(bid && bid.params && bid.params.zoneid); }, - buildRequests: function(validBidRequests, bidderRequest) { + buildRequests: function buildRequests(validBidRequests, bidderRequest) { return validBidRequests.map(bidRequest => { var server = bidRequest.params.server || BIDDER_SERVER; @@ -24,19 +26,20 @@ export const spec = { subid: 'hb', flashver: getFlashVersion(), tmax: bidderRequest.timeout, - defloc: utils.getTopWindowUrl(), - referrer: utils.getTopWindowReferrer(), + defloc: bidderRequest.refererInfo.referer, + referrer: getTopWindowReferrer(), + schain: getSupplyChain(bidRequest.schain), }; - setConsentParams(bidderRequest.gdprConsent, payload); + setConsentParams(bidderRequest.gdprConsent, bidderRequest.uspConsent, payload); return { method: 'GET', - url: '//' + server + '/delivery/hb.php', + url: 'https://' + server + '/delivery/hb.php', data: payload }; }); }, - interpretResponse: function(serverResponse) { + interpretResponse: function interpretResponse(serverResponse) { serverResponse = serverResponse.body; const bidResponses = []; if (serverResponse && serverResponse.seatbid) { @@ -58,13 +61,13 @@ export const spec = { } return bidResponses; }, - getUserSyncs: function getUserSyncs(syncOptions, serverResponses, gdprConsent) { + getUserSyncs: function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { if (syncOptions.iframeEnabled) { - var url = '//' + BIDDER_SERVER + '/delivery/matches.php'; + var url = 'https://' + BIDDER_SERVER + '/delivery/matches.php'; var payload = { type: 'iframe' }; - setConsentParams(gdprConsent, payload); + setConsentParams(gdprConsent, uspConsent, payload); return [{ type: 'iframe', @@ -89,7 +92,15 @@ function getFlashVersion() { return result || ''; } -function setConsentParams(gdprConsent, payload) { +function getTopWindowReferrer() { + try { + return window.top.document.referrer; + } catch (e) { + return ''; + } +} + +function setConsentParams(gdprConsent, uspConsent, payload) { if (gdprConsent) { payload.gdpr = 0; payload.consent_str = ''; @@ -100,10 +111,37 @@ function setConsentParams(gdprConsent, payload) { if (typeof gdprConsent.consentString !== 'undefined') { payload.consent_str = gdprConsent.consentString; } - if (gdprConsent.vendorData && gdprConsent.vendorData.vendorConsents && typeof gdprConsent.vendorData.vendorConsents[FIDELITY_VENDOR_ID.toString(10)] !== 'undefined') { + if (gdprConsent.apiVersion === 1 && gdprConsent.vendorData && gdprConsent.vendorData.vendorConsents && typeof gdprConsent.vendorData.vendorConsents[FIDELITY_VENDOR_ID.toString(10)] !== 'undefined') { payload.consent_given = gdprConsent.vendorData.vendorConsents[FIDELITY_VENDOR_ID.toString(10)] ? 1 : 0; } + if (gdprConsent.apiVersion === 2 && gdprConsent.vendorData && gdprConsent.vendorData.vendor && gdprConsent.vendorData.vendor.consents && typeof gdprConsent.vendorData.vendor.consents[FIDELITY_VENDOR_ID.toString(10)] !== 'undefined') { + payload.consent_given = gdprConsent.vendorData.vendor.consents[FIDELITY_VENDOR_ID.toString(10)] ? 1 : 0; + } + } + if (typeof uspConsent !== 'undefined') { + payload.us_privacy = uspConsent; } } +function getSupplyChain(schain) { + var supplyChain = ''; + if (schain != null && schain.nodes) { + supplyChain = schain.ver + ',' + schain.complete; + for (let i = 0; i < schain.nodes.length; i++) { + supplyChain += '!'; + supplyChain += (schain.nodes[i].asi) ? encodeURIComponent(schain.nodes[i].asi) : ''; + supplyChain += ','; + supplyChain += (schain.nodes[i].sid) ? encodeURIComponent(schain.nodes[i].sid) : ''; + supplyChain += ','; + supplyChain += (schain.nodes[i].hp) ? encodeURIComponent(schain.nodes[i].hp) : ''; + supplyChain += ','; + supplyChain += (schain.nodes[i].rid) ? encodeURIComponent(schain.nodes[i].rid) : ''; + supplyChain += ','; + supplyChain += (schain.nodes[i].name) ? encodeURIComponent(schain.nodes[i].name) : ''; + supplyChain += ','; + supplyChain += (schain.nodes[i].domain) ? encodeURIComponent(schain.nodes[i].domain) : ''; + } + } + return supplyChain; +} registerBidder(spec); diff --git a/modules/fidelityBidAdapter.md b/modules/fidelityBidAdapter.md index a4f1e91cd3d..0af75689bd6 100644 --- a/modules/fidelityBidAdapter.md +++ b/modules/fidelityBidAdapter.md @@ -1,18 +1,22 @@ # Overview - +​ **Module Name**: Fidelity Media fmxSSP Bidder Adapter **Module Type**: Bidder Adapter **Maintainer**: on@fidelity-media.com - +​ # Description - +​ Connects to Fidelity Media fmxSSP demand source to fetch bids. - +​ # Test Parameters -``` +``` var adUnits = [{ code: 'banner-ad-div', - sizes: [[300, 250]], + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, bids: [{ bidder: 'fidelity', params: { @@ -23,4 +27,4 @@ Connects to Fidelity Media fmxSSP demand source to fetch bids. }] }]; -``` +``` \ No newline at end of file diff --git a/modules/fintezaAnalyticsAdapter.js b/modules/fintezaAnalyticsAdapter.js index 097d56e05f3..8729035491f 100644 --- a/modules/fintezaAnalyticsAdapter.js +++ b/modules/fintezaAnalyticsAdapter.js @@ -1,9 +1,10 @@ -import { ajax } from '../src/ajax'; -import adapter from '../src/AnalyticsAdapter'; -import adapterManager from '../src/adapterManager'; -import * as utils from '../src/utils'; -import { parse as parseURL } from '../src/url'; +import { ajax } from '../src/ajax.js'; +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; +import { getStorageManager } from '../src/storageManager.js'; +const storage = getStorageManager(); const CONSTANTS = require('../src/constants.json'); const ANALYTICS_TYPE = 'endpoint'; @@ -19,6 +20,7 @@ const SESSION_ID = '_fz_ssn'; const SESSION_DURATION = 30 * 60 * 1000; const SESSION_RAND_PART = 9; const TRACK_TIME_KEY = '_fz_tr'; +const UNIQ_ID_KEY = '_fz_uniq'; function getPageInfo() { const pageInfo = { @@ -26,12 +28,48 @@ function getPageInfo() { } if (document.referrer) { - pageInfo.referrerDomain = parseURL(document.referrer).hostname; + pageInfo.referrerDomain = utils.parseUrl(document.referrer).hostname; } return pageInfo; } +function getUniqId() { + let cookies; + + try { + cookies = parseCookies(document.cookie); + } catch (a) { + cookies = {}; + } + + let isUniqFromLS; + let uniq = cookies[ UNIQ_ID_KEY ]; + if (!uniq) { + try { + if (storage.hasLocalStorage()) { + uniq = storage.getDataFromLocalStorage(UNIQ_ID_KEY) || ''; + isUniqFromLS = true; + } + } catch (b) {} + } + + if (uniq && isNaN(uniq)) { + uniq = null; + } + + if (uniq && isUniqFromLS) { + let expires = new Date(); + expires.setFullYear(expires.getFullYear() + 10); + + try { + storage.setCookie(UNIQ_ID_KEY, uniq, expires.toUTCString()); + } catch (e) {} + } + + return uniq; +} + function initFirstVisit() { let now; let visitDate; @@ -53,7 +91,7 @@ function initFirstVisit() { now.setFullYear(now.getFullYear() + 20); try { - document.cookie = FIRST_VISIT_DATE + '=' + visitDate + '; path=/; expires=' + now.toUTCString(); + storage.setCookie(FIRST_VISIT_DATE, visitDate, now.toUTCString()); } catch (e) {} } @@ -73,7 +111,7 @@ function parseCookies(cookie) { let param, value; let i, j; - if (!cookie) { + if (!cookie || !storage.cookiesAreEnabled()) { return {}; } @@ -166,7 +204,7 @@ function initSession() { } try { - document.cookie = SESSION_ID + '=' + sessionId + '; path=/; expires=' + expires.toUTCString(); + storage.setCookie(SESSION_ID, sessionId, expires.toUTCString()); } catch (e) {} return { @@ -212,10 +250,10 @@ function saveTrackRequestTime() { const expires = new Date(now + SESSION_DURATION); try { - if (window.localStorage) { - window.localStorage.setItem(TRACK_TIME_KEY, now.toString()); + if (storage.hasLocalStorage()) { + storage.setDataInLocalStorage(TRACK_TIME_KEY, now.toString()); } else { - document.cookie = TRACK_TIME_KEY + '=' + now + '; path=/; expires=' + expires.toUTCString(); + storage.setCookie(TRACK_TIME_KEY, now.toString(), expires.toUTCString()); } } catch (a) {} } @@ -224,9 +262,9 @@ function getTrackRequestLastTime() { let cookie; try { - if (window.localStorage) { + if (storage.hasLocalStorage()) { return parseInt( - window.localStorage.getItem(TRACK_TIME_KEY) || 0, + storage.getDataFromLocalStorage(TRACK_TIME_KEY) || 0, 10, ); } @@ -330,6 +368,10 @@ function prepareTrackData(evtype, args) { ac: getAntiCacheParam(), }) + if (fntzAnalyticsAdapter.context.uniqId) { + trackData.fz_uniq = fntzAnalyticsAdapter.context.uniqId; + } + if (session.id) { trackData.ssn = session.id; } @@ -347,12 +389,12 @@ function sendTrackRequest(trackData) { try { ajax( fntzAnalyticsAdapter.context.host, - null, // Callback + null, trackData, { method: 'GET', - contentType: 'application/x-www-form-urlencoded', - // preflight: true, + withCredentials: true, + contentType: 'application/x-www-form-urlencoded' }, ); saveTrackRequestTime(); @@ -396,6 +438,7 @@ fntzAnalyticsAdapter.enableAnalytics = function (config) { bidWonTrack: config.options.bidWonTrack || BID_WON_TRACK, firstVisit: initFirstVisit(), screenResolution: `${window.screen.width}x${window.screen.height}`, + uniqId: getUniqId(), pageInfo: getPageInfo(), }; diff --git a/modules/fluctBidAdapter.js b/modules/fluctBidAdapter.js new file mode 100644 index 00000000000..420fe04ddcb --- /dev/null +++ b/modules/fluctBidAdapter.js @@ -0,0 +1,121 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'fluct'; +const END_POINT = 'https://hb.adingo.jp/prebid'; +const VERSION = '1.2'; +const NET_REVENUE = true; +const TTL = 300; + +export const spec = { + code: BIDDER_CODE, + aliases: ['adingo'], + + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: (bid) => { + return !!(bid.params.groupId && bid.params.tagId); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids. + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: (validBidRequests, bidderRequest) => { + const serverRequests = []; + const referer = bidderRequest.refererInfo.referer; + + utils._each(validBidRequests, (request) => { + const data = Object(); + + data.referer = referer; + data.adUnitCode = request.adUnitCode; + data.bidId = request.bidId; + data.transactionId = request.transactionId; + + data.sizes = []; + utils._each(request.sizes, (size) => { + data.sizes.push({ + w: size[0], + h: size[1] + }); + }); + + data.params = request.params; + + serverRequests.push({ + method: 'POST', + url: END_POINT, + options: { + contentType: 'application/json', + withCredentials: true, + customHeaders: { + 'x-fluct-app': 'prebid/fluctBidAdapter', + 'x-fluct-version': VERSION, + 'x-openrtb-version': 2.5 + } + }, + data: data + }); + }); + + return serverRequests; + }, + + /* + * Unpack the respnse from the server into a list of bids. + * + * @param {serverResponse} serverResponse A successful response from the server. + * @return {bid[]} An array of bids which weer nested inside the server. + */ + interpretResponse: (serverResponse, serverRequest) => { + const bidResponses = []; + + const res = serverResponse.body; + if (!utils.isEmpty(res) && !utils.isEmpty(res.seatbid) && !utils.isEmpty(res.seatbid[0].bid)) { + const bid = res.seatbid[0].bid[0]; + const dealId = bid.dealid; + const beaconUrl = bid.burl; + const callImpBeacon = ``; + let data = { + bidderCode: BIDDER_CODE, + requestId: res.id, + currency: res.cur, + cpm: parseFloat(bid.price) || 0, + netRevenue: NET_REVENUE, + width: bid.w, + height: bid.h, + creativeId: bid.crid, + ttl: TTL, + ad: bid.adm + callImpBeacon, + }; + if (!utils.isEmpty(dealId)) { + data.dealId = dealId; + } + bidResponses.push(data); + } + return bidResponses; + }, + + /* + * Register the user sync pixels which should be dropped after the auction. + * + * @params {syncOptions} syncOptions which user syncs are allowed? + * @params {ServerResponse[]} serverResponses List of server's responses. + * @return {UserSync[]} The user syncs which should be dropped. + * + */ + getUserSyncs: (syncOptions, serverResponses) => { + return []; + }, +}; + +registerBidder(spec); diff --git a/modules/fluctBidAdapter.md b/modules/fluctBidAdapter.md new file mode 100644 index 00000000000..a1dc4d6f225 --- /dev/null +++ b/modules/fluctBidAdapter.md @@ -0,0 +1,36 @@ +# Overview + +``` +Module Name: fluct Bid Adapter +Module Type: Bidder Adapter +Maintainer: developer@fluct.jp +``` + +# Description + +Connects to fluct exchange for bids. + +# Test parameters + +``` +var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: 'fluct', + params: { + tagId: '25405:1000192893', + groupId: '1000105712', + dfpUnitCode: '/62532913/s_fluct.test_hb_prebid_11940', // Optional + } + } + ] + } +] +``` diff --git a/modules/freeWheelAdserverVideo.js b/modules/freeWheelAdserverVideo.js index c81f3356d71..cb4bd938373 100644 --- a/modules/freeWheelAdserverVideo.js +++ b/modules/freeWheelAdserverVideo.js @@ -2,153 +2,18 @@ * This module adds Freewheel support for Video to Prebid. */ -import { registerVideoSupport } from '../src/adServerManager'; -import { auctionManager } from '../src/auctionManager'; -import { groupBy, deepAccess, logError, compareOn } from '../src/utils'; -import { config } from '../src/config'; -import { ADPOD } from '../src/mediaTypes'; -import { initAdpodHooks, TARGETING_KEY_PB_CAT_DUR, TARGETING_KEY_CACHE_ID, callPrebidCacheAfterAuction, sortByPricePerSecond } from './adpod'; -import { getHook } from '../src/hook'; +import { registerVideoSupport } from '../src/adServerManager.js'; +import { getHook, submodule } from '../src/hook.js'; +export const adpodUtils = {}; export function notifyTranslationModule(fn) { fn.call(this, 'freewheel'); } getHook('registerAdserver').before(notifyTranslationModule); -/** - * This function returns targeting keyvalue pairs for freewheel adserver module - * @param {Object} options - * @param {Array[string]} codes - * @param {function} callback - * @returns targeting kvs for adUnitCodes - */ -export function getTargeting({codes, callback} = {}) { - if (!callback) { - logError('No callback function was defined in the getTargeting call. Aborting getTargeting().'); - return; - } - codes = codes || []; - const adPodAdUnits = getAdPodAdUnits(codes); - const bidsReceived = auctionManager.getBidsReceived(); - const competiveExclusionEnabled = config.getConfig('adpod.brandCategoryExclusion'); - const deferCachingSetting = config.getConfig('adpod.deferCaching'); - const deferCachingEnabled = (typeof deferCachingSetting === 'boolean') ? deferCachingSetting : true; - - let bids = getBidsForAdpod(bidsReceived, adPodAdUnits); - bids = (competiveExclusionEnabled || deferCachingEnabled) ? getExclusiveBids(bids) : bids; - bids.sort(sortByPricePerSecond); - - let targeting = {}; - if (deferCachingEnabled === false) { - adPodAdUnits.forEach((adUnit) => { - let adPodTargeting = []; - let adPodDurationSeconds = deepAccess(adUnit, 'mediaTypes.video.adPodDurationSec'); - - bids - .filter((bid) => bid.adUnitCode === adUnit.code) - .forEach((bid, index, arr) => { - if (bid.video.durationBucket <= adPodDurationSeconds) { - adPodTargeting.push({ - [TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR] - }); - adPodDurationSeconds -= bid.video.durationBucket; - } - if (index === arr.length - 1 && adPodTargeting.length > 0) { - adPodTargeting.push({ - [TARGETING_KEY_CACHE_ID]: bid.adserverTargeting[TARGETING_KEY_CACHE_ID] - }); - } - }); - targeting[adUnit.code] = adPodTargeting; - }); - - callback(null, targeting); - } else { - let bidsToCache = []; - adPodAdUnits.forEach((adUnit) => { - let adPodDurationSeconds = deepAccess(adUnit, 'mediaTypes.video.adPodDurationSec'); - - bids - .filter((bid) => bid.adUnitCode === adUnit.code) - .forEach((bid) => { - if (bid.video.durationBucket <= adPodDurationSeconds) { - bidsToCache.push(bid); - adPodDurationSeconds -= bid.video.durationBucket; - } - }); - }); - - callPrebidCacheAfterAuction(bidsToCache, function(error, bidsSuccessfullyCached) { - if (error) { - callback(error, null); - } else { - let groupedBids = groupBy(bidsSuccessfullyCached, 'adUnitCode'); - Object.keys(groupedBids).forEach((adUnitCode) => { - let adPodTargeting = []; - - groupedBids[adUnitCode].forEach((bid, index, arr) => { - adPodTargeting.push({ - [TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR] - }); - - if (index === arr.length - 1 && adPodTargeting.length > 0) { - adPodTargeting.push({ - [TARGETING_KEY_CACHE_ID]: bid.adserverTargeting[TARGETING_KEY_CACHE_ID] - }); - } - }); - targeting[adUnitCode] = adPodTargeting; - }); - - callback(null, targeting); - } - }); - } - return targeting; -} - -/** - * This function returns the adunit of mediaType adpod - * @param {Array} codes adUnitCodes - * @returns {Array[Object]} adunits of mediaType adpod - */ -function getAdPodAdUnits(codes) { - return auctionManager.getAdUnits() - .filter((adUnit) => deepAccess(adUnit, 'mediaTypes.video.context') === ADPOD) - .filter((adUnit) => (codes.length > 0) ? codes.indexOf(adUnit.code) != -1 : true); -} - -/** - * This function removes bids of same freewheel category. It will be used when competitive exclusion is enabled. - * @param {Array[Object]} bidsReceived - * @returns {Array[Object]} unique freewheel category bids - */ -function getExclusiveBids(bidsReceived) { - let bids = bidsReceived - .map((bid) => Object.assign({}, bid, {[TARGETING_KEY_PB_CAT_DUR]: bid.adserverTargeting[TARGETING_KEY_PB_CAT_DUR]})); - bids = groupBy(bids, TARGETING_KEY_PB_CAT_DUR); - let filteredBids = []; - Object.keys(bids).forEach((targetingKey) => { - bids[targetingKey].sort(compareOn('responseTimestamp')); - filteredBids.push(bids[targetingKey][0]); - }); - return filteredBids; -} - -/** - * This function returns bids for adpod adunits - * @param {Array[Object]} bidsReceived - * @param {Array[Object]} adPodAdUnits - * @returns {Array[Object]} bids of mediaType adpod - */ -function getBidsForAdpod(bidsReceived, adPodAdUnits) { - let adUnitCodes = adPodAdUnits.map((adUnit) => adUnit.code); - return bidsReceived - .filter((bid) => adUnitCodes.indexOf(bid.adUnitCode) != -1 && (bid.video && bid.video.context === ADPOD)) -} - -initAdpodHooks(); registerVideoSupport('freewheel', { - getTargeting: getTargeting + getTargeting: (args) => adpodUtils.getTargeting(args) }); + +submodule('adpod', adpodUtils); diff --git a/modules/freewheel-sspBidAdapter.js b/modules/freewheel-sspBidAdapter.js index 3e52ba2cbe9..e1db7d5e1d3 100644 --- a/modules/freewheel-sspBidAdapter.js +++ b/modules/freewheel-sspBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -// import { config } from '../src/config'; +import * as utils from '../src/utils.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'freewheel-ssp'; @@ -11,11 +11,7 @@ const PRIMETIME_URL = PROTOCOL + '://cdn.stickyadstv.com/prime-time/'; const USER_SYNC_URL = PROTOCOL + '://ads.stickyadstv.com/auto-user-sync'; function getProtocol() { - if (location.protocol && location.protocol.indexOf('https') === 0) { - return 'https'; - } else { - return 'http'; - } + return 'https'; } function isValidUrl(str) { @@ -38,6 +34,20 @@ function getBiggerSize(array) { return result; } +function getBiggerSizeWithLimit(array, minSizeLimit, maxSizeLimit) { + var minSize = minSizeLimit || [0, 0]; + var maxSize = maxSizeLimit || [Number.MAX_VALUE, Number.MAX_VALUE]; + var candidates = []; + + for (var i = 0; i < array.length; i++) { + if (array[i][0] * array[i][1] >= minSize[0] * minSize[1] && array[i][0] * array[i][1] <= maxSize[0] * maxSize[1]) { + candidates.push(array[i]); + } + } + + return getBiggerSize(candidates); +} + /* * read the pricing extension with this format: 1.0000 * @return {object} pricing data in format: {currency: "EUR", price:"1.000"} @@ -92,6 +102,24 @@ function getCreativeId(xmlNode) { return creaId; } +function getDealId(xmlNode) { + var dealId = ''; + var impNodes = xmlNode.querySelectorAll('Impression'); // Nodelist.forEach is not supported in IE and Edge + // Workaround given here https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10638731/ + + Array.prototype.forEach.call(impNodes, function (el) { + var queries = el.textContent.substring(el.textContent.indexOf('?') + 1).split('&'); + Array.prototype.forEach.call(queries, function (item) { + var split = item.split('='); + if (split[0] == 'dealId') { + dealId = split[1]; + } + }); + }); + + return dealId; +} + /** * returns the top most accessible window */ @@ -204,7 +232,7 @@ var getOutstreamScript = function(bid) { export const spec = { code: BIDDER_CODE, - supportedMediaTypes: ['banner', 'video'], + supportedMediaTypes: [BANNER, VIDEO], aliases: ['stickyadstv'], // former name for freewheel-ssp /** * Determines whether or not the given bid request is valid. @@ -225,62 +253,82 @@ export const spec = { buildRequests: function(bidRequests, bidderRequest) { // var currency = config.getConfig(currency); - var currentBidRequest = bidRequests[0]; - if (bidRequests.length > 1) { - utils.logMessage('Prebid.JS - freewheel bid adapter: only one ad unit is required.'); - } + let buildRequest = (currentBidRequest, bidderRequest) => { + var zone = currentBidRequest.params.zoneId; + var timeInMillis = new Date().getTime(); + var keyCode = hashcode(zone + '' + timeInMillis); + var requestParams = { + reqType: 'AdsSetup', + protocolVersion: '2.0', + zoneId: zone, + componentId: getComponentId(currentBidRequest.params.format), + timestamp: timeInMillis, + pKey: keyCode + }; - var zone = currentBidRequest.params.zoneId; - var timeInMillis = new Date().getTime(); - var keyCode = hashcode(zone + '' + timeInMillis); - - var requestParams = { - reqType: 'AdsSetup', - protocolVersion: '2.0', - zoneId: zone, - componentId: getComponentId(currentBidRequest.params.format), - timestamp: timeInMillis, - pKey: keyCode - }; + // Add GDPR flag and consent string + if (bidderRequest && bidderRequest.gdprConsent) { + requestParams._fw_gdpr_consent = bidderRequest.gdprConsent.consentString; - // Add GDPR flag and consent string - if (bidderRequest.gdprConsent) { - requestParams._fw_gdpr_consent = bidderRequest.gdprConsent.consentString; + if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { + requestParams._fw_gdpr = bidderRequest.gdprConsent.gdprApplies; + } + } - if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { - requestParams._fw_gdpr = bidderRequest.gdprConsent.gdprApplies; + if (currentBidRequest.params.gdpr_consented_providers) { + requestParams._fw_gdpr_consented_providers = currentBidRequest.params.gdpr_consented_providers; } - } - if (currentBidRequest.params.gdpr_consented_providers) { - requestParams._fw_gdpr_consented_providers = currentBidRequest.params.gdpr_consented_providers; - } + // Add CCPA consent string + if (bidderRequest && bidderRequest.uspConsent) { + requestParams._fw_us_privacy = bidderRequest.uspConsent; + } - var vastParams = currentBidRequest.params.vastUrlParams; - if (typeof vastParams === 'object') { - for (var key in vastParams) { - if (vastParams.hasOwnProperty(key)) { - requestParams[key] = vastParams[key]; + var vastParams = currentBidRequest.params.vastUrlParams; + if (typeof vastParams === 'object') { + for (var key in vastParams) { + if (vastParams.hasOwnProperty(key)) { + requestParams[key] = vastParams[key]; + } } } - } - var location = utils.getTopWindowUrl(); - if (isValidUrl(location)) { - requestParams.loc = location; - } + var location = (bidderRequest && bidderRequest.refererInfo) ? bidderRequest.refererInfo.referer : getTopMostWindow().location.href; + if (isValidUrl(location)) { + requestParams.loc = location; + } - var playerSize = getBiggerSize(currentBidRequest.sizes); - if (playerSize[0] > 0 || playerSize[1] > 0) { - requestParams.playerSize = playerSize[0] + 'x' + playerSize[1]; - } + var playerSize = []; + if (currentBidRequest.mediaTypes.video && currentBidRequest.mediaTypes.video.playerSize) { + // If mediaTypes is video, get size from mediaTypes.video.playerSize per http://prebid.org/blog/pbjs-3 + if (utils.isArray(currentBidRequest.mediaTypes.video.playerSize[0])) { + playerSize = currentBidRequest.mediaTypes.video.playerSize[0]; + } else { + playerSize = currentBidRequest.mediaTypes.video.playerSize; + } + } else if (currentBidRequest.mediaTypes.banner.sizes) { + // If mediaTypes is banner, get size from mediaTypes.banner.sizes per http://prebid.org/blog/pbjs-3 + playerSize = getBiggerSizeWithLimit(currentBidRequest.mediaTypes.banner.sizes, currentBidRequest.mediaTypes.banner.minSizeLimit, currentBidRequest.mediaTypes.banner.maxSizeLimit); + } else { + // Backward compatible code, in case size still pass by sizes in bid request + playerSize = getBiggerSize(currentBidRequest.sizes); + } - return { - method: 'GET', - url: FREEWHEEL_ADSSETUP, - data: requestParams, - bidRequest: currentBidRequest + if (playerSize[0] > 0 || playerSize[1] > 0) { + requestParams.playerSize = playerSize[0] + 'x' + playerSize[1]; + } + + return { + method: 'GET', + url: FREEWHEEL_ADSSETUP, + data: requestParams, + bidRequest: currentBidRequest + }; }; + + return bidRequests.map(function(currentBidRequest) { + return buildRequest(currentBidRequest, bidderRequest); + }); }, /** @@ -292,7 +340,21 @@ export const spec = { */ interpretResponse: function(serverResponse, request) { var bidrequest = request.bidRequest; - var playerSize = getBiggerSize(bidrequest.sizes); + var playerSize = []; + if (bidrequest.mediaTypes.video && bidrequest.mediaTypes.video.playerSize) { + // If mediaTypes is video, get size from mediaTypes.video.playerSize per http://prebid.org/blog/pbjs-3 + if (utils.isArray(bidrequest.mediaTypes.video.playerSize[0])) { + playerSize = bidrequest.mediaTypes.video.playerSize[0]; + } else { + playerSize = bidrequest.mediaTypes.video.playerSize; + } + } else if (bidrequest.mediaTypes.banner.sizes) { + // If mediaTypes is banner, get size from mediaTypes.banner.sizes per http://prebid.org/blog/pbjs-3 + playerSize = getBiggerSizeWithLimit(bidrequest.mediaTypes.banner.sizes, bidrequest.mediaTypes.banner.minSizeLimit, bidrequest.mediaTypes.banner.maxSizeLimit); + } else { + // Backward compatible code, in case size still pass by sizes in bid request + playerSize = getBiggerSize(bidrequest.sizes); + } if (typeof serverResponse == 'object' && typeof serverResponse.body == 'string') { serverResponse = serverResponse.body; @@ -309,6 +371,7 @@ export const spec = { const princingData = getPricing(xmlDoc); const creativeId = getCreativeId(xmlDoc); + const dealId = getDealId(xmlDoc); const topWin = getTopMostWindow(); if (!topWin.freewheelssp_cache) { @@ -327,20 +390,16 @@ export const spec = { creativeId: creativeId, currency: princingData.currency, netRevenue: true, - ttl: 360 + ttl: 360, + dealId: dealId }; - var mediaTypes = bidrequest.mediaTypes || {}; - if (mediaTypes.video) { - // bidResponse.vastXml = serverResponse; + if (bidrequest.mediaTypes.video) { + bidResponse.vastXml = serverResponse; bidResponse.mediaType = 'video'; - - var blob = new Blob([serverResponse], {type: 'application/xml'}); - bidResponse.vastUrl = window.URL.createObjectURL(blob); - } else { - bidResponse.ad = formatAdHTML(bidrequest, playerSize); } + bidResponse.ad = formatAdHTML(bidrequest, playerSize); bidResponses.push(bidResponse); } @@ -348,11 +407,13 @@ export const spec = { }, getUserSyncs: function(syncOptions) { - if (syncOptions.pixelEnabled) { + if (syncOptions && syncOptions.pixelEnabled) { return [{ type: 'image', url: USER_SYNC_URL }]; + } else { + return []; } }, diff --git a/modules/freewheel-sspBidAdapter.md b/modules/freewheel-sspBidAdapter.md index 70ab2415279..0086aac6567 100644 --- a/modules/freewheel-sspBidAdapter.md +++ b/modules/freewheel-sspBidAdapter.md @@ -13,15 +13,21 @@ Module that connects to Freewheel ssp's demand sources var adUnits = [ { code: 'test-div', - sizes: [[300, 250]], // a display size + + mediaTypes: { + banner: { + sizes: [[300, 250]], // a display size + } + }, + bids: [ { bidder: "freewheel-ssp", params: { - zoneId : '41852' + zoneId : '277225' } } ] } ]; -``` \ No newline at end of file +``` diff --git a/modules/fyberBidAdapter.js b/modules/fyberBidAdapter.js deleted file mode 100644 index 3586d0775ac..00000000000 --- a/modules/fyberBidAdapter.js +++ /dev/null @@ -1,378 +0,0 @@ -import {logError, getTopWindowUrl, getTopWindowReferrer, getTopWindowLocation, createTrackPixelHtml} from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { formatQS } from '../src/url'; -import { config } from '../src/config'; - -/** - * @type {{CODE: string, V: string, RECTANGLE_SIZE: {W: number, H: number}, SPOT_TYPES: {INTERSTITIAL: string, RECTANGLE: string, FLOATING: string, BANNER: string}, DISPLAY_AD: number, ENDPOINT_URL: string, EVENTS_ENDPOINT_URL: string, RESPONSE_HEADERS_NAME: {PRICING_VALUE: string, AD_H: string, AD_W: string}}} - */ -const CONSTANTS = { - CODE: 'fyber', - V: 'FY-JS-HB-PBJS-1.0', - RECTANGLE_SIZE: {W: 300, H: 250}, - - SPOT_TYPES: { - INTERSTITIAL: 'interstitial', - RECTANGLE: 'rectangle', - FLOATING: 'floating', - BANNER: 'banner' - }, - - DISPLAY_AD: 20, - ENDPOINT_URL: '//ad-tag.inner-active.mobi/simpleM2M/requestJsonAd', - EVENTS_ENDPOINT_URL: '//vast-events.inner-active.mobi/Event', - RESPONSE_HEADERS_NAME: { - PRICING_VALUE: 'X-IA-Pricing-Value', - AD_H: 'X-IA-Ad-Height', - AD_W: 'X-IA-Ad-Width', - CREATIVE_ID: 'X-IA-Creative-ID', - CURRENCY: 'X-IA-Pricing-Currency', - TIMEOUT: 'X-IA-SESSION-TIMEOUT' - } -}; - -/** - * gloable util functions - * @type {{defaultsQsParams: {v: (string|string), page: string, mw: boolean, hb: string}, stringToCamel: (function(*)), objectToCamel: (function(*=))}} - */ -const Helpers = { - defaultsQsParams: {v: CONSTANTS.V, page: encodeURIComponent(getTopWindowUrl()), mw: true, hb: 'prebidjs'}, - /** - * Returns the ad HTML template - * @param adHtml: string {ad server creative} - * @param tracking: object {impressions, clicks} - * @param bidParams: object - * @returns {string}: create template - */ - getAd(adHtml, tracking, bidParams) { - let impressionsHtml = ''; - if (tracking && Array.isArray(tracking.impressions)) { - let impressions = tracking.impressions; - impressions.push(Reporter.getEventUrl('HBPreBidImpression', bidParams, false)); - impressions.forEach(impression => impression && (impressionsHtml += createTrackPixelHtml(impression))); - } - adHtml = impressionsHtml + adHtml.replace(/ - - - - -
${adHtml}
- - - `; - return adTemplate; - }, - - /** - * Change string format from underscore to camelcase (e.g., APP_ID to appId) - * @param {string} str - * @return string - */ - stringToCamel(str) { - if (str.indexOf('_') === -1) { - const first = str.charAt(0); - if (first !== first.toLowerCase()) { - str = str.toLowerCase(); - } - return str; - } - - str = str.toLowerCase(); - return str.replace(/(\_[a-z])/g, $1 => $1.toUpperCase().replace('_', '')); - }, - - /** - * Change all object keys string format from underscore to camelcase (e.g., {'APP_ID' : ...} to {'appId' : ...}) - * @param params: object - * @returns object - */ - objectToCamel(params) { - Object.keys(params).forEach(key => { - const keyCamelCase = this.stringToCamel(key); - if (keyCamelCase !== key) { - params[keyCamelCase] = params[key]; - delete params[key]; - } - }); - return params; - }, - - /** - * @param {Object} params - * @return {string} url - */ - getEndpointUrl(params) { - return (params && params.qa && params.qa.url) || (Reporter.getPageProtocol() + CONSTANTS.ENDPOINT_URL); - }, - - /** - * Adjust bid params to fyber-ad-server params - * @param {Object} bid - * @return {Object} bid - */ - toBidParams(bid) { - const bidParamsWithCustomParams = Object.assign({}, bid.params, bid.params.customParams); - delete bidParamsWithCustomParams.customParams; - bid.params = this.objectToCamel(bidParamsWithCustomParams); - return bid; - }, - - /** - * Validate if response is valid - * @param responseAsJson : object - * @param headersData: {} - * @returns {boolean} - * @private - */ - isValidBidResponse(responseAsJson, headersData) { - return (responseAsJson && responseAsJson.ad && responseAsJson.ad.html && headersData && headersData[CONSTANTS.RESPONSE_HEADERS_NAME.PRICING_VALUE] > 0); - } -}; - -/** - * Url generator - generates a request URL - * @type {{defaultsParams: *, serverParamNameBySettingParamName: {referrer: string, keywords: string, appId: string, portal: string, age: string, gender: string, isSecured: (boolean|null)}, toServerParams: (function(*)), unwantedValues: *[], getUrlParams: (function(*=))}} - */ -const Url = { - defaultsParams: Object.assign({}, Helpers.defaultsQsParams, {f: CONSTANTS.DISPLAY_AD, fs: false, ref: getTopWindowReferrer()}), - serverParamNameBySettingParamName: { - referrer: 'ref', - keywords: 'k', - appId: 'aid', - portal: 'po', - age: 'a', - gender: 'g', - gdprPrivacyConsent: 'gdpr_privacy_consent', - consentString: 'consent_string', - gdprConsentData: 'gdpr_consent_data' - }, - unwantedValues: ['', null, undefined], - - /** - * Maps publisher params to server params - * @param params: object {k:v} - * @returns object {k:v} - */ - toServerParams(params) { - const serverParams = {}; - for (const paramName in params) { - if (params.hasOwnProperty(paramName) && this.serverParamNameBySettingParamName.hasOwnProperty(paramName)) { - serverParams[this.serverParamNameBySettingParamName[paramName]] = params[paramName]; - } else { - serverParams[paramName] = params[paramName]; - } - } - - serverParams.isSecured = Reporter.getPageProtocol() === 'https:' || null; - return serverParams; - }, - - handleGDPR(params) { - if (params.hasOwnProperty('gdprPrivacyConsent')) { - if (['true', true, '1', 1].indexOf(params.gdprPrivacyConsent) !== -1) { - params.gdprPrivacyConsent = 1; - } else { - params.gdprPrivacyConsent = 0; - } - } - }, - - /** - * Prepare querty string to ad server - * @param params: object {k:v} - * @returns : object {k:v} - */ - getUrlParams(params) { - this.handleGDPR(params); - const serverParams = this.toServerParams(params); - const toQueryString = Object.assign({}, this.defaultsParams, serverParams); - for (const paramName in toQueryString) { - if (toQueryString.hasOwnProperty(paramName) && this.unwantedValues.indexOf(toQueryString[paramName]) !== -1) { - delete toQueryString[paramName]; - } - } - toQueryString.fs = params.spotType === CONSTANTS.SPOT_TYPES.INTERSTITIAL; - - if (params.spotType === CONSTANTS.SPOT_TYPES.RECTANGLE) { - toQueryString.rw = CONSTANTS.RECTANGLE_SIZE.W; - toQueryString.rh = CONSTANTS.RECTANGLE_SIZE.H; - } - toQueryString.bco = config.getConfig('cbTimeout') || config.getConfig('bidderTimeout'); - toQueryString.timestamp = Date.now(); - delete toQueryString.qa; - return toQueryString; - } -}; - -/** - * Analytics - * @type {{errorEventName: string, pageProtocol: string, getPageProtocol: (function(): string), getEventUrl: (function(*, *=)), defaults: {v: (string|string), page: string, mw: boolean, hb: string}, eventQueryStringParams: (function(Object): string)}} - */ -const Reporter = { - /** - * @private - */ - errorEventName: 'HBPreBidError', - pageProtocol: '', - defaults: Helpers.defaultsQsParams, - - /** - * Gets the page protocol based on the document.location.protocol - * The returned string is either http:// or https:// - * @return {string} - */ - getPageProtocol() { - if (!this.pageProtocol) { - this.pageProtocol = (getTopWindowLocation().protocol === 'http:' ? 'http:' : 'https:'); - } - return this.pageProtocol; - }, - - getEventUrl(evtName, extraDetails) { - let eventsEndpoint = CONSTANTS.EVENTS_ENDPOINT_URL + '?table=' + ((evtName === this.errorEventName) ? 'mbwError' : 'mbwEvent'); - let queryStringParams = this.eventQueryStringParams(extraDetails); - const appId = extraDetails && extraDetails.appId; - let queryStringParamsWithAID = `${queryStringParams}&aid=${appId}_${evtName}_other&evtName=${evtName}`; - return eventsEndpoint + '&' + queryStringParamsWithAID; - }, - - /** - * Fyber Event Reporting Query String Parameters, not including App Id. - * @param {object} extraDetails - e.g., a JS exception JSON object. - * @return {string} Fyber event contcatenated queryString parameters. - */ - eventQueryStringParams(extraDetails) { - const toQS = Object.assign({}, this.defaults, {realAppId: extraDetails && extraDetails.appId, timestamp: Date.now()}); - Url.handleGDPR(toQS); - return formatQS(toQS); - } -}; -const {PRICING_VALUE, AD_W, AD_H, CREATIVE_ID, CURRENCY, TIMEOUT} = CONSTANTS.RESPONSE_HEADERS_NAME; -/** - * Http helper to extract metadata - * @type {{headers: *[], getBidHeaders: (function(*))}} - */ -const Http = { - headerNames: [PRICING_VALUE, AD_W, AD_H, CREATIVE_ID, CURRENCY, TIMEOUT], - - /** - * Extract headers data - * @param responseHeaders: XMLHttpRequest - * @return {} - */ - getBidHeaders(responseHeaders) { - const headersData = {}; - this.headerNames.forEach(headerName => headersData[headerName] = responseHeaders.get(headerName)); - return headersData; - } -}; - -const bidByBidId = {}; -class FyberBid { - constructor(headersData, response, bid) { - this.handleGDPR(response.config.tracking, bid.params); - const [w, h] = bid.sizes[0]; - this.cpm = ((bid.params.qa && bid.params.qa.cpm) || headersData[PRICING_VALUE]) * 1000; - this.requestId = bid.bidId; - this.width = parseFloat(headersData[AD_W]) || w; - this.ad = Helpers.getAd(response.ad.html, response.config.tracking, bid.params); - this.height = parseFloat(headersData[AD_H]) || h; - this.creativeId = headersData[CREATIVE_ID]; - this.currency = headersData[CURRENCY] || 'USD'; - this.netRevenue = true; - this.ttl = 60 * (headersData[TIMEOUT] || 20); - this.dealId = null; - } - - handleGDPR(tracking, params) { - if (params.hasOwnProperty('gdprPrivacyConsent')) { - if (['true', true, '1', 1].indexOf(params.gdprPrivacyConsent) !== -1) { - params.gdprPrivacyConsent = 1; - } else { - params.gdprPrivacyConsent = 0; - } - Object.keys(tracking).forEach((trackName) => { - if (Array.isArray(tracking[trackName])) { - tracking[trackName].forEach((url, index) => { - if (url) { - if (url.indexOf('?') === -1) { - url += '?'; - } - url += '&gdpr_privacy_consent=' + params.gdprPrivacyConsent; - tracking[trackName][index] = url; - } - }); - } - }); - } - } -} - -export const spec = { - code: CONSTANTS.CODE, - - /** - * Determines whether or not the given bid request is valid. - * Valid bid request must have appId and spotType - * @param {BidRequest} bid The bid params to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ - isBidRequestValid(bid) { - const {appId, spotType} = Helpers.objectToCamel(bid.params); - const isValid = !!(appId && spotType); - if (!isValid) { - logError(`bid requires appId = ${appId} , spotType = ${spotType}`); - } - return isValid; - }, - - buildRequests(bidRequests) { - let requests = []; - bidRequests.forEach((bid) => { - bid = Helpers.toBidParams(bid); - bidByBidId[bid.bidId] = bid; - requests.push({ - method: 'GET', - url: Helpers.getEndpointUrl(bid.params), - data: Url.getUrlParams(bid.params), - bidId: bid.bidId - }); - }); - return requests; - }, - - interpretResponse(response, request) { - const isValid = response.body && response.body.ad; - const headersData = (isValid && Http.getBidHeaders(response.headers)) || {}; - const bid = bidByBidId[request.bidId]; - const bidResponse = []; - if (!isValid || !Helpers.isValidBidResponse(response.body, headersData)) { - logError(`response failed for ${CONSTANTS.CODE} adapter`); - return bidResponse; - } - bidResponse.push(new FyberBid(headersData, response.body, bid)); - return bidResponse; - } -}; -registerBidder(spec); diff --git a/modules/gammaBidAdapter.js b/modules/gammaBidAdapter.js index 926dae14790..5fd3c56b2c6 100644 --- a/modules/gammaBidAdapter.js +++ b/modules/gammaBidAdapter.js @@ -1,7 +1,7 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; -const ENDPOINT = 'hb.gammaplatform.com'; +const ENDPOINT = 'https://hb.gammaplatform.com'; +const ENDPOINT_USERSYNC = 'https://cm-supply-web.gammaplatform.com'; const BIDDER_CODE = 'gamma'; export const spec = { @@ -25,13 +25,14 @@ export const spec = { * @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server. * @return ServerRequest Info describing the request to the server. */ - buildRequests: function(bidRequests) { + buildRequests: function(bidRequests, bidderRequest) { const serverRequests = []; + const bidderRequestReferer = (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer) || ''; for (var i = 0, len = bidRequests.length; i < len; i++) { const gaxObjParams = bidRequests[i]; serverRequests.push({ method: 'GET', - url: '//' + ENDPOINT + '/adx/request?wid=' + gaxObjParams.params.siteId + '&zid=' + gaxObjParams.params.zoneId + '&hb=pbjs&bidid=' + gaxObjParams.bidId + '&urf=' + encodeURIComponent(utils.getTopWindowUrl()) + url: ENDPOINT + '/adx/request?wid=' + gaxObjParams.params.siteId + '&zid=' + gaxObjParams.params.zoneId + '&hb=pbjs&bidid=' + gaxObjParams.bidId + '&urf=' + encodeURIComponent(bidderRequestReferer) }); } return serverRequests; @@ -60,7 +61,7 @@ export const spec = { if (syncOptions.iframeEnabled) { return [{ type: 'iframe', - url: '//' + ENDPOINT + '/adx/usersync' + url: ENDPOINT_USERSYNC + '/adx/usersync' }]; } } diff --git a/modules/gamoshiBidAdapter.js b/modules/gamoshiBidAdapter.js index 67475f8d8d9..1316d74e430 100644 --- a/modules/gamoshiBidAdapter.js +++ b/modules/gamoshiBidAdapter.js @@ -1,14 +1,11 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {config} from '../src/config'; -import {Renderer} from '../src/Renderer'; -import {BANNER, VIDEO} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; +import {Renderer} from '../src/Renderer.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; const ENDPOINTS = { - 'viewdeos': 'https://rtb.viewdeos.com', - 'cleanmedia': 'https://bidder.cleanmediaads.com', - 'gamoshi': 'https://rtb.gamoshi.io', - 'gambid': 'https://rtb.gamoshi.io', + 'gamoshi': 'https://rtb.gamoshi.io' }; const DEFAULT_TTL = 360; @@ -45,69 +42,85 @@ export const helper = { export const spec = { code: 'gamoshi', - aliases: ['gambid', 'cleanmedia', 'viewdeos'], + aliases: ['gambid', 'cleanmedia', '9MediaOnline'], supportedMediaTypes: ['banner', 'video'], isBidRequestValid: function (bid) { - return !!bid.params.supplyPartnerId && - typeof bid.params.supplyPartnerId === 'string' && - (typeof bid.params['rtbEndpoint'] === 'undefined' || typeof bid.params['rtbEndpoint'] === 'string') && - (typeof bid.params.bidfloor === 'undefined' || typeof bid.params.bidfloor === 'number') && - (typeof bid.params['adpos'] === 'undefined' || typeof bid.params['adpos'] === 'number') && - (typeof bid.params['protocols'] === 'undefined' || Array.isArray(bid.params['protocols'])) && - (typeof bid.params.instl === 'undefined' || bid.params.instl === 0 || bid.params.instl === 1); + return !!bid.params.supplyPartnerId && utils.isStr(bid.params.supplyPartnerId) && + (!bid.params['rtbEndpoint'] || utils.isStr(bid.params['rtbEndpoint'])) && + (!bid.params.bidfloor || utils.isNumber(bid.params.bidfloor)) && + (!bid.params['adpos'] || utils.isNumber(bid.params['adpos'])) && + (!bid.params['protocols'] || Array.isArray(bid.params['protocols'])) && + (!bid.params.instl || bid.params.instl === 0 || bid.params.instl === 1); }, buildRequests: function (validBidRequests, bidderRequest) { return validBidRequests.map(bidRequest => { const {adUnitCode, auctionId, mediaTypes, params, sizes, transactionId} = bidRequest; - const baseEndpoint = params['rtbEndpoint'] || ENDPOINTS[bidRequest.bidder] || ENDPOINTS['gamoshi']; + const baseEndpoint = params['rtbEndpoint'] || ENDPOINTS['gamoshi']; const rtbEndpoint = `${baseEndpoint}/r/${params.supplyPartnerId}/bidr?rformat=open_rtb&reqformat=rtb_json&bidder=prebid` + (params.query ? '&' + params.query : ''); let url = config.getConfig('pageUrl') || bidderRequest.refererInfo.referer; const rtbBidRequest = { - 'id': auctionId, - 'site': { - 'domain': helper.getTopWindowDomain(url), - 'page': url, - 'ref': bidderRequest.refererInfo.referer + id: auctionId, + site: { + domain: helper.getTopWindowDomain(url), + page: url, + ref: bidderRequest.refererInfo.referer }, - 'device': { - 'ua': navigator.userAgent + device: { + ua: navigator.userAgent, + dnt: utils.getDNT() ? 1 : 0, + h: screen.height, + w: screen.width, + language: navigator.language }, - 'imp': [], - 'ext': {} + imp: [], + ext: {}, + user: {ext: {}}, + source: {ext: {}}, + regs: {ext: {}} }; + const gdprConsent = bidderRequest.gdprConsent; - if (bidderRequest.gdprConsent && - bidderRequest.gdprConsent.consentString && - bidderRequest.gdprConsent.gdprApplies) { + if (gdprConsent && gdprConsent.consentString && gdprConsent.gdprApplies) { rtbBidRequest.ext.gdpr_consent = { - consent_string: bidderRequest.gdprConsent.consentString, - consent_required: bidderRequest.gdprConsent.gdprApplies + consent_string: gdprConsent.consentString, + consent_required: gdprConsent.gdprApplies }; + + utils.deepSetValue(rtbBidRequest, 'regs.ext.gdpr', gdprConsent.gdprApplies === true ? 1 : 0); + utils.deepSetValue(rtbBidRequest, 'user.ext.consent', gdprConsent.consentString); + } + + if (validBidRequests[0].schain) { + utils.deepSetValue(rtbBidRequest, 'source.ext.schain', validBidRequests[0].schain); + } + + if (bidderRequest && bidderRequest.uspConsent) { + utils.deepSetValue(rtbBidRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent); } const imp = { - 'id': transactionId, - 'instl': params.instl === 1 ? 1 : 0, - 'tagid': adUnitCode, - 'bidfloor': params.bidfloor || 0, - 'bidfloorcur': 'USD', - 'secure': helper.startsWith(utils.getTopWindowUrl().toLowerCase(), 'http://') ? 0 : 1 + id: transactionId, + instl: params.instl === 1 ? 1 : 0, + tagid: adUnitCode, + bidfloor: params.bidfloor || 0, + bidfloorcur: 'USD', + secure: 1 }; const hasFavoredMediaType = params.favoredMediaType && this.supportedMediaTypes.includes(params.favoredMediaType); - if ((!mediaTypes || mediaTypes.banner)) { + if (!mediaTypes || mediaTypes.banner) { if (!hasFavoredMediaType || params.favoredMediaType === BANNER) { const bannerImp = Object.assign({}, imp, { banner: { w: sizes.length ? sizes[0][0] : 300, h: sizes.length ? sizes[0][1] : 250, pos: params.pos || 0, - topframe: helper.getTopFrame() + topframe: utils.inIframe() ? 0 : 1 } }); rtbBidRequest.imp.push(bannerImp); @@ -119,8 +132,6 @@ export const spec = { const playerSize = mediaTypes.video.playerSize || sizes; const videoImp = Object.assign({}, imp, { video: { - w: playerSize ? playerSize[0][0] : 300, - h: playerSize ? playerSize[0][1] : 250, protocols: params.protocols || [1, 2, 3, 4, 5, 6], pos: params.pos || 0, ext: { @@ -128,15 +139,41 @@ export const spec = { } } }); + + if (utils.isArray(playerSize[0])) { + videoImp.video.w = playerSize[0][0]; + videoImp.video.h = playerSize[0][1]; + } else if (utils.isNumber(playerSize[0])) { + videoImp.video.w = playerSize[0]; + videoImp.video.h = playerSize[1]; + } else { + videoImp.video.w = 300; + videoImp.video.h = 250; + } + rtbBidRequest.imp.push(videoImp); } } + let eids = []; + if (bidRequest && bidRequest.userId) { + addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.id5id`), 'id5-sync.com', 'ID5ID'); + addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.tdid`), 'adserver.org', 'TDID'); + } + if (eids.length > 0) { + rtbBidRequest.user.ext.eids = eids; + } + if (rtbBidRequest.imp.length === 0) { return; } - return {method: 'POST', url: rtbEndpoint, data: rtbBidRequest, bidRequest}; + return { + method: 'POST', + url: rtbEndpoint, + data: rtbBidRequest, + bidRequest + }; }); }, @@ -179,28 +216,52 @@ export const spec = { return outBids; }, - getUserSyncs: function (syncOptions, serverResponses, gdprConsent) { + getUserSyncs: function (syncOptions, serverResponses, gdprConsent, uspConsent) { const syncs = []; - const gdprApplies = gdprConsent && (typeof gdprConsent.gdprApplies === 'boolean') ? gdprConsent.gdprApplies : false; - const suffix = gdprApplies ? 'gc=' + encodeURIComponent(gdprConsent.consentString) : 'gc=missing'; + let gdprApplies = false; + let consentString = ''; + let uspConsentString = ''; + + if (gdprConsent && (typeof gdprConsent.gdprApplies === 'boolean')) { + gdprApplies = gdprConsent.gdprApplies; + } + let gdpr = gdprApplies ? 1 : 0; + + if (gdprApplies && gdprConsent.consentString) { + consentString = encodeURIComponent(gdprConsent.consentString) + } + + if (uspConsent) { + uspConsentString = encodeURIComponent(uspConsent); + } + + const macroValues = { + gdpr: gdpr, + consent: consentString, + uspConsent: uspConsentString + }; + serverResponses.forEach(resp => { if (resp.body) { const bidResponse = resp.body; if (bidResponse.ext && Array.isArray(bidResponse.ext['utrk'])) { - bidResponse.ext['utrk'].forEach(pixel => { - const url = pixel.url + (pixel.url.indexOf('?') > 0 ? '&' + suffix : '?' + suffix); - return syncs.push({type: pixel.type, url}); - }); + bidResponse.ext['utrk'] + .forEach(pixel => { + const url = replaceMacros(pixel.url, macroValues); + syncs.push({type: pixel.type, url}); + }); } + if (Array.isArray(bidResponse.seatbid)) { bidResponse.seatbid.forEach(seatBid => { if (Array.isArray(seatBid.bid)) { seatBid.bid.forEach(bid => { if (bid.ext && Array.isArray(bid.ext['utrk'])) { - bid.ext['utrk'].forEach(pixel => { - const url = pixel.url + (pixel.url.indexOf('?') > 0 ? '&' + suffix : '?' + suffix); - return syncs.push({type: pixel.type, url}); - }); + bid.ext['utrk'] + .forEach(pixel => { + const url = replaceMacros(pixel.url, macroValues); + syncs.push({type: pixel.type, url}); + }); } }); } @@ -208,13 +269,14 @@ export const spec = { } } }); + return syncs; } }; function newRenderer(bidRequest, bid, rendererOptions = {}) { const renderer = Renderer.install({ - url: (bidRequest.params && bidRequest.params.rendererUrl) || (bid.ext && bid.ext.renderer_url) || '//s.wlplayer.com/video/latest/renderer.js', + url: (bidRequest.params && bidRequest.params.rendererUrl) || (bid.ext && bid.ext.renderer_url) || 'https://s.gamoshi.io/video/latest/renderer.js', config: rendererOptions, loaded: false, }); @@ -246,4 +308,25 @@ function renderOutstream(bid) { }); } +function addExternalUserId(eids, value, source, rtiPartner) { + if (utils.isStr(value)) { + eids.push({ + source, + uids: [{ + id: value, + ext: { + rtiPartner + } + }] + }); + } +} + +function replaceMacros(url, macros) { + return url + .replace('[GDPR]', macros.gdpr) + .replace('[CONSENT]', macros.consent) + .replace('[US_PRIVACY]', macros.uspConsent); +} + registerBidder(spec); diff --git a/modules/gdprEnforcement.js b/modules/gdprEnforcement.js new file mode 100644 index 00000000000..6a3fbdce1f2 --- /dev/null +++ b/modules/gdprEnforcement.js @@ -0,0 +1,184 @@ +/** + * This module gives publishers extra set of features to enforce individual purposes of TCF v2 + */ + +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { hasDeviceAccess } from '../src/utils.js'; +import adapterManager, { gdprDataHandler } from '../src/adapterManager.js'; +import find from 'core-js-pure/features/array/find.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import { registerSyncInner } from '../src/adapters/bidderFactory.js'; +import { getHook } from '../src/hook.js'; +import { validateStorageEnforcement } from '../src/storageManager.js'; + +const purpose1 = 'storage'; + +let addedDeviceAccessHook = false; +let enforcementRules; + +function getGvlid() { + let gvlid; + const bidderCode = config.getCurrentBidder(); + if (bidderCode) { + const bidder = adapterManager.getBidAdapter(bidderCode); + gvlid = bidder.getSpec().gvlid; + } else { + utils.logWarn('Current module not found'); + } + return gvlid; +} + +/** + * This function takes in rules and consentData as input and validates against the consentData provided. If it returns true Prebid will allow the next call else it will log a warning + * @param {Object} rules enforcement rules set in config + * @param {Object} consentData gdpr consent data + * @returns {boolean} + */ +function validateRules(rule, consentData, currentModule, gvlid) { + // if vendor has exception => always true + if (includes(rule.vendorExceptions || [], currentModule)) { + return true; + } + // if enforcePurpose is false or purpose was granted isAllowed is true, otherwise false + const purposeAllowed = rule.enforcePurpose === false || utils.deepAccess(consentData, 'vendorData.purpose.consents.1') === true; + // if enforceVendor is false or vendor was granted isAllowed is true, otherwise false + const vendorAllowed = rule.enforceVendor === false || utils.deepAccess(consentData, `vendorData.vendor.consents.${gvlid}`) === true; + return purposeAllowed && vendorAllowed; +} + +/** + * This hook checks whether module has permission to access device or not. Device access include cookie and local storage + * @param {Function} fn reference to original function (used by hook logic) + * @param {Number=} gvlid gvlid of the module + * @param {string=} moduleName name of the module + */ +export function deviceAccessHook(fn, gvlid, moduleName, result) { + result = Object.assign({}, { + hasEnforcementHook: true + }); + if (!hasDeviceAccess()) { + utils.logWarn('Device access is disabled by Publisher'); + result.valid = false; + fn.call(this, gvlid, moduleName, result); + } else { + const consentData = gdprDataHandler.getConsentData(); + if (consentData && consentData.gdprApplies) { + if (consentData.apiVersion === 2) { + if (!gvlid) { + gvlid = getGvlid(); + } + const curModule = moduleName || config.getCurrentBidder(); + const purpose1Rule = find(enforcementRules, hasPurpose1); + let isAllowed = validateRules(purpose1Rule, consentData, curModule, gvlid); + if (isAllowed) { + result.valid = true; + fn.call(this, gvlid, moduleName, result); + } else { + utils.logWarn(`User denied Permission for Device access for ${curModule}`); + result.valid = false; + fn.call(this, gvlid, moduleName, result); + } + } else { + utils.logInfo('Enforcing TCF2 only'); + result.valid = true; + fn.call(this, gvlid, moduleName, result); + } + } else { + result.valid = true; + fn.call(this, gvlid, moduleName, result); + } + } +} + +/** + * This hook checks if a bidder has consent for user sync or not + * @param {Function} fn reference to original function (used by hook logic) + * @param {...any} args args + */ +export function userSyncHook(fn, ...args) { + const consentData = gdprDataHandler.getConsentData(); + if (consentData && consentData.gdprApplies) { + if (consentData.apiVersion === 2) { + const gvlid = getGvlid(); + const curBidder = config.getCurrentBidder(); + if (gvlid) { + const purpose1Rule = find(enforcementRules, hasPurpose1); + let isAllowed = validateRules(purpose1Rule, consentData, curBidder, gvlid); + if (isAllowed) { + fn.call(this, ...args); + } else { + utils.logWarn(`User sync not allowed for ${curBidder}`); + } + } else { + utils.logWarn(`User sync not allowed for ${curBidder}`); + } + } else { + utils.logInfo('Enforcing TCF2 only'); + fn.call(this, ...args); + } + } else { + fn.call(this, ...args); + } +} + +/** + * This hook checks if user id module is given consent or not + * @param {Function} fn reference to original function (used by hook logic) + * @param {Submodule[]} submodules Array of user id submodules + * @param {Object} consentData GDPR consent data + */ +export function userIdHook(fn, submodules, consentData) { + if (consentData && consentData.gdprApplies) { + if (consentData.apiVersion === 2) { + let userIdModules = submodules.map((submodule) => { + const gvlid = submodule.submodule.gvlid; + const moduleName = submodule.submodule.name; + if (gvlid) { + const purpose1Rule = find(enforcementRules, hasPurpose1); + let isAllowed = validateRules(purpose1Rule, consentData, moduleName, gvlid); + if (isAllowed) { + return submodule; + } else { + utils.logWarn(`User denied permission to fetch user id for ${moduleName} User id module`); + } + } else { + utils.logWarn(`User denied permission to fetch user id for ${moduleName} User id module`); + } + return undefined; + }).filter(module => module) + fn.call(this, userIdModules, {...consentData, hasValidated: true}); + } else { + utils.logInfo('Enforcing TCF2 only'); + fn.call(this, submodules, consentData); + } + } else { + fn.call(this, submodules, consentData); + } +} + +const hasPurpose1 = (rule) => { return rule.purpose === purpose1 } + +/** + * A configuration function that initializes some module variables, as well as add hooks + * @param {Object} config GDPR enforcement config object + */ +export function setEnforcementConfig(config) { + const rules = utils.deepAccess(config, 'gdpr.rules'); + if (!rules) { + utils.logWarn('GDPR enforcement rules not defined, exiting enforcement module'); + return; + } + + enforcementRules = rules; + const hasDefinedPurpose1 = find(enforcementRules, hasPurpose1); + if (hasDefinedPurpose1 && !addedDeviceAccessHook) { + addedDeviceAccessHook = true; + validateStorageEnforcement.before(deviceAccessHook, 49); + registerSyncInner.before(userSyncHook, 48); + // Using getHook as user id and gdprEnforcement are both optional modules. Using import will auto include the file in build + getHook('validateGdprEnforcement').before(userIdHook, 47); + } +} + +config.getConfig('consentManagement', config => setEnforcementConfig(config.consentManagement)); diff --git a/modules/getintentBidAdapter.js b/modules/getintentBidAdapter.js index bc2ed093665..134dd0b4fc9 100644 --- a/modules/getintentBidAdapter.js +++ b/modules/getintentBidAdapter.js @@ -1,5 +1,5 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { isInteger } from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { isInteger } from '../src/utils.js'; const BIDDER_CODE = 'getintent'; const IS_NET_REVENUE = true; @@ -83,7 +83,7 @@ export const spec = { } function buildUrl(bid) { - return '//' + BID_HOST + (bid.is_video ? BID_VIDEO_PATH : BID_BANNER_PATH); + return 'https://' + BID_HOST + (bid.is_video ? BID_VIDEO_PATH : BID_BANNER_PATH); } /** diff --git a/modules/giantsBidAdapter.js b/modules/giantsBidAdapter.js deleted file mode 100644 index e2693392578..00000000000 --- a/modules/giantsBidAdapter.js +++ /dev/null @@ -1,343 +0,0 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; -import includes from 'core-js/library/fn/array/includes'; - -const BIDDER_CODE = 'giants'; -const URL = '//d.admp.io/hb'; -const VIDEO_TARGETING = ['id', 'mimes', 'minduration', 'maxduration', - 'startdelay', 'skippable', 'playback_method', 'frameworks']; -const NATIVE_MAPPING = { - body: 'description', - cta: 'ctatext', - image: { - serverName: 'main_image', - requiredParams: { required: true }, - minimumParams: { sizes: [{}] }, - }, - icon: { - serverName: 'icon', - requiredParams: { required: true }, - minimumParams: { sizes: [{}] }, - }, - sponsoredBy: 'sponsored_by', -}; -const SOURCE = 'pbjs'; - -export const spec = { - code: BIDDER_CODE, - aliases: [], - supportedMediaTypes: [BANNER, VIDEO, NATIVE], - - /** - * Determines whether or not the given bid request is valid. - * - * @param {object} bid The bid to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ - isBidRequestValid: function(bid) { - return !!(bid.params.zoneId); - }, - - /** - * Make a server request from the list of BidRequests. - * - * @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server. - * @return ServerRequest Info describing the request to the server. - */ - buildRequests: function(bidRequests, bidderRequest) { - const tags = bidRequests.map(bidToTag); - // const zoneIds = bidRequests.map(bidToZoneId); - // var firstBid = bidRequests[0]; - var ref = utils.getTopWindowUrl(); - const url = URL + '/multi?url=' + ref; - // + '&callback=window.$$PREBID_GLOBAL$$.giantsResponse&callback_uid=' + bid.bidId; - - const payload = { - tags: [...tags], - // user: userObj, - sdk: { - source: SOURCE, - version: '$prebid.version$' - } - }; - // if (member > 0) { - // payload.member_id = member; - // } - - if (bidderRequest && bidderRequest.gdprConsent) { - // note - objects for impbus use underscore instead of camelCase - payload.gdpr_consent = { - consent_string: bidderRequest.gdprConsent.consentString, - consent_required: bidderRequest.gdprConsent.gdprApplies - }; - } - - const payloadString = JSON.stringify(payload); - - return { - method: 'POST', - // url: URL, - url: url, - data: payloadString, - bidderRequest - }; - }, - - /** - * Unpack the response from the server into a list of bids. - * - * @param {*} serverResponse A successful response from the server. - * @return {Bid[]} An array of bids which were nested inside the server. - */ - interpretResponse: function(serverResponse, {bidderRequest}) { - serverResponse = serverResponse.body; - const bids = []; - if (!serverResponse || serverResponse.error) { - let errorMessage = `in response for ${bidderRequest.bidderCode} adapter`; - if (serverResponse && serverResponse.error) { errorMessage += `: ${serverResponse.error}`; } - utils.logError(errorMessage); - return bids; - } - if (serverResponse.tags) { - serverResponse.tags.forEach(serverBid => { - if (serverBid.cpm && serverBid.cpm !== 0) { - const bid = newBid(serverBid, bidderRequest); - bid.mediaType = BANNER; - bids.push(bid); - } - }); - } - return bids; - }, - - getUserSyncs: function(syncOptions) { - if (syncOptions.iframeEnabled) { - return [{ - type: 'iframe', - url: '//d.admp.io/ping' - }]; - } - } -} - -/* Turn keywords parameter into ut-compatible format */ -function getKeywords(keywords) { - let arrs = []; - - utils._each(keywords, (v, k) => { - if (utils.isArray(v)) { - let values = []; - utils._each(v, (val) => { - val = utils.getValueString('keywords.' + k, val); - if (val) { values.push(val); } - }); - v = values; - } else { - v = utils.getValueString('keywords.' + k, v); - if (utils.isStr(v)) { - v = [v]; - } else { - return; - } // unsuported types - don't send a key - } - arrs.push({key: k, value: v}); - }); - - return arrs; -} - -/** - * Unpack the Server's Bid into a Prebid-compatible one. - * @param serverBid - * @param rtbBid - * @param bidderRequest - * @return Bid - */ -function newBid(serverBid, bidderRequest) { - const bid = { - requestId: serverBid.uuid, - cpm: serverBid.cpm, - creativeId: serverBid.creative_id, - // dealId: rtbBid.deal_id, - currency: 'USD', - netRevenue: true, - ttl: 300 - }; - - Object.assign(bid, { - width: serverBid.width, - height: serverBid.height, - // ad: serverBid.ad - ad: _renderCreative(serverBid.adUrl, serverBid.width, serverBid.height) - }); - // try { - // const url = rtbBid.rtb.trackers[0].impression_urls[0]; - // const tracker = utils.createTrackPixelHtml(url); - // bid.ad += tracker; - // } catch (error) { - // utils.logError('Error appending tracking pixel', error); - // } - - return bid; -} - -function bidToTag(bid) { - const tag = {}; - tag.sizes = transformSizes(bid.sizes); - tag.primary_size = tag.sizes[0]; - tag.ad_types = []; - tag.uuid = bid.bidId; - if (bid.params.zoneId) { - tag.id = bid.params.zoneId; - } else { - tag.code = bid.params.invCode; - } - tag.allow_smaller_sizes = bid.params.allowSmallerSizes || false; - tag.use_pmt_rule = bid.params.usePaymentRule || false - tag.prebid = true; - tag.disable_psa = true; - if (bid.params.reserve) { - tag.reserve = bid.params.reserve; - } - if (bid.params.position) { - tag.position = {'above': 1, 'below': 2}[bid.params.position] || 0; - } - if (bid.params.trafficSourceCode) { - tag.traffic_source_code = bid.params.trafficSourceCode; - } - if (bid.params.privateSizes) { - tag.private_sizes = transformSizes(bid.params.privateSizes); - } - if (bid.params.supplyType) { - tag.supply_type = bid.params.supplyType; - } - if (bid.params.pubClick) { - tag.pubclick = bid.params.pubClick; - } - if (bid.params.extInvCode) { - tag.ext_inv_code = bid.params.extInvCode; - } - if (bid.params.externalImpId) { - tag.external_imp_id = bid.params.externalImpId; - } - if (!utils.isEmpty(bid.params.keywords)) { - tag.keywords = getKeywords(bid.params.keywords); - } - - if (bid.mediaType === NATIVE || utils.deepAccess(bid, `mediaTypes.${NATIVE}`)) { - tag.ad_types.push(NATIVE); - - if (bid.nativeParams) { - const nativeRequest = buildNativeRequest(bid.nativeParams); - tag[NATIVE] = {layouts: [nativeRequest]}; - } - } - - const videoMediaType = utils.deepAccess(bid, `mediaTypes.${VIDEO}`); - const context = utils.deepAccess(bid, 'mediaTypes.video.context'); - - if (bid.mediaType === VIDEO || videoMediaType) { - tag.ad_types.push(VIDEO); - } - - // instream gets vastUrl, outstream gets vastXml - if (bid.mediaType === VIDEO || (videoMediaType && context !== 'outstream')) { - tag.require_asset_url = true; - } - - if (bid.params.video) { - tag.video = {}; - // place any valid video params on the tag - Object.keys(bid.params.video) - .filter(param => includes(VIDEO_TARGETING, param)) - .forEach(param => tag.video[param] = bid.params.video[param]); - } - - if ( - (utils.isEmpty(bid.mediaType) && utils.isEmpty(bid.mediaTypes)) || - (bid.mediaType === BANNER || (bid.mediaTypes && bid.mediaTypes[BANNER])) - ) { - tag.ad_types.push(BANNER); - } - - return tag; -} - -// function bidToZoneId(bid) { -// return bid.params.zoneId; -// } - -/* Turn bid request sizes into ut-compatible format */ -function transformSizes(requestSizes) { - let sizes = []; - let sizeObj = {}; - - if (utils.isArray(requestSizes) && requestSizes.length === 2 && - !utils.isArray(requestSizes[0])) { - sizeObj.width = parseInt(requestSizes[0], 10); - sizeObj.height = parseInt(requestSizes[1], 10); - sizes.push(sizeObj); - } else if (typeof requestSizes === 'object') { - for (let i = 0; i < requestSizes.length; i++) { - let size = requestSizes[i]; - sizeObj = {}; - sizeObj.width = parseInt(size[0], 10); - sizeObj.height = parseInt(size[1], 10); - sizes.push(sizeObj); - } - } - - return sizes; -} - -function buildNativeRequest(params) { - const request = {}; - - // map standard prebid native asset identifier to /ut parameters - // e.g., tag specifies `body` but /ut only knows `description`. - // mapping may be in form {tag: ''} or - // {tag: {serverName: '', requiredParams: {...}}} - Object.keys(params).forEach(key => { - // check if one of the forms is used, otherwise - // a mapping wasn't specified so pass the key straight through - const requestKey = - (NATIVE_MAPPING[key] && NATIVE_MAPPING[key].serverName) || - NATIVE_MAPPING[key] || - key; - - // required params are always passed on request - const requiredParams = NATIVE_MAPPING[key] && NATIVE_MAPPING[key].requiredParams; - request[requestKey] = Object.assign({}, requiredParams, params[key]); - - // minimum params are passed if no non-required params given on adunit - const minimumParams = NATIVE_MAPPING[key] && NATIVE_MAPPING[key].minimumParams; - - if (requiredParams && minimumParams) { - // subtract required keys from adunit keys - const adunitKeys = Object.keys(params[key]); - const requiredKeys = Object.keys(requiredParams); - const remaining = adunitKeys.filter(key => !includes(requiredKeys, key)); - - // if none are left over, the minimum params needs to be sent - if (remaining.length === 0) { - request[requestKey] = Object.assign({}, request[requestKey], minimumParams); - } - } - }); - - return request; -} - -function _renderCreative(adUrl, width, height) { - return ` - - - - `; } -/** - * Returns iframe document in a browser agnostic way - * @param {Object} iframe reference - * @return {Object} iframe `document` reference - */ -export function getIframeDocument(iframe) { - if (!iframe) { - return; - } - - let doc; - try { - if (iframe.contentWindow) { - doc = iframe.contentWindow.document; - } else if (iframe.contentDocument.document) { - doc = iframe.contentDocument.document; - } else { - doc = iframe.contentDocument; - } - } catch (e) { - internal.logError('Cannot get iframe document', e); - } - - return doc; -} - export function getValueString(param, val, defaultValue) { if (val === undefined || val === null) { return defaultValue; @@ -858,16 +696,6 @@ export function adUnitsFilter(filter, bid) { return includes(filter, bid && bid.adUnitCode); } -/** - * Check if parent iframe of passed document supports content rendering via 'srcdoc' property - * @param {HTMLDocument} doc document to check support of 'srcdoc' - */ -export function isSrcdocSupported(doc) { - // Firefox is excluded due to https://bugzilla.mozilla.org/show_bug.cgi?id=1265961 - return doc.defaultView && doc.defaultView.frameElement && - 'srcdoc' in doc.defaultView.frameElement && !/firefox/i.test(navigator.userAgent); -} - export function deepClone(obj) { return clone(obj); } @@ -881,7 +709,7 @@ export function inIframe() { } export function isSafariBrowser() { - return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + return /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent); } export function replaceAuctionPrice(str, cpm) { @@ -893,37 +721,20 @@ export function timestamp() { return new Date().getTime(); } -export function checkCookieSupport() { - if (window.navigator.cookieEnabled || !!document.cookie.length) { - return true; - } -} -export function cookiesAreEnabled() { - if (internal.checkCookieSupport()) { - return true; - } - window.document.cookie = 'prebid.cookieTest'; - return window.document.cookie.indexOf('prebid.cookieTest') != -1; -} - -export function getCookie(name) { - let m = window.document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]*)\\s*(;|$)'); - return m ? decodeURIComponent(m[2]) : null; -} - -export function setCookie(key, value, expires) { - document.cookie = `${key}=${encodeURIComponent(value)}${(expires !== '') ? `; expires=${expires}` : ''}; path=/`; +/** + * When the deviceAccess flag config option is false, no cookies should be read or set + * @returns {boolean} + */ +export function hasDeviceAccess() { + return config.getConfig('deviceAccess') !== false; } /** - * @returns {boolean} + * @returns {(boolean|undefined)} */ -export function localStorageIsEnabled () { - try { - localStorage.setItem('prebid.cookieTest', '1'); - return localStorage.getItem('prebid.cookieTest') === '1'; - } catch (error) { - return false; +export function checkCookieSupport() { + if (window.navigator.cookieEnabled || !!document.cookie.length) { + return true; } } @@ -947,7 +758,7 @@ export function delayExecution(func, numRequiredCalls) { return function () { numCalls++; if (numCalls === numRequiredCalls) { - func.apply(null, arguments); + func.apply(this, arguments); } } } @@ -966,39 +777,6 @@ export function groupBy(xs, key) { }, {}); } -/** - * deepAccess utility function useful for doing safe access (will not throw exceptions) of deep object paths. - * @param {Object} obj The object containing the values you would like to access. - * @param {string|number} path Object path to the value you would like to access. Non-strings are coerced to strings. - * @returns {*} The value found at the specified object path, or undefined if path is not found. - */ -export function deepAccess(obj, path) { - if (!obj) { - return; - } - path = String(path).split('.'); - for (let i = 0; i < path.length; i++) { - obj = obj[path[i]]; - if (typeof obj === 'undefined') { - return; - } - } - return obj; -} - -/** - * Returns content for a friendly iframe to execute a URL in script tag - * @param {string} url URL to be executed in a script tag in a friendly iframe - * and are macros left to be replaced if required - */ -export function createContentToExecuteExtScriptInFriendlyFrame(url) { - if (!url) { - return ''; - } - - return ``; -} - /** * Build an object consisting of only defined parameters to avoid creating an * object with defined keys and undefined values. @@ -1101,6 +879,24 @@ export function isSlotMatchingAdUnitCode(adUnitCode) { return (slot) => compareCodeAndSlot(slot, adUnitCode); } +/** + * @summary Uses the adUnit's code in order to find a matching gptSlot on the page + */ +export function getGptSlotInfoForAdUnitCode(adUnitCode) { + let matchingSlot; + if (isGptPubadsDefined()) { + // find the first matching gpt slot on the page + matchingSlot = find(window.googletag.pubads().getSlots(), isSlotMatchingAdUnitCode(adUnitCode)); + } + if (matchingSlot) { + return { + gptSlot: matchingSlot.getAdUnitPath(), + divId: matchingSlot.getSlotElementId() + } + } + return {}; +}; + /** * Constructs warning message for when unsupported bidders are dropped from an adunit * @param {Object} adUnit ad unit from which the bidder is being dropped @@ -1117,18 +913,6 @@ export function unsupportedBidderMessage(adUnit, bidder) { `; } -/** - * Delete property from object - * @param {Object} object - * @param {string} prop - * @return {Object} object - */ -export function deletePropertyFromObject(object, prop) { - let result = Object.assign({}, object); - delete result[prop]; - return result; -} - /** * Checks input is integer or not * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger @@ -1150,6 +934,53 @@ export function convertCamelToUnderscore(value) { return value.replace(/(?:^|\.?)([A-Z])/g, function (x, y) { return '_' + y.toLowerCase() }).replace(/^_/, ''); } +/** + * Returns a new object with undefined properties removed from given object + * @param obj the object to clean + */ +export function cleanObj(obj) { + return Object.keys(obj).reduce((newObj, key) => { + if (typeof obj[key] !== 'undefined') { + newObj[key] = obj[key]; + } + return newObj; + }, {}) +} + +/** + * Create a new object with selected properties. Also allows property renaming and transform functions. + * @param obj the original object + * @param properties An array of desired properties + */ +export function pick(obj, properties) { + if (typeof obj !== 'object') { + return {}; + } + return properties.reduce((newObj, prop, i) => { + if (typeof prop === 'function') { + return newObj; + } + + let newProp = prop; + let match = prop.match(/^(.+?)\sas\s(.+?)$/i); + + if (match) { + prop = match[1]; + newProp = match[2]; + } + + let value = obj[prop]; + if (typeof properties[i + 1] === 'function') { + value = properties[i + 1](value, newObj); + } + if (typeof value !== 'undefined') { + newObj[newProp] = value; + } + + return newObj; + }, {}); +} + /** * Converts an object of arrays (either strings or numbers) into an array of objects containing key and value properties * normally read from bidder params @@ -1218,26 +1049,6 @@ export function convertTypes(types, params) { return params; } -export function setDataInLocalStorage(key, value) { - if (hasLocalStorage()) { - window.localStorage.setItem(key, value); - } -} - -export function getDataFromLocalStorage(key) { - if (hasLocalStorage()) { - return window.localStorage.getItem(key); - } -} - -export function hasLocalStorage() { - try { - return !!window.localStorage; - } catch (e) { - logError('Local storage api disabled'); - } -} - export function isArrayOfNums(val, size) { return (isArray(val)) && ((size) ? val.length === size : true) && (val.every(v => isInteger(v))); } @@ -1300,3 +1111,93 @@ export function compareOn(property) { return 0; } } + +export function parseQS(query) { + return !query ? {} : query + .replace(/^\?/, '') + .split('&') + .reduce((acc, criteria) => { + let [k, v] = criteria.split('='); + if (/\[\]$/.test(k)) { + k = k.replace('[]', ''); + acc[k] = acc[k] || []; + acc[k].push(v); + } else { + acc[k] = v || ''; + } + return acc; + }, {}); +} + +export function formatQS(query) { + return Object + .keys(query) + .map(k => Array.isArray(query[k]) + ? query[k].map(v => `${k}[]=${v}`).join('&') + : `${k}=${query[k]}`) + .join('&'); +} + +export function parseUrl(url, options) { + let parsed = document.createElement('a'); + if (options && 'noDecodeWholeURL' in options && options.noDecodeWholeURL) { + parsed.href = url; + } else { + parsed.href = decodeURIComponent(url); + } + // in window.location 'search' is string, not object + let qsAsString = (options && 'decodeSearchAsString' in options && options.decodeSearchAsString); + return { + href: parsed.href, + protocol: (parsed.protocol || '').replace(/:$/, ''), + hostname: parsed.hostname, + port: +parsed.port, + pathname: parsed.pathname.replace(/^(?!\/)/, '/'), + search: (qsAsString) ? parsed.search : internal.parseQS(parsed.search || ''), + hash: (parsed.hash || '').replace(/^#/, ''), + host: parsed.host || window.location.host + }; +} + +export function buildUrl(obj) { + return (obj.protocol || 'http') + '://' + + (obj.host || + obj.hostname + (obj.port ? `:${obj.port}` : '')) + + (obj.pathname || '') + + (obj.search ? `?${internal.formatQS(obj.search || '')}` : '') + + (obj.hash ? `#${obj.hash}` : ''); +} + +/** + * This function compares two objects for checking their equivalence. + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {boolean} + */ +export function deepEqual(obj1, obj2) { + return deepequal(obj1, obj2); +} + +export function mergeDeep(target, ...sources) { + if (!sources.length) return target; + const source = sources.shift(); + + if (isPlainObject(target) && isPlainObject(source)) { + for (const key in source) { + if (isPlainObject(source[key])) { + if (!target[key]) Object.assign(target, { [key]: {} }); + mergeDeep(target[key], source[key]); + } else if (isArray(source[key])) { + if (!target[key]) { + Object.assign(target, { [key]: source[key] }); + } else if (isArray(target[key])) { + target[key] = target[key].concat(source[key]); + } + } else { + Object.assign(target, { [key]: source[key] }); + } + } + } + + return mergeDeep(target, ...sources); +} diff --git a/src/video.js b/src/video.js index 9cf25016d46..befeb2ded39 100644 --- a/src/video.js +++ b/src/video.js @@ -1,11 +1,12 @@ -import adapterManager from './adapterManager'; -import { getBidRequest, deepAccess, logError } from './utils'; -import { config } from '../src/config'; -import includes from 'core-js/library/fn/array/includes'; -import { hook } from './hook'; +import adapterManager from './adapterManager.js'; +import { getBidRequest, deepAccess, logError } from './utils.js'; +import { config } from '../src/config.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import { hook } from './hook.js'; const VIDEO_MEDIA_TYPE = 'video'; export const OUTSTREAM = 'outstream'; +export const INSTREAM = 'instream'; /** * Helper functions for working with video-enabled adUnits @@ -48,7 +49,7 @@ export const checkVideoBidSetup = hook('sync', function(bid, bidRequest, videoMe if (!config.getConfig('cache.url') && bid.vastXml && !bid.vastUrl) { logError(` This bid contains only vastXml and will not work when a prebid cache url is not specified. - Try enabling prebid cache with pbjs.setConfig({ cache: {url: "..."} }); + Try enabling prebid cache with $$PREBID_GLOBAL$$.setConfig({ cache: {url: "..."} }); `); return false; } diff --git a/src/videoCache.js b/src/videoCache.js index 06847012a6e..9f1fd7e4117 100644 --- a/src/videoCache.js +++ b/src/videoCache.js @@ -9,8 +9,9 @@ * This trickery helps integrate with ad servers, which set character limits on request params. */ -import { ajax } from './ajax'; -import { config } from '../src/config'; +import { ajax } from './ajax.js'; +import { config } from './config.js'; +import * as utils from './utils.js'; /** * @typedef {object} CacheableUrlBid @@ -60,12 +61,22 @@ function wrapURI(uri, impUrl) { */ function toStorageRequest(bid) { const vastValue = bid.vastXml ? bid.vastXml : wrapURI(bid.vastUrl, bid.vastImpUrl); + let payload = { type: 'xml', value: vastValue, ttlseconds: Number(bid.ttl) }; + if (config.getConfig('cache.vasttrack')) { + payload.bidder = bid.bidder; + payload.bidid = bid.requestId; + // function has a thisArg set to bidderRequest for accessing the auctionStart + if (utils.isPlainObject(this) && this.hasOwnProperty('auctionStart')) { + payload.timestamp = this.auctionStart; + } + } + if (typeof bid.customCacheKey === 'string' && bid.customCacheKey !== '') { payload.key = bid.customCacheKey; } @@ -94,7 +105,7 @@ function toStorageRequest(bid) { */ function shimStorageCallback(done) { return { - success: function(responseBody) { + success: function (responseBody) { let ids; try { ids = JSON.parse(responseBody).responses @@ -109,7 +120,7 @@ function shimStorageCallback(done) { done(new Error("The cache server didn't respond with a responses property."), []); } }, - error: function(statusText, responseBody) { + error: function (statusText, responseBody) { done(new Error(`Error storing video ad in the cache: ${statusText}: ${JSON.stringify(responseBody)}`), []); } } @@ -120,11 +131,12 @@ function shimStorageCallback(done) { * * @param {CacheableBid[]} bids A list of bid objects which should be cached. * @param {videoCacheStoreCallback} [done] An optional callback which should be executed after + * @param {BidderRequest} [bidderRequest] * the data has been stored in the cache. */ -export function store(bids, done) { +export function store(bids, done, bidderRequest) { const requestData = { - puts: bids.map(toStorageRequest) + puts: bids.map(toStorageRequest, bidderRequest) }; ajax(config.getConfig('cache.url'), shimStorageCallback(done), JSON.stringify(requestData), { diff --git a/test/.eslintrc.js b/test/.eslintrc.js index 4cd5a854ac4..842bccd99b1 100644 --- a/test/.eslintrc.js +++ b/test/.eslintrc.js @@ -35,6 +35,6 @@ module.exports = { "no-unused-vars": "off", "no-use-before-define": "off", "no-useless-escape": "off", - "one-var": "off", + "one-var": "off" } }; diff --git a/test/fake-server/README.md b/test/fake-server/README.md new file mode 100644 index 00000000000..2e93fa44947 --- /dev/null +++ b/test/fake-server/README.md @@ -0,0 +1,28 @@ +## fake-server + +A simple http server that matches incoming requests to a stored list of `request-response` pair, and returns a fake response. The server is meant to replace actual calls to `appnexus` adapter (extendable to any other adapter) endpoint when the e2e tests runs. + + +## How to add a Request - Response pair ? + +All the `request-response` pairs are stored in the `fixtures/` directory. They are organized by their test group and test name. + +Follow the steps below to add another `request-response` pair. + +1. Inside the `/fixtures` directory, create a directory and give it a suitable name. + - If you are creating a one-off type of test, you can name this directory with a name that describes the test; for example `basic-banner`. + - If you plan to create a series of tests focusing on one feature/topic, then you can create a generic container directory to hold all your tests together; for example `longform`. + - If you did the latter case, please proceed to create the necessary test directories describing them with a meaningful and **unique** test name. +2. If you are planning to handle multiple bidder requests as part of your tests, you will need to create a specific directory for each request. For example, you could create a pair named like so `longform_biddersettings_1` and `longform_biddersettings_2`. +3. Once all your directories are created, inside the bottom test folder(s), create **three files**: + - `description.md` (Contains path of test page and spec file. Also, contains the ad unit that generates the **request-response** pair) + - `request.json` (This object will be matched against the acutal incoming request) + - `response.json` (This object will be returned as response of the fake-server, if the response object's request pair matchest the incoming request) + +For reference, please have a look at `fixtures/basic-banner` or `fixtures/longform` directories (as matching your scenario). + +## How is the server initiated ? + +When the command `gulp e2e-test --host=test.localhost` is executed, gulp task `test` automatically spawns the `fake-server` which runs on port `4444`. + +On execution of the tests, the server automatically stops. \ No newline at end of file diff --git a/test/fake-server/fake-responder.js b/test/fake-server/fake-responder.js new file mode 100644 index 00000000000..c884b00ca9c --- /dev/null +++ b/test/fake-server/fake-responder.js @@ -0,0 +1,75 @@ +/* eslint no-console: 0 */ +const deepEqual = require('deep-equal'); +const generateFixtures = require('./fixtures'); +const path = require('path'); + +// path to the fixture directory +const fixturesPath = path.join(__dirname, 'fixtures'); + +// An object storing 'Request-Response' pairs. +let REQ_RES_MAP = generateFixtures(fixturesPath); + +/** + * Matches 'req.body' with the responseBody pair + * @param {object} requestBody - `req.body` of incoming request hitting middleware 'fakeResponder'. + * @returns {objct} responseBody + */ +const matchResponse = function (requestBody) { + let actualUuids = []; + + const requestResponsePairs = Object.keys(REQ_RES_MAP).map(testName => REQ_RES_MAP[testName]); + + // delete 'uuid' property + requestBody.tags.forEach(body => { + // store the 'uuid' before deleting it. + actualUuids.push(body.uuid); + + // delete the 'uuid' + delete body.uuid; + }); + + ['sdk', 'referrer_detection', 'gdpr_consent'].forEach(prop => { + if (requestBody && requestBody[prop]) { + delete requestBody[prop]; + } + }); + + // delete 'uuid' from `expected request body` + requestResponsePairs + .forEach(reqRes => { reqRes.request.httpRequest && reqRes.request.httpRequest.body.tags.forEach(body => body.uuid && delete body.uuid) }); + + // match the 'actual' requestBody with the 'expected' requestBody and find the 'responseBody' + const responseBody = requestResponsePairs.filter(reqRes => reqRes.request.httpRequest && deepEqual(reqRes.request.httpRequest.body.tags, requestBody.tags))[0].response.httpResponse.body; + + // ENABLE THE FOLLOWING CODE FOR TROUBLE-SHOOTING FAKED REQUESTS; COMMENT AGAIN WHEN DONE + // console.log('value found for responseBody:', responseBody); + // responseBody.tags.forEach((tag, index) => { + // console.log('value found for responseBody.tag[', index, ']:ads', tag.ads); + // }); + + // copy the actual uuids to the responseBody + // TODO:: what if responseBody is 'undefined' + responseBody.tags.forEach(body => { + body.uuid = actualUuids.shift(); + }); + + return responseBody; +} + +/** + * An ExpressJs middleware function that checks the incoming Request Body + * and returns the corresponding Fake Response Body pertaining to that Request. + */ + +const fakeResponder = function (req, res, next) { + const request = JSON.parse(req.body); + + const response = matchResponse(request); + + res.type('json'); + res.write(JSON.stringify(response)); + + next(); +} + +module.exports = fakeResponder; diff --git a/test/fake-server/fixtures/basic-banner/description.md b/test/fake-server/fixtures/basic-banner/description.md new file mode 100644 index 00000000000..45ef571aaac --- /dev/null +++ b/test/fake-server/fixtures/basic-banner/description.md @@ -0,0 +1,34 @@ +Test Page - 'test/pages/banner.html' +Test Spec File - 'test/spec/e2e/banner/basic_banner_ad.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'div-gpt-ad-1460505748561-0', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13144370 + } + }] +}, { + code: 'div-gpt-ad-1460505748561-1', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + bids: [{ + bidder: "appnexus", + params: { + placementId: 13144370 + } + }] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-banner/request.json b/test/fake-server/fixtures/basic-banner/request.json new file mode 100644 index 00000000000..ea85b5a6842 --- /dev/null +++ b/test/fake-server/fixtures/basic-banner/request.json @@ -0,0 +1,61 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 300, + "height": 250 + }, + { + "width": 300, + "height": 600 + } + ], + "primary_size": { + "width": 300, + "height": 250 + }, + "ad_types": [ + "banner" + ], + "id": 13144370, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 1 + }, + { + "sizes": [ + { + "width": 300, + "height": 250 + }, + { + "width": 300, + "height": 600 + } + ], + "primary_size": { + "width": 300, + "height": 250 + }, + "ad_types": [ + "banner" + ], + "id": 13144370, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-banner/response.json b/test/fake-server/fixtures/basic-banner/response.json new file mode 100644 index 00000000000..dc73d3fa3d2 --- /dev/null +++ b/test/fake-server/fixtures/basic-banner/response.json @@ -0,0 +1,92 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13144370, + "auction_id": "8147841645883553832", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKzCKAzBAAAAwDWAAUBCJKPpe4FEKjwl-js2byJcRiq5MnUovf28WEqNgkAAAkCABEJBywAABkAAACA61HgPyEREgApEQkAMREb8GkwsqKiBjjtSEDtSEgAUABYnPFbYABotc95eACAAQGKAQCSAQNVU0SYAawCoAH6AagBAbABALgBAcABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3MzQ3MjE0Nik7AR0scicsIDk2ODQ2MDM1Nh4A8PWSAqUCIXp6ZmhVQWl1c0s0S0VOT0JseTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlJSUNhQUJ3Q0hncWdBRWtpQUVxa0FFQW1BRUFvQUVCcUFFRHNBRUF1UUVwaTRpREFBRGdQOEVCS1l1SWd3QUE0RF9KQVozRkl5WjA1Tm9fMlFFQUFBQUFBQUR3UC1BQkFQVUJBQUFBQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU9BQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEcnJDdUNyb0RDVk5KVGpNNk5EY3pOZUFEcUJXSUJBQ1FCQUNZQkFIQkIFRQkBCHlRUQkJAQEUTmdFQVBFEY0BkEg0QkFDSUJmOGuaAokBIUl3OTBCOikBJG5QRmJJQVFvQUQROFhEZ1B6b0pVMGxPTXpvME56TTFRS2dWUxFoDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJTDTrYdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9oZWxsb193b3JsZAVO8EA_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAOsAsgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw248F6YBACiBAsxMC43NS43NC42OagEkECyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggA4AQB8ATTgZcuiAUBmAUAoAX______wEDFAHABQDJBWmAFPA_0gUJCQkMcAAA2AUB4AUB8AUB-gUECAAQAJAGAJgGALgGAMEGCSM08L_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgHyBgIIAIAHAYgHAKAHAQ..&s=68cfb6ed042ea47f5d3fc2c32cc068500e542066", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "banner", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 96846035, + "media_type_id": 1, + "media_subtype_id": 1, + "cpm": 0.5, + "cpm_publisher_currency": 0.5, + "is_bin_price_applied": false, + "publisher_currency_code": "$", + "brand_category_id": 0, + "test": 99999, + "client_initiated_ad_counting": true, + "rtb": { + "banner": { + "content": "
", + "width": 300, + "height": 250 + }, + "trackers": [ + { + "impression_urls": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue&e=wqT_3QK7CKA7BAAAAwDWAAUBCJKPpe4FEKjwl-js2byJcRiq5MnUovf28WEqNgkAAAECCOA_EQEHNAAA4D8ZAAAAgOtR4D8hERIAKREJADERG6gwsqKiBjjtSEDtSEgCUNOBly5YnPFbYABotc95eJK4BYABAYoBA1VTRJIBAQbwUpgBrAKgAfoBqAEBsAEAuAEBwAEEyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTczNDcyMTQ2KTt1ZigncicsIDk2ODQ2MDM1Nh4A8PWSAqUCIXp6ZmhVQWl1c0s0S0VOT0JseTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlJSUNhQUJ3Q0hncWdBRWtpQUVxa0FFQW1BRUFvQUVCcUFFRHNBRUF1UUVwaTRpREFBRGdQOEVCS1l1SWd3QUE0RF9KQVozRkl5WjA1Tm9fMlFFQUFBQUFBQUR3UC1BQkFQVUJBQUFBQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU9BQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEcnJDdUNyb0RDVk5KVGpNNk5EY3pOZUFEcUJXSUJBQ1FCQUNZQkFIQkIFRQkBCHlRUQkJAQEUTmdFQVBFEY0BkEg0QkFDSUJmOGuaAokBIUl3OTBCOikBJG5QRmJJQVFvQUQROFhEZ1B6b0pVMGxPTXpvME56TTFRS2dWUxFoDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJTDTrYdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9oZWxsb193b3JsZAVO8EA_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAOsAsgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw248F6YBACiBAsxMC43NS43NC42OagEkECyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggB4AQB8ATTgZcuiAUBmAUAoAX______wEDFAHABQDJBWmIFPA_0gUJCQkMcAAA2AUB4AUB8AUB-gUECAAQAJAGAJgGALgGAMEGCSM08D_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgHyBgIIAIAHAYgHAKAHAQ..&s=951a029669a69e3f0c527c937c2d852be92802e1" + ], + "video_events": {} + } + ] + } + } + ] + }, + { + "tag_id": 13144370, + "auction_id": "8147841645883553832", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKzCKAzBAAAAwDWAAUBCJKPpe4FEKjwl-js2byJcRiq5MnUovf28WEqNgkAAAkCABEJBywAABkAAACA61HgPyEREgApEQkAMREb8GkwsqKiBjjtSEDtSEgAUABYnPFbYABotc95eACAAQGKAQCSAQNVU0SYAawCoAH6AagBAbABALgBAcABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3MzQ3MjE0Nik7AR0scicsIDk2ODQ2MDM1Nh4A8PWSAqUCIXp6ZmhVQWl1c0s0S0VOT0JseTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlJSUNhQUJ3Q0hncWdBRWtpQUVxa0FFQW1BRUFvQUVCcUFFRHNBRUF1UUVwaTRpREFBRGdQOEVCS1l1SWd3QUE0RF9KQVozRkl5WjA1Tm9fMlFFQUFBQUFBQUR3UC1BQkFQVUJBQUFBQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU9BQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEcnJDdUNyb0RDVk5KVGpNNk5EY3pOZUFEcUJXSUJBQ1FCQUNZQkFIQkIFRQkBCHlRUQkJAQEUTmdFQVBFEY0BkEg0QkFDSUJmOGuaAokBIUl3OTBCOikBJG5QRmJJQVFvQUQROFhEZ1B6b0pVMGxPTXpvME56TTFRS2dWUxFoDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJTDTrYdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9oZWxsb193b3JsZAVO8EA_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAOsAsgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw248F6YBACiBAsxMC43NS43NC42OagEkECyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggA4AQB8ATTgZcuiAUBmAUAoAX______wEDFAHABQDJBWmAFPA_0gUJCQkMcAAA2AUB4AUB8AUB-gUECAAQAJAGAJgGALgGAMEGCSM08L_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgHyBgIIAIAHAYgHAKAHAQ..&s=68cfb6ed042ea47f5d3fc2c32cc068500e542066", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "banner", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 968460356666, + "media_type_id": 1, + "media_subtype_id": 1, + "cpm": 0.5, + "cpm_publisher_currency": 0.5, + "is_bin_price_applied": false, + "publisher_currency_code": "$", + "brand_category_id": 0, + "client_initiated_ad_counting": true, + "rtb": { + "banner": { + "content": "
", + "width": 300, + "height": 250 + }, + "trackers": [ + { + "impression_urls": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue&e=wqT_3QK7CKA7BAAAAwDWAAUBCJKPpe4FEKjwl-js2byJcRiq5MnUovf28WEqNgkAAAECCOA_EQEHNAAA4D8ZAAAAgOtR4D8hERIAKREJADERG6gwsqKiBjjtSEDtSEgCUNOBly5YnPFbYABotc95eJK4BYABAYoBA1VTRJIBAQbwUpgBrAKgAfoBqAEBsAEAuAEBwAEEyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTczNDcyMTQ2KTt1ZigncicsIDk2ODQ2MDM1Nh4A8PWSAqUCIXp6ZmhVQWl1c0s0S0VOT0JseTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlJSUNhQUJ3Q0hncWdBRWtpQUVxa0FFQW1BRUFvQUVCcUFFRHNBRUF1UUVwaTRpREFBRGdQOEVCS1l1SWd3QUE0RF9KQVozRkl5WjA1Tm9fMlFFQUFBQUFBQUR3UC1BQkFQVUJBQUFBQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU9BQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEcnJDdUNyb0RDVk5KVGpNNk5EY3pOZUFEcUJXSUJBQ1FCQUNZQkFIQkIFRQkBCHlRUQkJAQEUTmdFQVBFEY0BkEg0QkFDSUJmOGuaAokBIUl3OTBCOikBJG5QRmJJQVFvQUQROFhEZ1B6b0pVMGxPTXpvME56TTFRS2dWUxFoDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJTDTrYdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9oZWxsb193b3JsZAVO8EA_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAOsAsgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw248F6YBACiBAsxMC43NS43NC42OagEkECyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggB4AQB8ATTgZcuiAUBmAUAoAX______wEDFAHABQDJBWmIFPA_0gUJCQkMcAAA2AUB4AUB8AUB-gUECAAQAJAGAJgGALgGAMEGCSM08D_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgHyBgIIAIAHAYgHAKAHAQ..&s=951a029669a69e3f0c527c937c2d852be92802e1" + ], + "video_events": {} + } + ] + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-instream/description.md b/test/fake-server/fixtures/basic-instream/description.md new file mode 100644 index 00000000000..5d185f23ad3 --- /dev/null +++ b/test/fake-server/fixtures/basic-instream/description.md @@ -0,0 +1,28 @@ +Test Page - 'test/pages/instream.html' +Test Spec File - 'test/spec/e2e/instream/basic_instream_ad.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'video1', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480] + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: '13232361', + video: { + skipppable: false, + playback_methods: ['auto_play_sound_off'] + } + } + } + ] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-instream/request.json b/test/fake-server/fixtures/basic-instream/request.json new file mode 100644 index 00000000000..db07ad3e98a --- /dev/null +++ b/test/fake-server/fixtures/basic-instream/request.json @@ -0,0 +1,34 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 13232361, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "require_asset_url": true, + "video": {}, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-instream/response.json b/test/fake-server/fixtures/basic-instream/response.json new file mode 100644 index 00000000000..5f51034f0be --- /dev/null +++ b/test/fake-server/fixtures/basic-instream/response.json @@ -0,0 +1,42 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [{ + "tag_id": 13232361, + "auction_id": "1398509384102899505", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Finstream.html&e=wqT_3QKxCKAxBAAAAwDWAAUBCKXQzPAFELHeg_SAnKC0ExjCs_b6q5D9_0oqNgkAAAkCABEJBywAABkAAADgehQUQCEREgApEQkAMREb8Hkw6dGnBjjtSEDtSEgAUABYnPFbYABozbp1eACAAQGKAQCSAQNVU0SYAQGgAQGoAQGwAQC4AQPAAQDIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzgzMTM3NjUpO3VmKCdyJywgOTc1MTc3NzEsIC4eAPD1kgK1AiF5andtb2dpMi1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNmRHbkJsZ0FZTUlHYUFCd0tIZ0dnQUU4aUFFR2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFVUU1FQjg2MXFwQUFBRkVESkFmZjUwcVFyNGVvXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHR2aThDcm9EQ1ZOSlRqTTZORGN6T09BRC1SaUlCQUNRQkFDWUJBSEJCBUUJAQh5UVEJCQEBFE5nRUFQRRGNAZAsNEJBQ0lCWUlscVFVAREBFDx3UHcuLpoCiQEhTGc5WkRRNjkBJG5QRmJJQVFvQUQVSFRVUURvSlUwbE9Nem8wTnpNNFFQa1lTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBSZUFBLsICP2h0dHA6Ly9wcmViaWQub3JnL2Rldi1kb2NzL3Nob3ctdmlkZW8td2l0aC1hLWRmcC12aWRlby10YWcuaHRtbNgCAOACrZhI6gIzaHQFSkh0ZXN0LmxvY2FsaG9zdDo5OTk5BRQ4L3BhZ2VzL2luc3RyZWFtBT7IgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvCanwXpgEAKIECzEwLjc1Ljc0LjY5qAS0LLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM42gQCCADgBADwBMuBwC6IBQGYBQCgBf______AQMUAcAFAMkFaX8U8D_SBQkJCQx4AADYBQHgBQHwBcOVC_oFBAgAEACQBgGYBgC4BgDBBgklKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=6805157848bdfdf973d0dbafff4bb9b4c4ce7e60", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [{ + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQklKBNeAAAAABEx74AO4IBoExklKBNeAAAAACDLgcAuKAAw7Ug47UhA0-hISLuv1AFQ6dGnBljDlQtiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcuBwC6wAQE.&s=07e6e5f2f03cc92e899c3ddbf4e2988e966caaa2&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97517771, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10.000000, + "cpm_publisher_currency": 10.000000, + "publisher_currency_code": "$", + "brand_category_id": 36, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": ["auto_play_sound_on"], + "frameworks": ["vpaid_1_0", "vpaid_2_0"], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Finstream.html&e=wqT_3QKNCaCNBAAAAwDWAAUBCKXQzPAFELHeg_SAnKC0ExjCs_b6q5D9_0oqNgkAAAECCBRAEQEHNAAAFEAZAAAA4HoUFEAhERIAKREJADERG6gw6dGnBjjtSEDtSEgCUMuBwC5YnPFbYABozbp1eJG4BYABAYoBA1VTRJIBAQbwUpgBAaABAagBAbABALgBA8ABBMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3ODMxMzc2NSk7dWYoJ3InLCA5NzUxNzc3MSwgLh4A8PWSArUCIXlqd21vZ2kyLUx3S0VNdUJ3QzRZQUNDYzhWc3dBRGdBUUFSSTdVaFE2ZEduQmxnQVlNSUdhQUJ3S0hnR2dBRThpQUVHa0FFQW1BRUFvQUVCcUFFRHNBRUF1UUh6cldxa0FBQVVRTUVCODYxcXBBQUFGRURKQWZmNTBxUXI0ZW9fMlFFQUFBQUFBQUR3UC1BQkFQVUJBQUFBQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU9BQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEdHZpOENyb0RDVk5KVGpNNk5EY3pPT0FELVJpSUJBQ1FCQUNZQkFIQkIFRQkBCHlRUQkJAQEUTmdFQVBFEY0BkCw0QkFDSUJZSWxxUVUBEQEUPHdQdy4umgKJASFMZzlaRFE2OQEkblBGYklBUW9BRBVIVFVRRG9KVTBsT016bzBOek00UVBrWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8FJlQUEuwgI_aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc2hvdy12aWRlby13aXRoLWEtZGZwLXZpZGVvLXRhZy5odG1s2AIA4AKtmEjqAjNodAVKSHRlc3QubG9jYWxob3N0Ojk5OTkFFDgvcGFnZXMvaW5zdHJlYW0FPmjyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-4ElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw398F6YBACiBAsxMC43NS43NC42OagEtCyyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczONoEAggB4AQA8ATLgcAuiAUBmAUAoAX______wEDFAHABQDJBWnbFPA_0gUJCQkMeAAA2AUB4AUB8AXDlQv6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=68b9d39d60a72307a201e479000a8c7be5508188" + } + } + }] + }] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-native/description.md b/test/fake-server/fixtures/basic-native/description.md new file mode 100644 index 00000000000..950cc5da7d7 --- /dev/null +++ b/test/fake-server/fixtures/basic-native/description.md @@ -0,0 +1,62 @@ +Test Page - 'test/pages/native.html' +Test Spec File - 'test/spec/e2e/native/basic_native_ad.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: '/19968336/prebid_native_example_1', + sizes: [360, 360], + mediaTypes: { + native: { + title: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + } + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232354, + allowSmallerSizes: true + } + }] +}, { + code: '/19968336/prebid_native_example_2', + sizes: [ + [1, 1] + ], + mediaTypes: { + native: { + title: { + required: true + }, + body: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + }, + icon: { + required: false + }, + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232354, + allowSmallerSizes: true + } + }] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-native/request.json b/test/fake-server/fixtures/basic-native/request.json new file mode 100644 index 00000000000..08e75d5bd69 --- /dev/null +++ b/test/fake-server/fixtures/basic-native/request.json @@ -0,0 +1,81 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 1, + "height": 1 + } + ], + "ad_types": [ + "native" + ], + "id": 13232354, + "allow_smaller_sizes": true, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "native": { + "layouts": [ + { + "title": { + "required": true + }, + "main_image": { + "required": true + }, + "sponsored_by": { + "required": true + } + } + ] + }, + "hb_source": 1 + }, + { + "sizes": [ + { + "width": 1, + "height": 1 + } + ], + "ad_types": [ + "native" + ], + "id": 13232354, + "allow_smaller_sizes": true, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "native": { + "layouts": [ + { + "title": { + "required": true + }, + "description": { + "required": true + }, + "main_image": { + "required": true + }, + "sponsored_by": { + "required": true + }, + "icon": { + "required": false + } + } + ] + }, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-native/response.json b/test/fake-server/fixtures/basic-native/response.json new file mode 100644 index 00000000000..fb85110663d --- /dev/null +++ b/test/fake-server/fixtures/basic-native/response.json @@ -0,0 +1,116 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13232354, + "auction_id": "2566965852006062421", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fnative.html&e=wqT_3QLhB6DhAwAAAwDWAAUBCNDZme8FENWyhPv4uuzPIxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMOLRpwY47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc1MzgyMjI0KTsBHThyJywgOTc0OTQ0MDMsIDEdHvDQkgKpAiFCenhPTlFqOC1Md0tFSVBMdmk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNHRHbkJsZ0FZSUlDYUFCd0FIZ0FnQUdtQVlnQl9GLVFBUUNZQVFDZ0FRR29BUU93QVFDNUFmT3RhcVFBQUNSQXdRSHpyV3FrQUFBa1FNa0JRTDdBTHVfbzFqX1pBUUFBQUFBQUFQQV80QUVBOVFFQUFBQUFtQUlBb0FJQXRRSUFBQUFBdlFJQUFBQUE0QUlBNkFJQS1BSUFnQU1CbUFNQnFBUDgBxIh1Z01KVTBsT016bzBOelF5NEFQbUZvZ0VBSkFFQUpnRUFjRQldBQEIREpCBQgJARgyQVFBOFFRCQ0BAVBQZ0VBSWdGaGlVLpoCiQEhYWdfb0o6LQEkblBGYklBUW9BRBVYDGtRRG8yhQAQUU9ZV1MRWAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0MoGVBQS7YAgDgAq2YSOoCMWh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5BRTwvC9wYWdlcy9uYXRpdmUuaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qATruAKyBA4IABABGAAgACgAMAA4ArgEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQy2gQCCADgBAHwBIPLvi6IBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQkMeAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYJJTTwv8gGANAG9S_aBhYKEAkUGQFQEAAYAOAGDPIGAggAgAcBiAcAoAdB&s=54514bb848c51d509dfe3e21af09b77edfe9738e", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "native", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97494403, + "media_type_id": 12, + "media_subtype_id": 65, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 53, + "client_initiated_ad_counting": true, + "viewability": { + "config": "" + }, + "rtb": { + "native": { + "title": "This is a Prebid Native Creative", + "sponsored": "Prebid.org", + "main_img": { + "url": "http://vcdn.adnxs.com/p/creative-image/94/22/cd/0f/9422cd0f-f400-45d3-80f5-2b92629d9257.jpg", + "width": 3000, + "height": 2250, + "prevent_crop": false + }, + "link": { + "url": "http://prebid.org/dev-docs/show-native-ads.html", + "click_trackers": [ + "http://sin3-ib.adnxs.com/click?AAAAAAAAJEAAAAAAAAAkQAAAAAAAACRAAAAAAAAAJEAAAAAAAAAkQFUZYY_XsZ8jKnKSKrrb42HQbOZdAAAAAOLoyQBtJAAAbSQAAAIAAACDpc8FnPgWAAAAAABVU0QAVVNEAAEAAQBNXQAAAAABAQQCAAAAALoA8BZszgAAAAA./bcr=AAAAAAAA8D8=/cnd=%21ag_oJQj8-LwKEIPLvi4YnPFbIAQoADEAAAAAAAAkQDoJU0lOMzo0NzQyQOYWSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA./cca=OTMyNSNTSU4zOjQ3NDI=/bn=89169/" + ] + }, + "impression_trackers": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fnative.html&e=wqT_3QLpB6DpAwAAAwDWAAUBCNDZme8FENWyhPv4uuzPIxiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjRuAWAAQGKAQNVU0SSAQEG8FKYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzUzODIyMjQpO3VmKCdyJywgOTc0OTQ0MDMsIC4eAPDQkgKpAiFCenhPTlFqOC1Md0tFSVBMdmk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNHRHbkJsZ0FZSUlDYUFCd0FIZ0FnQUdtQVlnQl9GLVFBUUNZQVFDZ0FRR29BUU93QVFDNUFmT3RhcVFBQUNSQXdRSHpyV3FrQUFBa1FNa0JRTDdBTHVfbzFqX1pBUUFBQUFBQUFQQV80QUVBOVFFQUFBQUFtQUlBb0FJQXRRSUFBQUFBdlFJQUFBQUE0QUlBNkFJQS1BSUFnQU1CbUFNQnFBUDgBxIh1Z01KVTBsT016bzBOelF5NEFQbUZvZ0VBSkFFQUpnRUFjRQldBQEIREpCBQgJARgyQVFBOFFRCQ0BAVBQZ0VBSWdGaGlVLpoCiQEhYWdfb0o6LQEkblBGYklBUW9BRBVYDGtRRG8yhQAQUU9ZV1MRWAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0MoGVBQS7YAgDgAq2YSOoCMWh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5BRTwlS9wYWdlcy9uYXRpdmUuaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qATruAKyBA4IABABGAAgACgAMAA4ArgEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQy2gQCCAHgBAHwBEH6IIgFAZgFAKAF_xEBGAHABQDJBQAFARTwP9IFCQkFC3wAAADYBQHgBQHwBZn0IfoFBAgAEACQBgGYBgC4BgDBBgEhQAAA8D_IBgDQBvUv2gYWChAAOgEAUBAAGADgBgzyBgIIAIAHAYgHAKAHQQ..&s=6b203c7aee654cffa9c0b3771f6945f6d1e8d06c" + ], + "id": 97494403 + } + } + } + ] + }, + { + "tag_id": 13232354, + "auction_id": "6083251961435599864", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fnative.html&e=wqT_3QLhB6DhAwAAAwDWAAUBCNDZme8FEPjnxITbrYO2VBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMOLRpwY47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc1MzgyMjI0KTsBHSxyJywgOTc0OTQyMDQ2HgDw0JICqQIhYlR3OWZBajgtTHdLRUx6SnZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWUlJQ2FBQndBSGdBZ0FHbUFZZ0JfRi1RQVFDWUFRQ2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCeVdmYjBYeWIxVF9aQVFBQUFBQUFBUEFfNEFFQTlRRUFBQUFBbUFJQW9BSUF0UUlBQUFBQXZRSUFBQUFBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVA4AcSIdWdNSlUwbE9Nem8wTnpReTRBUG1Gb2dFQUpBRUFKZ0VBY0UJXQUBCERKQgUICQEYMkFRQThRUQkNAQFUUGdFQUlnRmhpVS6aAokBIW9ROTNPUTYtASRuUEZiSUFRb0FEFVgMa1FEbzKFABBRT1lXUxFYDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQygZUFBLtgCAOACrZhI6gIxaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkFFPC8L3BhZ2VzL25hdGl2ZS5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBOu4ArIEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDLaBAIIAOAEAfAEvMm-LogFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJCQx4AADYBQHgBQHwBZn0IfoFBAgAEACQBgGYBgC4BgDBBgklNPC_yAYA0Ab1L9oGFgoQCRQZAVAQABgA4AYM8gYCCACABwGIBwCgB0E.&s=99a73b39ab82dd9384eee306ff03276ab688cfe5", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "native", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97494204, + "media_type_id": 12, + "media_subtype_id": 65, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 53, + "client_initiated_ad_counting": true, + "viewability": { + "config": "" + }, + "rtb": { + "native": { + "title": "This is a Prebid Native Creative", + "desc": "This is a Prebid Native Creative. There are many like it, but this one is mine.", + "sponsored": "Prebid.org", + "icon": { + "url": "http://vcdn.adnxs.com/p/creative-image/1a/3e/e9/5b/1a3ee95b-06cd-4260-98c7-0258627c9197.png", + "width": 127, + "height": 83, + "prevent_crop": false + }, + "main_img": { + "url": "http://vcdn.adnxs.com/p/creative-image/f8/7f/0f/13/f87f0f13-230c-4f05-8087-db9216e393de.jpg", + "width": 989, + "height": 742, + "prevent_crop": false + }, + "link": { + "url": "http://prebid.org/dev-docs/show-native-ads.html", + "click_trackers": [ + "http://sin3-ib.adnxs.com/click?AAAAAAAAJEAAAAAAAAAkQAAAAAAAACRAAAAAAAAAJEAAAAAAAAAkQPgzkbBtDWxUKnKSKrrb42HQbOZdAAAAAOLoyQBtJAAAbSQAAAIAAAC8pM8FnPgWAAAAAABVU0QAVVNEAAEAAQBNXQAAAAABAQQCAAAAALoAJhcX3AAAAAA./bcr=AAAAAAAA8D8=/cnd=%21oQ93OQj8-LwKELzJvi4YnPFbIAQoADEAAAAAAAAkQDoJU0lOMzo0NzQyQOYWSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA./cca=OTMyNSNTSU4zOjQ3NDI=/bn=89169/" + ] + }, + "impression_trackers": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fnative.html&e=wqT_3QLpB6DpAwAAAwDWAAUBCNDZme8FEPjnxITbrYO2VBiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlC8yb4uWJzxW2AAaM26dXjRuAWAAQGKAQNVU0SSAQEG8FKYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzUzODIyMjQpO3VmKCdyJywgOTc0OTQyMDQsIC4eAPDQkgKpAiFiVHc5ZkFqOC1Md0tFTHpKdmk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNHRHbkJsZ0FZSUlDYUFCd0FIZ0FnQUdtQVlnQl9GLVFBUUNZQVFDZ0FRR29BUU93QVFDNUFmT3RhcVFBQUNSQXdRSHpyV3FrQUFBa1FNa0J5V2ZiMFh5YjFUX1pBUUFBQUFBQUFQQV80QUVBOVFFQUFBQUFtQUlBb0FJQXRRSUFBQUFBdlFJQUFBQUE0QUlBNkFJQS1BSUFnQU1CbUFNQnFBUDgBxIh1Z01KVTBsT016bzBOelF5NEFQbUZvZ0VBSkFFQUpnRUFjRQldBQEIREpCBQgJARgyQVFBOFFRCQ0BAVRQZ0VBSWdGaGlVLpoCiQEhb1E5M09RNi0BJG5QRmJJQVFvQUQVWAxrUURvMoUAEFFPWVdTEVgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDKBlQUEu2AIA4AKtmEjqAjFodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OQUU8LwvcGFnZXMvbmF0aXZlLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagE67gCsgQOCAAQARgAIAAoADAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDc0MtoEAggB4AQB8AS8yb4uiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkJDHgAANgFAeAFAfAFmfQh-gUECAAQAJAGAZgGALgGAMEGCSU48D_IBgDQBvUv2gYWChAAOgEAUBAAGADgBgzyBgIIAIAHAYgHAKAHQQ..&s=5c316c116b6e2bdb19f3950c4c769821e735688e" + ], + "id": 97494204 + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-outstream/description.md b/test/fake-server/fixtures/basic-outstream/description.md new file mode 100644 index 00000000000..c5855d6af15 --- /dev/null +++ b/test/fake-server/fixtures/basic-outstream/description.md @@ -0,0 +1,44 @@ +Test Page - 'test/pages/outstream.html' +Test Spec File - 'test/spec/e2e/outstream/basic_outstream_ad.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'video_ad_unit_1', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480] + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232385, + video: { + skippable: true, + playback_method: ['auto_play_sound_off'] + } + } + }] +}, { + code: 'video_ad_unit_2', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480] + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232385, + video: { + skippable: true, + playback_method: ['auto_play_sound_off'] + } + } + }] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-outstream/request.json b/test/fake-server/fixtures/basic-outstream/request.json new file mode 100644 index 00000000000..611a518fc2d --- /dev/null +++ b/test/fake-server/fixtures/basic-outstream/request.json @@ -0,0 +1,50 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [{ + "sizes": [{ + "width": 640, + "height": 480 + }], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": ["video"], + "id": 13232385, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "video": { + "skippable": true, + "playback_method": ["auto_play_sound_off"] + }, + "hb_source": 1 + }, { + "sizes": [{ + "width": 640, + "height": 480 + }], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": ["video"], + "id": 13232385, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "video": { + "skippable": true, + "playback_method": ["auto_play_sound_off"] + }, + "hb_source": 1 + }], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-outstream/response.json b/test/fake-server/fixtures/basic-outstream/response.json new file mode 100644 index 00000000000..13b4e527b1f --- /dev/null +++ b/test/fake-server/fixtures/basic-outstream/response.json @@ -0,0 +1,105 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13232385, + "auction_id": "527250675737245396", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Foutstream.html&e=wqT_3QKwCKAwBAAAAwDWAAUBCOiWpO8FENTtnJej9sqoBxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMIHSpwY47UhA7UhIAFAAWJzxW2AAaOWljwF4AIABAYoBAJIBA1VTRJgBAaABAagBAbABALgBA8ABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3NTU1Mzg5NikFHTRyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFUenpuS1FqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSG5NQW5aODYzalA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TOEE4RDgumgKJASFXdzkxSDo5ASRuUEZiSUFRb0FEFVhYa1FEb0pVMGxPTXpvME9ETTBRUGtXU1ENTwxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8EllQUEuwgI4aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc2hvdy1vdXRzdHJlYW0tdmlkZW8tYWRzLmh0bWzYAgDgAq2YSOoCNA1DSHRlc3QubG9jYWxob3N0Ojk5OTkFFBgvcGFnZXMvFUkALgE_yIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzLwmj8F6YBACiBAsxMC43NS43NC42OagEmM8CsgQSCAQQBBiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ4MzTaBAIIAOAEAPAEy4HALogFAZgFAKAF_____wUDFAHABQDJBWlyFPA_0gUJCQkMeAAA2AUB4AUB8AXDlQv6BQQIABAAkAYBmAYAuAYAwQYJJTTwv8gGANAG9S_aBhYKEAkUGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=9953ce4d94992db04897ab580bf81b3e274b2601", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQloC-ldAAAAABHUNucysitRBxloC-ldAAAAACDLgcAuKAAw7Ug47UhA0-hISLuv1AFQgdKnBljDlQtiAi0taAFwAXgAgAECiAEEkAGABZgB4AOgAQCoAcuBwC6wAQE.&s=979aee1106a0bea5609a3c23fdc46153ad6d9eec&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97517771, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 36, + "renderer_url": "http://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js", + "renderer_id": 2, + "renderer_config": "{\"skippable\":{\"videoThreshold\":null,\"skipLocation\":\"top-right\"}}", + "client_initiated_ad_counting": true, + "viewability": { + "config": "tv=vh2-121&d=1x1&s=3479483&st=0&vctx=4&ts=1575553896&vc=iab;vid_ccr=1&vjs=http%3A%2F%2Fcdn.adnxs.com%2Fv%2Fvideo%2F182%2Ftrk.js&cb=http%3A%2F%2Fsin3-ib.adnxs.com%2Fvevent%3Fan_audit%3D0%26referrer%3Dhttp%253A%252F%252Ftest.localhost%253A9999%252Ftest%252Fpages%252Foutstream.html%26e%3DwqT_3QK4CKA4BAAAAwDWAAUBCOiWpO8FENTtnJej9sqoBxiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIHSpwY47UhA7UhIAlDLgcAuWJzxW2AAaOWljwF4urgFgAEBigEDVVNEkgUG8FKYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzU1NTM4OTYpO3VmKCdyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFUenpuS1FqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSG5NQW5aODYzalA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TOEE4RDgumgKJASFXdzkxSDo5ASRuUEZiSUFRb0FEFVhYa1FEb0pVMGxPTXpvME9ETTBRUGtXU1ENTwxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8EllQUEuwgI4aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc2hvdy1vdXRzdHJlYW0tdmlkZW8tYWRzLmh0bWzYAgDgAq2YSOoCNA1DSHRlc3QubG9jYWxob3N0Ojk5OTkFFBgvcGFnZXMvFUkALgE_yIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzLwmj8F6YBACiBAsxMC43NS43NC42OagEmM8CsgQSCAQQBBiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ4MzTaBAIIAeAEAPAEy4HALogFAZgFAKAF_____wUDFAHABQDJBWl6FPA_0gUJCQkMeAAA2AUB4AUB8AXDlQv6BQQIABAAkAYBmAYAuAYAwQYJJTTwP8gGANAG9S_aBhYKEAkUGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA%26s%3D5adef946cd5f0d8db86d67860914e02ef6f91d6b&cet=0&cecb=&rdcb=http%3A%2F%2Fsin3-ib.adnxs.com%2Frd_log%3Fan_audit%3D0%26referrer%3Dhttp%253A%252F%252Ftest.localhost%253A9999%252Ftest%252Fpages%252Foutstream.html%26e%3DwqT_3QKMCaCMBAAAAwDWAAUBCOiWpO8FENTtnJej9sqoBxiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIHSpwY47UhA7UhIAlDLgcAuWJzxW2AAaOWljwF4urgFgAEBigEDVVNEkgUG8FKYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzU1NTM4OTYpO3VmKCdyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFUenpuS1FqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSG5NQW5aODYzalA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TOEE4RDgumgKJASFXdzkxSDo5ASRuUEZiSUFRb0FEFVhYa1FEb0pVMGxPTXpvME9ETTBRUGtXU1ENTwxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8EllQUEuwgI4aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc2hvdy1vdXRzdHJlYW0tdmlkZW8tYWRzLmh0bWzYAgDgAq2YSOoCNA1DSHRlc3QubG9jYWxob3N0Ojk5OTkFFBgvcGFnZXMvFUkALgE_aPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7gSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzDffwXpgEAKIECzEwLjc1Ljc0LjY5qASYzwKyBBIIBBAEGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDgzNNoEAggB4AQA8ATLgcAuiAUBmAUAoAX_____BQMUAcAFAMkFac4U8D_SBQkJCQx4AADYBQHgBQHwBcOVC_oFBAgAEACQBgGYBgC4BgDBBgklNPA_yAYA0Ab1L9oGFgoQCRQZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.%26s%3Df2a73057b50fb0c9e98a6093141472a4ed2e401e&bridge=1.11.0&rblog=auc=527250675737245396;bm=9325;sm=9325;cr=97517771;pl=13232385&vid_context=anoutstream;anbannerstream;anoverlayplayer" + }, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_off" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "content": "adnxs00:00:30.000" + } + } + } + ] + }, + { + "tag_id": 13232385, + "auction_id": "3449642271543746980", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Foutstream.html&e=wqT_3QKwCKAwBAAAAwDWAAUBCOiWpO8FEKTDpazn6-XvLxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMIHSpwY47UhA7UhIAFAAWJzxW2AAaOWljwF4AIABAYoBAJIBA1VTRJgBAaABAagBAbABALgBA8ABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3NTU1Mzg5NikFHTRyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFvendNV2dqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSHIwdDF2TTdMaVA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TPEE4RDgumgKJASFXdzkxSFE2OQEkblBGYklBUW9BRBVYWGtRRG9KVTBsT016bzBPRE0wUVBrV1NRDU8MUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBJZUFBLsICOGh0dHA6Ly9wcmViaWQub3JnL2Rldi1kb2NzL3Nob3ctb3V0c3RyZWFtLXZpZGVvLWFkcy5odG1s2AIA4AKtmEjqAjQNQ0h0ZXN0LmxvY2FsaG9zdDo5OTk5BRQYL3BhZ2VzLxVJAC4BP8iAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My8Jo_BemAQAogQLMTAuNzUuNzQuNjmoBJjPArIEEggEEAQYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0ODM02gQCCADgBADwBMuBwC6IBQGYBQCgBf____8FAxQBwAUAyQVpchTwP9IFCQkJDHgAANgFAeAFAfAFw5UL-gUECAAQAJAGAZgGALgGAMEGCSU08L_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=e43b45a2391036da6d93eda546d8808de0169bb1", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQloC-ldAAAAABGkYYl1XpffLxloC-ldAAAAACDLgcAuKAAw7Ug47UhA0-hISLuv1AFQgdKnBljDlQtiAi0taAFwAXgAgAECiAEEkAGABZgB4AOgAQCoAcuBwC6wAQE.&s=414834fdc6e268f284292aedf8b01ee525c3e999&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97517771, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 36, + "renderer_url": "http://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js", + "renderer_id": 2, + "renderer_config": "{\"skippable\":{\"videoThreshold\":null,\"skipLocation\":\"top-right\"}}", + "client_initiated_ad_counting": true, + "viewability": { + "config": "tv=vh2-121&d=1x1&s=3479483&st=0&vctx=4&ts=1575553896&vc=iab;vid_ccr=1&vjs=http%3A%2F%2Fcdn.adnxs.com%2Fv%2Fvideo%2F182%2Ftrk.js&cb=http%3A%2F%2Fsin3-ib.adnxs.com%2Fvevent%3Fan_audit%3D0%26referrer%3Dhttp%253A%252F%252Ftest.localhost%253A9999%252Ftest%252Fpages%252Foutstream.html%26e%3DwqT_3QK4CKA4BAAAAwDWAAUBCOiWpO8FEKTDpazn6-XvLxiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIHSpwY47UhA7UhIAlDLgcAuWJzxW2AAaOWljwF4urgFgAEBigEDVVNEkgUG8FKYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzU1NTM4OTYpO3VmKCdyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFvendNV2dqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSHIwdDF2TTdMaVA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TPEE4RDgumgKJASFXdzkxSFE2OQEkblBGYklBUW9BRBVYWGtRRG9KVTBsT016bzBPRE0wUVBrV1NRDU8MUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBJZUFBLsICOGh0dHA6Ly9wcmViaWQub3JnL2Rldi1kb2NzL3Nob3ctb3V0c3RyZWFtLXZpZGVvLWFkcy5odG1s2AIA4AKtmEjqAjQNQ0h0ZXN0LmxvY2FsaG9zdDo5OTk5BRQYL3BhZ2VzLxVJAC4BP8iAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My8Jo_BemAQAogQLMTAuNzUuNzQuNjmoBJjPArIEEggEEAQYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0ODM02gQCCAHgBADwBMuBwC6IBQGYBQCgBf____8FAxQBwAUAyQVpehTwP9IFCQkJDHgAANgFAeAFAfAFw5UL-gUECAAQAJAGAZgGALgGAMEGCSU08D_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..%26s%3Dc2a8dac8959d9366981afc868ec5b54853090944&cet=0&cecb=&rdcb=http%3A%2F%2Fsin3-ib.adnxs.com%2Frd_log%3Fan_audit%3D0%26referrer%3Dhttp%253A%252F%252Ftest.localhost%253A9999%252Ftest%252Fpages%252Foutstream.html%26e%3DwqT_3QKMCaCMBAAAAwDWAAUBCOiWpO8FEKTDpazn6-XvLxiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIHSpwY47UhA7UhIAlDLgcAuWJzxW2AAaOWljwF4urgFgAEBigEDVVNEkgUG8FKYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzU1NTM4OTYpO3VmKCdyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFvendNV2dqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSHIwdDF2TTdMaVA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TPEE4RDgumgKJASFXdzkxSFE2OQEkblBGYklBUW9BRBVYWGtRRG9KVTBsT016bzBPRE0wUVBrV1NRDU8MUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBJZUFBLsICOGh0dHA6Ly9wcmViaWQub3JnL2Rldi1kb2NzL3Nob3ctb3V0c3RyZWFtLXZpZGVvLWFkcy5odG1s2AIA4AKtmEjqAjQNQ0h0ZXN0LmxvY2FsaG9zdDo5OTk5BRQYL3BhZ2VzLxVJAC4BP2jyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-4ElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw338F6YBACiBAsxMC43NS43NC42OagEmM8CsgQSCAQQBBiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ4MzTaBAIIAeAEAPAEy4HALogFAZgFAKAF_____wUDFAHABQDJBWnOFPA_0gUJCQkMeAAA2AUB4AUB8AXDlQv6BQQIABAAkAYBmAYAuAYAwQYJJTTwP8gGANAG9S_aBhYKEAkUGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA%26s%3D4e9e218d8f075cb19c4a4e8da2a7e716fa15d3c5&bridge=1.11.0&rblog=auc=3449642271543746980;bm=9325;sm=9325;cr=97517771;pl=13232385&vid_context=anoutstream;anbannerstream;anoverlayplayer" + }, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_off" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "content": "adnxs00:00:30.000" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/index.js b/test/fake-server/fixtures/index.js new file mode 100644 index 00000000000..bd58bda5ad5 --- /dev/null +++ b/test/fake-server/fixtures/index.js @@ -0,0 +1,41 @@ +/* eslint-disable no-console */ + +const path = require('path'); +const fs = require('fs'); + +const REQ_RES_PAIRS = {}; + +/** + * @param {String} dirname - Path of the fixture directory + * @returns {object} reqResPair - An object containing 'request' - 'response' segregated by ad unit media type. + */ +function getReqResPairs (dirname) { + try { + const filenames = fs.readdirSync(dirname, { withFileTypes: true }); + filenames.forEach(filename => { + if (filename.isDirectory()) { + getReqResPairs(`${dirname}/${filename.name}`); + } else { + if (filename.name === 'request.json' || filename.name === 'response.json') { + const parentDir = path.basename(dirname); + if (!REQ_RES_PAIRS[parentDir]) { + REQ_RES_PAIRS[parentDir] = { + request: {}, + response: {} + } + } + if (filename.name === 'request.json') { + REQ_RES_PAIRS[parentDir]['request'] = JSON.parse(fs.readFileSync(`${dirname}/${filename.name}`, { encoding: 'utf-8' })); + } else { + REQ_RES_PAIRS[parentDir]['response'] = JSON.parse(fs.readFileSync(`${dirname}/${filename.name}`, { encoding: 'utf-8' })); + } + } + } + }); + return REQ_RES_PAIRS; + } catch (e) { + console.error(`Error:: ${e.message}`); + } +} + +module.exports = getReqResPairs; diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_1/description.md b/test/fake-server/fixtures/longform/longform_biddersettings_1/description.md new file mode 100644 index 00000000000..207e851af74 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_1/description.md @@ -0,0 +1,41 @@ +Test Page - 'integrationExamples/longform/basic_w_bidderSettings.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_bidderSettings.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + debug: true, + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_1/request.json b/test/fake-server/fixtures/longform/longform_biddersettings_1/request.json new file mode 100644 index 00000000000..aba76398093 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_1/request.json @@ -0,0 +1,387 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_1/response.json b/test/fake-server/fixtures/longform/longform_biddersettings_1/response.json new file mode 100644 index 00000000000..e3ea15d7c6e --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_1/response.json @@ -0,0 +1,114 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "2678252910506723691", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "3548675574061430850", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "8693167356543642173", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "7686428711280367086", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "3784359541475413084", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "7233136875958651734", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "159775901183771330", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "6558726890185052779", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "6624810255570939818", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "528384387675374412", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "2535665225687089273", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "2166694611986638079", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "9137369006412413609", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "3524702228053475248", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "57990683038266307", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_2/description.md b/test/fake-server/fixtures/longform/longform_biddersettings_2/description.md new file mode 100644 index 00000000000..cafbb17f61b --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_2/description.md @@ -0,0 +1,28 @@ +Test Page - 'integrationExamples/longform/basic_w_bidderSettings.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_bidderSettings.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_2/request.json b/test/fake-server/fixtures/longform/longform_biddersettings_2/request.json new file mode 100644 index 00000000000..f2f20700ffe --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_2/request.json @@ -0,0 +1,137 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_2/response.json b/test/fake-server/fixtures/longform/longform_biddersettings_2/response.json new file mode 100644 index 00000000000..e2332806dbb --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_2/response.json @@ -0,0 +1,188 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "245a09bd675168", + "tag_id": 15394006, + "auction_id": "3810681093956255668", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QKVCKAVBAAAAwDWAAUBCKD4kfAFELT_vOy9yJDxNBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIUxEMWZkUWlua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOE13Q2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFZVS10N09mcU9BXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTS1BRG9SaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJaRWxxUVUJE0RBRHdQdy4umgKJASFLdy1SRkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV6UUtFWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9AUBZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagErLkEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTPaBAIIAOAEAPAE0uyfR4gFAZgFAKAF____________AcAFAMkFAGVbFPA_0gUJCQULfAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=66ba37441db5e28c87ee52e729333fd9324333f9", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQkgfAReAAAAABG0P4_dQ0LiNBkgfAReAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=6931bf3569012d0e1f02cb5a2e88dfcafe00dba9&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QLxCOhxBAAAAwDWAAUBCKD4kfAFELT_vOy9yJDxNBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4vLgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFMRDFmZFFpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjhNd0NrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWVUtdDdPZnFPQV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU0tQURvUmlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWkVscVFVCRNEQUR3UHcuLpoCiQEhS3ctUkZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVelFLRVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkMyHQDwlUFTVF9NT0RJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKy5BLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUz2gQCCAHgBADwBGGFIIgFAZgFAKAF_xEBFAHABQDJBWm2FPA_0gUJCQkMeAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=ea46ec90cf31744c7be2af5d5f239ab4eed29098" + } + } + } + ] + }, + { + "uuid": "245a09bd675168", + "tag_id": 15394006, + "auction_id": "7325897349627488405", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QKUCKAUBAAAAwDWAAUBCKD4kfAFEJXRloy0mrTVZRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIXJUeTNJd2lta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOE13Q2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFVSzAtQ2hwcWRrXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTS1BRG9SaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJaRWxxUVUJE0RBRHdQdy4umgKJASFBQTlLQlE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV6UUtFWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9AUBZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagErLkEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTPaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAGVbFPA_0gUJCQULeAAAANgFAeAFAfAF4Fj6BQQIABAAkAYBmAYAuAYAwQYBIDAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=271fd8a0ccdfc36e320f707164588ed1b33e9861", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQkgfAReAAAAABGVqIVB09CqZRkgfAReAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICLS1oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=115ac2b842cf3efeb5acaeda94ddf05632c345ca&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QLwCOhwBAAAAwDWAAUBCKD4kfAFEJXRloy0mrTVZRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4vLgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFyVHkzSXdpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjhNd0NrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVUswLUNocHFka18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU0tQURvUmlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWkVscVFVCRNEQUR3UHcuLpoCiQEhQUE5S0JRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVelFLRVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkMyHQDwlUFTVF9NT0RJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKy5BLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUz2gQCCAHgBADwBGGFIIgFAZgFAKAF_xEBFAHABQDJBWm2FPA_0gUJCQkMdAAA2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgkkKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=f73e060b15a6bbcca65f918a296f155b78c74eca" + } + } + } + ] + }, + { + "uuid": "245a09bd675168", + "tag_id": 15394006, + "auction_id": "968802322305726102", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QKVCKAVBAAAAwDWAAUBCKD4kfAFEJbt7LTEkvi4DRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTsBHTByJywgMTQ5NDE0MTg4Nh8A8P2SArkCIUtUejN5d2lHa184UEVLekNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOE13Q2tBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFTT3dTTWVaYnVJXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGMxTS1BRG9SaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJaRWxxUVUJE0RBRHdQdy4umgKJASF0ZzY4Nmc2PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOelV6UUtFWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9AUBZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagErLkEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTPaBAIIAOAEAPAErMKfR4gFAZgFAKAF____________AcAFAMkFAGVbFPA_0gUJCQULfAAAANgFAeAFAfAF8owB-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=e35825a106304da78477df1575f981395be21d5f", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQkgfAReAAAAABGWNptGlOBxDRkgfAReAAAAACCswp9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jyjAFiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAazCn0ewAQE.&s=677bedd5b2d21fdc3f940cbae279261c8f84c2e7&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149414188, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 32, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 29000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QLxCOhxBAAAAwDWAAUBCKD4kfAFEJbt7LTEkvi4DRiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQrMKfR1ic8VtgAGjNunV4vLgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTt1ZigncicsIDE0OTQxNDE4OCwgMTUZH_D9kgK5AiFLVHozeXdpR2tfOFBFS3pDbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjhNd0NrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBU093U01lWmJ1SV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjMU0tQURvUmlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWkVscVFVCRNEQUR3UHcuLpoCiQEhdGc2ODZnNj0BJG5QRmJJQVFvQUQVSFRxUURvSlUwbE9Nem8wTnpVelFLRVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkMyHQDwlUFTVF9NT0RJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKy5BLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUz2gQCCAHgBADwBGGFIIgFAZgFAKAF_xEBFAHABQDJBWm2FPA_0gUJCQkMeAAA2AUB4AUB8AXyjAH6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=0707b1385afa81517cd338f1516aeccc46fe33e1" + } + } + } + ] + }, + { + "uuid": "245a09bd675168", + "tag_id": 15394006, + "auction_id": "1273216786519070425", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "245a09bd675168", + "tag_id": 15394006, + "auction_id": "1769115862397582681", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QKUCKAUBAAAAwDWAAUBCKD4kfAFENn63YWPsMrGGBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIXp6djFzd2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOE13Q2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFZbW5MamdJaXVRXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTS1BRG9SaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJaRWxxUVUJE0RBRHdQdy4umgKJASFGdzkxRFE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV6UUtFWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9AUBZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagErLkEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTPaBAIIAOAEAPAExOefR4gFAZgFAKAF____________AcAFAMkFAGVbFPA_0gUJCQULeAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYBIDAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=fb3a15e7ff747fccd750671b763e312d97083c72", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQkgfAReAAAAABFZfbfwgCmNGBkgfAReAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICLS1oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=7f4b8dd7c7dd9faecebac2e9ec6d7ef8da08da16&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QLwCOhwBAAAAwDWAAUBCKD4kfAFENn63YWPsMrGGBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4vLgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiF6enYxc3dpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjhNd0NrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWW1uTGpnSWl1UV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU0tQURvUmlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWkVscVFVCRNEQUR3UHcuLpoCiQEhRnc5MURRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVelFLRVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkMyHQDwsEFTVF9NT0RJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKy5BLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUz2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBWm2FPA_0gUJCQkMdAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgkkKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=3a27c12c33ebaaae43dbce1cafb0bae43b753fa0" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/description.md b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/description.md new file mode 100644 index 00000000000..45ae30a7a41 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/description.md @@ -0,0 +1,43 @@ +Test Page - 'integrationExamples/longform/basic_w_custom_adserver_translation.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_custom_adserver_translation.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: true + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + }, + brandCategoryTranslation: { + translationFile: 'custom_adserver_translation.json' + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/request.json b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/request.json new file mode 100644 index 00000000000..e7497ac78f3 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/request.json @@ -0,0 +1,402 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/response.json b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/response.json new file mode 100644 index 00000000000..b4d8483a539 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/response.json @@ -0,0 +1,294 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "7360998998672342781", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCN73l_AFEP39-97ssuGTZhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIVNqMmZTQWlua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaQmtTcHl1c2Q4XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFOZzhKRnc2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfC2Lmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAE0uyfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAZXZw2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYFIiwA8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=c92cbcde5c8bf8e053f86493dd4c4698da0392de", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQne-wVeAAAAABH9_t7LloUnZhne-wVeAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=8e35c1264cd1b4f1d89f929c3a4a334cf6a68eca&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-COh-BAAAAwDWAAUBCN73l_AFEP39-97ssuGTZhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV40rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFTajJmU0FpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnV1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWkJrU3B5dXNkOF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhTmc4SkZ3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBJLGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBNLsn0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=ca640dffaea7bfcf2b0f2e11d8877821189b74bb" + } + } + } + ] + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "1919339751435064934", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCN73l_AFEOasy7zbqrfRGhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIU1EMUZJQWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFRclZ0ZGpIUGVBXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASE1QTdmLVE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfC2Lmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAZXZw2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYFIiwA8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=c3130de64bc0b8df258e603dfb96f78550ab0c3c", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQne-wVeAAAAABFm1pK3Vd2iGhne-wVeAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=2c3cee10303d9b93531bed443c0781d905270598&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-COh-BAAAAwDWAAUBCN73l_AFEOasy7zbqrfRGhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV40rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFNRDFGSUFpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnV1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBUXJWdGRqSFBlQV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhNUE3Zi1RNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBJLGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBIvhn0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx4AADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=996a3937245f03e5eefb0cb69917d2d8d7f60424" + } + } + } + ] + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "3257875652791896280", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "5756905673624319729", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "4205438746002589111", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "204849530930208960", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "3482944224379652843", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "2123689132466331410", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "6150444453316813936", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "2810956382376737966", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "7164199537578897638", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKhCKAhBAAAAwDWAAUBCN73l_AFEObhocvZsJa2Yxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIXNENXVfQWlta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYSEZfdmZOei1NXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFDd19DQnc2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfC2Lmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAZXZs2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgUhLADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=2b9ed1e2e7f27fea52cbdc64cb700195bbd14d75", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQne-wVeAAAAABHmcGiZhVlsYxne-wVeAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICLS1oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=8ba7f141449cb45f8b6e12361a62d8d68aa9c812&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL9COh9BAAAAwDWAAUBCN73l_AFEObhocvZsJa2Yxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV40rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFzRDV1X0FpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnV1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWEhGX3ZmTnotTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhQ3dfQ0J3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBJLGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBK_ln0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx0AADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSQo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=527640949733fba32740156d743d421eb1fe2863" + } + } + } + ] + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "8404712946290777461", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCN73l_AFEPW6p5bQvOLRdBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIWp6MkdiZ2lta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaQ0RhTlBDYk9NXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0BBRHdQdy4umgKJASFOUS0yRjo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56TXpRSzRZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwZWVBQS7YAgDgAq2YSOoCYGh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19jdXN0b21fYWRzZXJ2ZXJfdHJhbnNsYQE18LYuaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qASSxgSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggA4AQA8ATf359HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABldnDYBQHgBQHwBay8FPoFBAgAEACQBgGYBgC4BgDBBgUiLADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=ed84428f432d6e743bcad6f7862aed957bece82b", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQne-wVeAAAAABF13ckC5YmjdBne-wVeAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=7024b063fcacac27e184ed097ad5878c4dd4dc1d&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-COh-BAAAAwDWAAUBCN73l_AFEPW6p5bQvOLRdBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV40rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiFqejJHYmdpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnV1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWkNEYU5QQ2JPTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNAQUR3UHcuLpoCiQEhTlEtMkY6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNXwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7wn0lGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAeAEAPAE39-fR4gFAZgFAKAF______8BBRQBwAUAyQVpwxTwP9IFCQkJDHgAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGCSUo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=aefe9625d8e866e048a156abdf26d7c626e6a398" + } + } + } + ] + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "4063389973481762703", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCN73l_AFEI_fjorv9IOyOBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIV96eHRIQWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFSVExWM2x4c2VJXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFEZy1VQ1E2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfC2Lmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAExd2fR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAZXZw2AUB4AUB8AXC8hf6BQQIABAAkAYBmAYAuAYAwQYFIiwA8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=2fb33b5204f9b75c58d89487725a9d55139f9ff4", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQne-wVeAAAAABGPr0Pxpg9kOBne-wVeAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=f9ec8d0b81c1cf4eefc58a7990f4a0a78440725f&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-CKB-BAAAAwDWAAUBCN73l_AFEI_fjorv9IOyOBiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXjSuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc0NTA0NjIpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIV96eHRIQWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFSVExWM2x4c2VJXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFEZy1VQ1E2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNXwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7wn0lGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAeAEAPAExd2fR4gFAZgFAKAF______8BBRQBwAUAyQVpwxTwP9IFCQkJDHgAANgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGCSUo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=6b79542e3cee0319d8cb83d1daf127c3aeea9b28" + } + } + } + ] + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "5097385192927446024", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "2612757136292876686", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/description.md b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/description.md new file mode 100644 index 00000000000..45ae30a7a41 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/description.md @@ -0,0 +1,43 @@ +Test Page - 'integrationExamples/longform/basic_w_custom_adserver_translation.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_custom_adserver_translation.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: true + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + }, + brandCategoryTranslation: { + translationFile: 'custom_adserver_translation.json' + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/request.json b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/request.json new file mode 100644 index 00000000000..f4cea46918f --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/request.json @@ -0,0 +1,142 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/response.json b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/response.json new file mode 100644 index 00000000000..6a81de25ebe --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/response.json @@ -0,0 +1,188 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "285a2f41615348", + "tag_id": 15394006, + "auction_id": "2837696487158070058", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCNSDmPAFEKr2uMu5veGwJxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIV9EemhKUWlta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCN3VZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFTbnRDdFVIdU9BXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TmVBRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmOGtxUVUJE0RBRHdQdy4umgKJASFOdzh1Rnc2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek0xUUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfDtLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEq8YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzXaBAIIAOAEAPAE39-fR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBay8FPoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPC_0Ab1L9oGFgoQAAAAAAU3DQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=3414eb9e83df14945d2dbfb00e17fb3f2bad2e33", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnUAQZeAAAAABEqO26Z64VhJxnUAQZeAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=e5a720a9884e1df845be9c33658ab69f4c56981e&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-COh-BAAAAwDWAAUBCNSDmPAFEKr2uMu5veGwJxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiFfRHpoSlFpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjd1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBU250Q3RVSHVPQV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek5lQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjhrcVFVCRNEQUR3UHcuLpoCiQEhTnc4dUZ3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNMVFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKvGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM12gQCCAHgBADwBN_fn0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx4AADYBQHgBQHwBay8FPoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=99418325b8f5ec79e22c1a9aedd73f03de616c2d" + } + } + } + ] + }, + { + "uuid": "285a2f41615348", + "tag_id": 15394006, + "auction_id": "8688113570839045503", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKhCKAhBAAAAwDWAAUBCNSDmPAFEP_K8rCtqJjJeBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIUN6d3Rud2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCN3VZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFWUzRZeVVvR09JXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TmVBRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmOGtxUVUJE0RBRHdQdy4umgKJASFKQTlsRUE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek0xUUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfDXLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEq8YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzXaBAIIAOAEAPAExOefR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBZk9-gUECAAQAJAGAZgGALgGAMEGBSEsAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=2e7c9d18300402e2e183667711728f7743b70a2b", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQnUAQZeAAAAABF_pRzWQmGSeBnUAQZeAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICLS1oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=febf12010c66ac7247f571f03c33175ca9036b32&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL9COh9BAAAAwDWAAUBCNSDmPAFEP_K8rCtqJjJeBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFDend0bndpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjd1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVlM0WXlVb0dPSV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek5lQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjhrcVFVCRNEQUR3UHcuLpoCiQEhSkE5bEVBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNMVFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKvGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM12gQCCAHgBADwBMTnn0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx0AADYBQHgBQHwBZk9-gUECAAQAJAGAZgGALgGAMEGCSQo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=92aa9e9c89384c435ab9c7fa62b963d8fc087ef7" + } + } + } + ] + }, + { + "uuid": "285a2f41615348", + "tag_id": 15394006, + "auction_id": "4162295099171231907", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKhCKAhBAAAAwDWAAUBCNSDmPAFEKOxzaPwqtzhORiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIWREMGtXZ2lta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCN3VZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhSFRjUzNjWS1VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TmVBRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmOGtxUVUJE0RBRHdQdy4umgKJASFEUTg2Q0E2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek0xUUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfDXLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEq8YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzXaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGBSEsAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=95047e919846faea401c778106fb33dae0c95b02", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQnUAQZeAAAAABGjWHMEV3HDORnUAQZeAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICLS1oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=50350aadc603f4bb6c59888515d60e9182da0eb8&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL9COh9BAAAAwDWAAUBCNSDmPAFEKOxzaPwqtzhORiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFkRDBrV2dpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjd1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYUhUY1MzY1ktVV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek5lQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjhrcVFVCRNEQUR3UHcuLpoCiQEhRFE4NkNBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNMVFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKvGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM12gQCCAHgBADwBK_ln0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx0AADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSQo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=82c42e6aa09e7c842254552ae524791fa3693bbb" + } + } + } + ] + }, + { + "uuid": "285a2f41615348", + "tag_id": 15394006, + "auction_id": "1076114531988487576", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCNSDmPAFEJj7vIbyjsj3Dhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIVRqMWVUZ2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCN3VZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFZOUNHX2M3MHRvXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TmVBRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmOGtxUVUJE0BBRHdQdy4umgKJASFFQThNQzo9ASRuUEZiSUFRb0FEFUhUa1FEb0pVMGxPTXpvME56TTFRSzRZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwZWVBQS7YAgDgAq2YSOoCYGh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19jdXN0b21fYWRzZXJ2ZXJfdHJhbnNsYQE18O0uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qASrxgSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggA4AQA8ATF3Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAAAABTcNAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=c49afba7ca4b5193f7da37b17e1fbfbee2328f61", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnUAQZeAAAAABGYPc8gdyDvDhnUAQZeAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=47618eb9096567900e84fd1c6aff09d753b2fe91&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-CKB-BAAAAwDWAAUBCNSDmPAFEJj7vIbyjsj3Dhiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXjWuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc0NTE5ODgpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIVRqMWVUZ2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCN3VZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFZOUNHX2M3MHRvXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TmVBRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmOGtxUVUJE0BBRHdQdy4umgKJASFFQThNQzo9ASRuUEZiSUFRb0FEFUhUa1FEb0pVMGxPTXpvME56TTFRSzRZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwZWVBQS7YAgDgAq2YSOoCYGh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19jdXN0b21fYWRzZXJ2ZXJfdHJhbnNsYQE1fC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvCfSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qASrxgSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggB4AQA8ATF3Z9HiAUBmAUAoAX______wEFFAHABQDJBWnDFPA_0gUJCQkMeAAA2AUB4AUB8AXC8hf6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=72d1ec3db5baaa29c1b0e5f07c012db606675fe5" + } + } + } + ] + }, + { + "uuid": "285a2f41615348", + "tag_id": 15394006, + "auction_id": "7495588537924508785", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_1/description.md b/test/fake-server/fixtures/longform/longform_priceGran_1/description.md new file mode 100644 index 00000000000..8bc4d242f46 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_1/description.md @@ -0,0 +1,62 @@ +Test Page - 'integrationExamples/longform/basic_w_priceGran.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_priceGran.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +const customConfigObject = { + 'buckets': [{ + 'precision': 2, // default is 2 if omitted - means 2.1234 rounded to 2 decimal places = 2.12 + 'min': 0, + 'max': 5, + 'increment': 0.01 // from $0 to $5, 1-cent increments + }, + { + 'precision': 2, + 'min': 5, + 'max': 8, + 'increment': 0.05 // from $5 to $8, round down to the previous 5-cent increment + }, + { + 'precision': 2, + 'min': 8, + 'max': 40, + 'increment': 0.5 // from $8 to $40, round down to the previous 50-cent increment + }] +}; + +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + }, + priceGranularity: customConfigObject +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_1/request.json b/test/fake-server/fixtures/longform/longform_priceGran_1/request.json new file mode 100644 index 00000000000..aba76398093 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_1/request.json @@ -0,0 +1,387 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_1/response.json b/test/fake-server/fixtures/longform/longform_priceGran_1/response.json new file mode 100644 index 00000000000..4665aa4ef9c --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_1/response.json @@ -0,0 +1,366 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "1249897353793397796", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEKTIuZTW4KGsERiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCITFqdjBlZ2lta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFXU1JOVU1OTk9jXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFTUTgtR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAE39-fR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkdADYBQHgBQHwBay8FPoFBAgAEACQBgGYBgC4BgDBBgkkKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=e9887c670ae9fcb7eb2a0253037c64c3587f4bcb", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnKwgleAAAAABEkZI5iBYdYERnJwgleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=68a5c49da3a6ecf3dfc0835cb3da72b3b2c7b080&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEKTIuZTW4KGsERiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiExanYwZWdpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBV1NSTlVNTk5PY18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhU1E4LUd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMeAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=9514ae5f8aae1ee9dddd24dce3e812ae76e0e783" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "4278372095219023172", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEMT65MOLmPWvOxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIUxEeUhqUWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaQWJScDluWS1FXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASEtQTVuX2c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkdADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgkkKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=987d4bb0c7611d41b5974ec412469da2241084cd", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnKwgleAAAAABFEPXm4wNRfOxnJwgleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=75aaa9ec84807690ceff60e39fbba6625240f9f3&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEMT65MOLmPWvOxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFMRHlIalFpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWkFiUnA5blktRV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhLUE1bl9nNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMeAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=9872a378866ce61fc366ca8c34bdd9302fa41a9b" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "8860024420878272196", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKRCKARBAAAAwDWAAUBCMmFp_AFEMSN8Z3LqMj6ehiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIU9EMjhLZ2lta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFkZExBS3hfN09nXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFIdzlLREE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkcADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSMo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=1289862cbe265fd9af13d2aab9635e3232421ec1", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQnKwgleAAAAABHERryzRCH1ehnJwgleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=0b094204d5c18803149e081bd2bc0077d25ebb14&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLtCOhtBAAAAwDWAAUBCMmFp_AFEMSN8Z3LqMj6ehiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFPRDI4S2dpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZGRMQUt4XzdPZ18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhSHc5S0RBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMdAAA2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgkkKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=f35771975371bb250fd6701914534b4f595fcf68" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "5236733650551797458", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKRCKARBAAAAwDWAAUBCMmFp_AFENLt5YOosKfWSBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIThUMjJsZ2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFkczByb2Ytbk9VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFOZzkxRkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAExOefR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkcADYBQHgBQHwBZk9-gUECAAQAJAGAZgGALgGAMEGCSMo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=e997907677e4e2f9b641d51b522a901b85944899", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQnKwgleAAAAABHSdnmAgp2sSBnJwgleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=d70eef0df40cece50465a13d05a2dc11b65eadeb&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLtCOhtBAAAAwDWAAUBCMmFp_AFENLt5YOosKfWSBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiE4VDIybGdpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZHMwcm9mLW5PVV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhTmc5MUZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_DtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAGn1FQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=e8b6716ad3d2fcbdb79976f72d60f8e90ce8f5a6" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "4987762881548953446", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "201567478388503336", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEKjm-NzbkYfmAhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIXV6NlFDd2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFkejE5MUdLNk8wXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0BBRHdQdy4umgKJASFTZy1SRzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56TXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0DgFlQUEu2AIA4AKtmEjqAk5odHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcHJpY2VHcmFuLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qASv5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggA4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAaWR0ANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=4a887316a3197dfae07c1443a4debc62a2f17fef", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnKwgleAAAAABEoM567jRzMAhnJwgleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=eef6278d136f8df4879846840f97933e9d67388a&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEKjm-NzbkYfmAhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiF1ejZRQ3dpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZHoxOTFHSzZPMF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNAQUR3UHcuLpoCiQEhU2ctUkc6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8JplQUEu2AIA4AKtmEjqAk5odHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcHJpY2VHcmFuLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkNVU1RPTREdCEFTVAEL8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAeAEAPAEYYIgiAUBmAUAoAX_EQEUAcAFAMkFabMU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=e68b089e4fc94aa7566784ccbff299e50c8bc090" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "3876520534914199302", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "4833995299234629234", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "8352235304492782614", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEJaok6aeuMb0cxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE0MTg4Nh8A8P2SArkCIUpUMS1FZ2lHa184UEVLekNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFmQ1lIN1I1bmVzXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASExUTY4OFE2PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAErMKfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkdADYBQHgBQHwBfKMAfoFBAgAEACQBgGYBgC4BgDBBgkkKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=7081f4ad4ae9837aaff4b4f59abc4ce7f8b02cb6", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnKwgleAAAAABEW1MTkwRnpcxnJwgleAAAAACCswp9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jyjAFiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAazCn0ewAQE.&s=71f281c81d1ae269bde275b84aa955c833ab1dea&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149414188, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 32, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 29000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEJaok6aeuMb0cxiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQrMKfR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxNDE4OCwgMTUZH_D9kgK5AiFKVDEtRWdpR2tfOFBFS3pDbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBZkNZSDdSNW5lc18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhMVE2ODhRNj0BJG5QRmJJQVFvQUQVSFRxUURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMeAAA2AUB4AUB8AXyjAH6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=05fc37623521011853ff69d194aa6d692b6c0504" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "2318891724556922037", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "5654583906891472332", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEMy7oJeqw8e8Thiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIXZ6Ml9mZ2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFhYzY5MFRlZi1rXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0BBRHdQdy4umgKJASFJZzhjRDo9ASRuUEZiSUFRb0FEFUhUa1FEb0pVMGxPTXpvME56TXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0DgFlQUEu2AIA4AKtmEjqAk5odHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcHJpY2VHcmFuLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qASv5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggA4AQA8ATF3Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAaWR0ANgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=f929565158c7caa5b85e88fa456cdd04d0e4b6d8", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnKwgleAAAAABHMHeiiGh55ThnJwgleAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=a93773067b8588465b9c007e19970bd9e08c1b6c&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCKBuBAAAAwDWAAUBCMmFp_AFEMy7oJeqw8e8Thiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXjDuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc2OTc5OTMpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIXZ6Ml9mZ2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFhYzY5MFRlZi1rXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0BBRHdQdy4umgKJASFJZzhjRDo9ASRuUEZiSUFRb0FEFUhUa1FEb0pVMGxPTXpvME56TXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwmmVBQS7YAgDgAq2YSOoCTmh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19wcmljZUdyYW4uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTV9NT0RFTF9MRUFGX05BTUUSAPICHgoaQ1VTVE9NER0IQVNUAQvwkElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qASv5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggB4AQA8ARhgiCIBQGYBQCgBf8RARQBwAUAyQVpsxTwP9IFCQkJDHgAANgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGCSUo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=a3a24cbf148bb959f539e883af3d118f64e81bc9" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "2268711976967571175", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "8379392370800588084", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "6225030428438795793", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "1592368529919250324", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_2/description.md b/test/fake-server/fixtures/longform/longform_priceGran_2/description.md new file mode 100644 index 00000000000..8bc4d242f46 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_2/description.md @@ -0,0 +1,62 @@ +Test Page - 'integrationExamples/longform/basic_w_priceGran.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_priceGran.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +const customConfigObject = { + 'buckets': [{ + 'precision': 2, // default is 2 if omitted - means 2.1234 rounded to 2 decimal places = 2.12 + 'min': 0, + 'max': 5, + 'increment': 0.01 // from $0 to $5, 1-cent increments + }, + { + 'precision': 2, + 'min': 5, + 'max': 8, + 'increment': 0.05 // from $5 to $8, round down to the previous 5-cent increment + }, + { + 'precision': 2, + 'min': 8, + 'max': 40, + 'increment': 0.5 // from $8 to $40, round down to the previous 50-cent increment + }] +}; + +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + }, + priceGranularity: customConfigObject +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_2/request.json b/test/fake-server/fixtures/longform/longform_priceGran_2/request.json new file mode 100644 index 00000000000..f2f20700ffe --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_2/request.json @@ -0,0 +1,137 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_2/response.json b/test/fake-server/fixtures/longform/longform_priceGran_2/response.json new file mode 100644 index 00000000000..ee7494ea665 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_2/response.json @@ -0,0 +1,188 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "6123799897847039642", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKRCKARBAAAAwDWAAUBCMmFp_AFEJqN_JX98Yb-VBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIUN6dzV3Z2lta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYQm5aNWdRbi1NXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASFJQS1IREE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkcADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSMo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=a7e4ff14c60153db90971365f90e514f45875324", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQnJwgleAAAAABGaBr_Sjxv8VBnJwgleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=842283d9de78fba7e92fac09f95bb63902a0b54a&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLtCOhtBAAAAwDWAAUBCMmFp_AFEJqN_JX98Yb-VBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4zrgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFDenc1d2dpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWEJuWjVnUW4tTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhSUEtSERBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMdAAA2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgkkKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=0fb74d544be103e1440c3ee8f7abc14d2c322d15" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "889501690217653627", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEPvKoYSxoomsDBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIWt6eTlHUWlua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFRSzgzNzR1VnVVXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASFTd19PR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAOAEAPAE0uyfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkdADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgkkKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=78ac70aeeae1da43c90efd248fb30a4ee630ffd5", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnJwgleAAAAABF7ZYgQEyVYDBnJwgleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=f21e2a522ddcaf0a67bc7d52f70288fdf7e6f3dd&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEPvKoYSxoomsDBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4zrgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFrenk5R1FpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBUUs4Mzc0dVZ1VV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhU3dfT0d3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMeAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=69611db1024ddb77e0754087ddbeae68a00633a1" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "2793012314322059080", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEMj-1IPuvLHhJhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE0MTg4Nh8A8P2SArkCIXhqb2ZBZ2lHa184UEVLekNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFRQWhlSGt0VHVRXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASExZzc1OFE2PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAOAEAPAErMKfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkdADYBQHgBQHwBfKMAfoFBAgAEACQBgGYBgC4BgDBBgkkKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=243f58d85b09468de2fe485662c950a86b5d90fb", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnJwgleAAAAABFIP3Xg5sXCJhnJwgleAAAAACCswp9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jyjAFiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAazCn0ewAQE.&s=99dd40ab6ae736c6aa7c96b5319e1723ea581e0d&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149414188, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 32, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 29000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEMj-1IPuvLHhJhiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQrMKfR1ic8VtgAGjNunV4zrgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxNDE4OCwgMTUZH_D9kgK5AiF4am9mQWdpR2tfOFBFS3pDbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBUUFoZUhrdFR1UV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhMWc3NThRNj0BJG5QRmJJQVFvQUQVSFRxUURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMeAAA2AUB4AUB8AXyjAH6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=d9a3c817696f263b6e6d81f7251827fa54a47c37" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "45194178065897765", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "3805126675549039795", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFELPZ2uvQ0aHnNBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIWNUM1hkZ2lua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFjbUQzMExTME9VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0BBRHdQdy4umgKJASEtUTZrXzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56UXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0DgFlQUEu2AIA4AKtmEjqAk5odHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcHJpY2VHcmFuLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qASv5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0M9oEAggA4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAaWR0ANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=bbeaa584bea9afedf6dcab51b1616988441dfa22", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnJwgleAAAAABGzrHYNjYbONBnJwgleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=b7e937b5acc3d8b910f6b08c3a40e04aa10818cd&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFELPZ2uvQ0aHnNBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4zrgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFjVDNYZGdpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBY21EMzBMUzBPVV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNAQUR3UHcuLpoCiQEhLVE2a186PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8JplQUEu2AIA4AKtmEjqAk5odHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcHJpY2VHcmFuLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkNVU1RPTREdCEFTVAEL8N5JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAeAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgAAYeYo8D_QBvUv2gYWChABDy4BAFAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=279827127eba3204bc3a152b8abaf701260eb494" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_1/description.md b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/description.md new file mode 100644 index 00000000000..8fe815912e8 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_w_requireExactDuration.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_requireExactDuration.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: true + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_1/request.json b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/request.json new file mode 100644 index 00000000000..1e036c367c6 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/request.json @@ -0,0 +1,401 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_1/response.json b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/response.json new file mode 100644 index 00000000000..b91a5a3d523 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/response.json @@ -0,0 +1,330 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "4424969993715088689", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFELH6mcm82Km0PRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIWhUNEwzZ2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFjek5XT196NC1VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFTZy1SR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCADgBADwBNLsn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=3d8c006f4f85ecffd49c500554c3852b9079ff2b", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABExfSbJw6ZoPRlNxwleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=e2c6cedf67a96613ea8851673ebcfdd25a19435c&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCM2Op_AFELH6mcm82Km0PRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4lbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFoVDRMM2dpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBY3pOV09fejQtVV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhU2ctUkd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBeZUFBLtgCAOACrZhI6gJZaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3JlcXVpcmVFeGFjdER1cmEBLnwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7wkElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATC5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggB4AQA8ARhjSCIBQGYBQCgBf8RARQBwAUAyQVpvhTwP9IFCQkJDHgAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGCSUo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=de23f822f483b6e85615d4297d872262310c240d" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "2013100091803497646", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "2659371493620557151", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFEN_KtpiJif_zJBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIWR6eUJxQWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFWSHZpWGF0Q09zXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASEtQTVuX2c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCADgBADwBIvhn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx4AADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgklKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=eafba287adec58427d1679f43a84ebb19223c4e7", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABFfpQ2TSPznJBlNxwleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=b335b2c79378c1699d54cf9ffe097958bd989a0b&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCM2Op_AFEN_KtpiJif_zJBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4lbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFkenlCcUFpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVkh2aVhhdENPc18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhLUE1bl9nNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBeZUFBLtgCAOACrZhI6gJZaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3JlcXVpcmVFeGFjdER1cmEBLnwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7wkElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATC5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggB4AQA8ARhjSCIBQGYBQCgBf8RARQBwAUAyQVpvhTwP9IFCQkJDHgAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGCSUo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=66b9e769da1e1d68b202605fc178fc172046e9c5" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "5424637592449788792", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "3470330348822422583", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "4415549097692431196", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "1628359298176905427", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "1949183409076770477", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "4707958683377993236", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "2499032734231846767", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "1295788165766409083", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKcCKAcBAAAAwDWAAUBCM2Op_AFEPvWpeWKj-T9ERiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCITR6eVM5d2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFlS0tONGIwQS00XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFOZzkxRkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCADgBADwBMTnn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx0AADYBQHgBQHwBZk9-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=3cb170cdf53cd6a6bfec0676659daeb6170895e3", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQlNxwleAAAAABF7a6mseJD7ERlNxwleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=45f5cce314725120ec769afaacbb7aa92d32e674&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL4COh4BAAAAwDWAAUBCM2Op_AFEPvWpeWKj-T9ERiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4lbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiE0enlTOXdpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZUtLTjRiMEEtNF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhTmc5MUZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBeZUFBLtgCAOACrZhI6gJZaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3JlcXVpcmVFeGFjdER1cmEBLnwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7w7UlGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATC5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggB4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwP9AG9S_aBhYKEACJABUBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=5c9f03b9c5c6cc2bf070d8cdc6c9af4b06595879" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "702761892273189154", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKcCKAcBAAAAwDWAAUBCM2Op_AFEKLi_7T7xq3gCRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE4NDg2Nh8A8P2SArkCITdUeVNDd2lva184UEVQYmpuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFHSTh5N21BQUFzUU1FQmlQTXU1Z0FBTEVESkFYQTM4QzJIcnVFXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHFKUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFaQThESlE2PQEkblBGYklBUW9BRBVIVHNRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCADgBADwBPbjn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx0AADYBQHgBQHwBf0F-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=f459a78a1b20c9643b90d7491f22593d79cff253", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQlNxwleAAAAABEi8Z-2N7bACRlNxwleAAAAACD2459HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1j9BWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgB9uOfR7ABAQ..&s=83289d261bced5258930a1ce2464260a96565241&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418486, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 14.00001, + "cpm_publisher_currency": 14.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL4COh4BAAAAwDWAAUBCM2Op_AFEKLi_7T7xq3gCRiq5MnUovf28WEqNgmOWItPAQAsQBGOWItPAQAsQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ9uOfR1ic8VtgAGjNunV4lbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxODQ4NiwgMTUZH_D9kgK5AiE3VHlTQ3dpb2tfOFBFUGJqbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRR0k4eTdtQUFBc1FNRUJpUE11NWdBQUxFREpBWEEzOEMySHJ1RV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RxSlBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhWkE4REpRNj0BJG5QRmJJQVFvQUQVSFRzUURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBeZUFBLtgCAOACrZhI6gJZaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3JlcXVpcmVFeGFjdER1cmEBLnwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7w7UlGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATC5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggB4AQA8AT2459HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF_QX6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwP9AG9S_aBhYKEACJABUBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=16a432c0a05db78fa40fefc7967796ff2a2e8444" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "8192047453391406704", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFEPCMp9SW-P_XcRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIXhUdGdYZ2lHa184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFSR0FWSjZORXVNXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0BBRHdQdy4umgKJASFKUThlRDo9ASRuUEZiSUFRb0FEFUhUcVFEb0pVMGxPTXpvME56TXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwXmVBQS7YAgDgAq2YSOoCWWh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19yZXF1aXJlRXhhY3REdXJhAS7wny5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEwuYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAE39-fR4gFAZgFAKAF______8BBRQBwAUAyQVpYhTwP9IFCQkJDHgAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGCSUo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=8bf90e0756a9265ab6ac029e883e14803447a7fb", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABFwxolqwf-vcRlNxwleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=cf9ea0df7655a5c6150a527399cb2852c61ec14a&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCM2Op_AFEPCMp9SW-P_XcRiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4lbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiF4VHRnWGdpR2tfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBUkdBVko2TkV1TV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNAQUR3UHcuLpoCiQEhSlE4ZUQ6PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEufC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBGGNIIgFAZgFAKAF_xEBFAHABQDJBWm-FPA_0gUJCQkMeAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=cefb5f476892ed335cd8b0fc20fabf7650b1d2e3" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "9041697983972949142", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFEJb5yqiVjaS9fRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIURUMkpEd2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFYeHdUOEhkUmVzXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFJZzhjRGc2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCADgBADwBMXdn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx4AADYBQHgBQHwBcLyF_oFBAgAEACQBgGYBgC4BgDBBgklKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=308ea3c3363b379ef62dbb6c7a91d1d91d9ee47a", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABGWvBJVaZB6fRlNxwleAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=70a33aa1a57d812d9da5c321e898197836ed16f8&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5CKB5BAAAAwDWAAUBCM2Op_AFEJb5yqiVjaS9fRiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXiVuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc2OTkxNDkpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIURUMkpEd2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFYeHdUOEhkUmVzXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFJZzhjRGc2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEufC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvDeSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBMXdn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXC8hf6BQQIABAAkAYBmAYAuAYAwQYAAGHxKPA_0Ab1L9oGFgoQAQ8uAQBQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=ee15793b41a9d22ffad9bd46878a47821d6044fa" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "356000177781223639", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_2/description.md b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/description.md new file mode 100644 index 00000000000..8fe815912e8 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_w_requireExactDuration.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_requireExactDuration.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: true + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_2/request.json b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/request.json new file mode 100644 index 00000000000..83877ff9ac0 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/request.json @@ -0,0 +1,141 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_2/response.json b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/response.json new file mode 100644 index 00000000000..e776170328e --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/response.json @@ -0,0 +1,188 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "198494455120718841", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKcCKAcBAAAAwDWAAUBCM2Op_AFEPnX6_r7tMzgAhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIXpUMDRwQWlta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhejg2NVNoMGVJXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZc2xxUVUJE0RBRHdQdy4umgKJASFKQTkzRFE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelEzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ32gQCCADgBADwBK_ln0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx0AADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=645b6e0a37eb3a315bc3208365bd4fc03e1ecd18", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQlNxwleAAAAABH561q_pzHBAhlNxwleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=35a21bf0bef1ca2c138e37a2e025ad523b5a1db2&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL4COh4BAAAAwDWAAUBCM2Op_AFEPnX6_r7tMzgAhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4xbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiF6VDA0cEFpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYXo4NjVTaDBlSV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME4tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWXNscVFVCRNEQUR3UHcuLpoCiQEhSkE5M0RRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRM1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBeZUFBLtgCAOACrZhI6gJZaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3JlcXVpcmVFeGFjdER1cmEBLnwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7wkElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATC5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0N9oEAggB4AQA8ARhjSCIBQGYBQCgBf8RARQBwAUAyQVpvhTwP9IFCQkJDHQAANgFAeAFAfAF4Fj6BQQIABAAkAYBmAYAuAYAwQYJJCjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=cf3130989b2b4fe5271240d65055b85d1192b78a" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "998265386177420565", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFEJW6sbXGoqPtDRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIVdqM1Jid2lHa184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFmcXpCNjduMU9rXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGMwTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZc2xxUVUJE0BBRHdQdy4umgKJASFLZzlMRDo9ASRuUEZiSUFRb0FEFUhUcVFEb0pVMGxPTXpvME56UTNRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwXmVBQS7YAgDgAq2YSOoCWWh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19yZXF1aXJlRXhhY3REdXJhAS7wny5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEwuYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDfaBAIIAOAEAPAE39-fR4gFAZgFAKAF______8BBRQBwAUAyQVpYhTwP9IFCQkJDHgAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGCSUo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=33f01ddfb15bc84d7bf134a168aeb9d9de76fa57", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABEVXaxmFI3aDRlNxwleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=023640de7c18a0d0e80b2456144b89a351455cda&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCM2Op_AFEJW6sbXGoqPtDRiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4xbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiFXajNSYndpR2tfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBZnF6QjY3bjFPa18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjME4tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWXNscVFVCRNAQUR3UHcuLpoCiQEhS2c5TEQ6PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOelEzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEufC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ32gQCCAHgBADwBGGNIIgFAZgFAKAF_xEBFAHABQDJBWm-FPA_0gUJCQkMeAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=515ab42a7fdcad8fcf34e4fb98b1e076a75006a9" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "8884527464400177295", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKcCKAcBAAAAwDWAAUBCM2Op_AFEI-RmcaB1Yumexiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCITVqcmtHUWlta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYb0paejlaR09NXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZc2xxUVUJE0BBRHdQdy4umgKJASFPdy1pRjo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56UTNRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwXmVBQS7YAgDgAq2YSOoCWWh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19yZXF1aXJlRXhhY3REdXJhAS7wny5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEwuYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDfaBAIIAOAEAPAExOefR4gFAZgFAKAF______8BBRQBwAUAyQVpYhTwP9IFCQkJDHQAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYJJCjwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=dc7d874e52ac39980ec1070a7769632be56a2f00", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQlNxwleAAAAABGPSMYYqC5MexlNxwleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=9fd739e9f0a6054296f9bb5168c49a89a425795c&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL4COh4BAAAAwDWAAUBCM2Op_AFEI-RmcaB1Yumexiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4xbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiE1anJrR1FpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWG9KWno5WkdPTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME4tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWXNscVFVCRNAQUR3UHcuLpoCiQEhT3ctaUY6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelEzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEufC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvDtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ32gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAIkAFQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=1f8ea8f07f781fe149beb0d65dd25ad725a12f3b" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "1279521442385130931", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFELPr8f6Pv_HgERiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIW9EeDJEQWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFkb01fcFZkVGVVXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMwTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZc2xxUVUJE0RBRHdQdy4umgKJASFKdzlKRHc2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOelEzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ32gQCCADgBADwBMXdn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx4AADYBQHgBQHwBcLyF_oFBAgAEACQBgGYBgC4BgDBBgklKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=4b14660ae659b3d301ec6c40f0f096bb88db145b", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABGzddz_-MXBERlNxwleAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=5f277bcab624f05c9d3a3a9c111961f3f33ccca2&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5CKB5BAAAAwDWAAUBCM2Op_AFELPr8f6Pv_HgERiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXjFuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc2OTkxNDkpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIW9EeDJEQWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFkb01fcFZkVGVVXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMwTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZc2xxUVUJE0RBRHdQdy4umgKJASFKdzlKRHc2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOelEzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEufC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvDeSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ32gQCCAHgBADwBMXdn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXC8hf6BQQIABAAkAYBmAYAuAYAwQYAAGHxKPA_0Ab1L9oGFgoQAQ8uAQBQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=7bb7b75e4769a1260eaed2c79752ee542b4d28ce" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "7664937561033023835", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/description.md b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/description.md new file mode 100644 index 00000000000..159ebbcc30b --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_wo_brandCategoryExclusion.html' +Test Spec File - 'test/spec/e2e/longform/basic_wo_brandCategoryExclusion.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: false + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/request.json b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/request.json new file mode 100644 index 00000000000..2d1fa3f16bf --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/request.json @@ -0,0 +1,386 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/response.json b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/response.json new file mode 100644 index 00000000000..bfef650e07a --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/response.json @@ -0,0 +1,654 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "6316075342634007031", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEPfztqL2oc3TVxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIV96eWNLZ2lua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFZYkYwSW1fZGU0XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0BBRHdQdy4umgKJASE5dzR0Xzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56VXdRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCADgBADwBIvhn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAaakRAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=bb81a081c756fd493253bf765c06ff46888f009a", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABH3uU1kDzWnVxk3yQleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=a3da30186f69a5ce2edcfc14fa3a31b92ee70060&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEPfztqL2oc3TVxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFfenljS2dpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWWJGMEltX2RlNF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNAQUR3UHcuLpoCiQEhOXc0dF86PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTDaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEUAcAFAMkFacEU8D_SBQkJCQx4AADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=62b9db151b3739399e0970c74fafc4bb61486510" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "8259815099516488747", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFEKuY2qihwrDQchiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIW1UeUFCd2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYNml4eGFGdE8wXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFOUTg3RkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAAGmpDQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=8a55db8e788616ef057647b49c0560296fdacb65", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABErjBYVEsKgchk3yQleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=75d46be63f76fd4062f354a56c692855da366148&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFEKuY2qihwrDQchiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFtVHlBQndpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWDZpeHhhRnRPMF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhTlE4N0ZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPDtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAIkDFQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=59e0ab1f626c2e4dc5c4f6e6837b77559cf502b4" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "7960926407704980889", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEJnboLK5jLm9bhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIUZEeFl4QWlta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhSUpVQVhXMC1JXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFTQThFR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATf359HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=8d00bc7576c3cc19fe8b3fb4aa42966583741dfa", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABGZLUiWY-R6bhk3yQleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=c813392cbb81d43466d5d949b9bebc2305e6fe7d&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEJnboLK5jLm9bhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiFGRHhZeEFpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYUlKVUFYVzAtSV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhU0E4RUd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=284760a6e2d4f226b639d29237e9c1aa25ca49a9" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "7561862402601574638", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEO7By9umucj4aBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCITREcWpId2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFTSVA1dzg5RGVRXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0BBRHdQdy4umgKJASFTUTlYRzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56VXdRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCADgBADwBNLsn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAaakRAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=917e8af2ed1c82091f487b6abd78de47b99e9e46", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABHu4HJryiHxaBk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=ff73768bfb14e9ae603064fc91e95b60c8d872e2&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEO7By9umucj4aBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiE0RHFqSHdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBU0lQNXc4OURlUV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNAQUR3UHcuLpoCiQEhU1E5WEc6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTDaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEUAcAFAMkFacEU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=84c66b632a2930d28092e00985ee154ba2e97288" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "6577796711489765634", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEIKC0sii6MGkWxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIVBUem53UWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFlaE5hMWl1Y3V3XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASE5dzR0X2c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=ea4a54786a8f3cf5177b3372ce97682da060c358", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABECgRQpQgdJWxk3yQleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=778fbf3014328ec0b01d6ebd7b306be32cf79950&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEIKC0sii6MGkWxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFQVHpud1FpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZWhOYTFpdWN1d18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhOXc0dF9nNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=28a3b583912b95528519f63a75c0fe2d06064e7b" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "2418275491761094586", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFELr_z7v0l9zHIRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIUF6MUJSZ2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFVNUE2dXpUVy1ZXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFTUTlYR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=c563626304ebb31fd6f1644cc2d4098133dec096", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABG6_3NHv3CPIRk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=88c9fbb2b9dc273865a5f9238543a29224908b26&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFELr_z7v0l9zHIRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFBejFCUmdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVTVBNnV6VFctWV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhU1E5WEd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=e76aeb8daad477f4428631fc89d277d4a4646ded" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "5990197965284733361", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFELHjwfj9qd2QUxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIURUeDF3d2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFmWXBYSEoxUGVNXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0BBRHdQdy4umgKJASFTUTlYRzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56VXdRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCADgBADwBNLsn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAaakRAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=e443347514ff5f6a52a2811f591f9a346061a756", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABGxcRDfT3UhUxk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=50348eb78116f7d35ca5ac6f6fa4c5548a6ceffc&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFELHjwfj9qd2QUxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFEVHgxd3dpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZllwWEhKMVBlTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNAQUR3UHcuLpoCiQEhU1E5WEc6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTDaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEUAcAFAMkFacEU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=a24f331ff55f96c5afe5134762f8d8e230b6287c" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "4399290132982250349", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEO32psKU4tqGPRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCITN6dDlwd2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFRWlZqbkpncmV3XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0BBRHdQdy4umgKJASFTUTlYRzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56VXdRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCADgBADwBNLsn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAaakRAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=0d9b0a06992ff427d281fae8d8b18d4e6838b944", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABFtu0lIEWsNPRk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=52a446d84f5e9a2baa068760c4406f4a567a911a&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEO32psKU4tqGPRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiEzenQ5cHdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBUVpWam5KZ3Jld18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNAQUR3UHcuLpoCiQEhU1E5WEc6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTDaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEUAcAFAMkFacEU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=e6ae592b5fc3de0053b5acd46294b83549aa00c8" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "8677372908685012092", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEPzYku74lY62eBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIVVEeGp5d2lua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFVN29abmh2c09RXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASE5dzR0X2c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=522b764f2276ce75053a55a0198b79fb8d1d39d5", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABF8rMSNrzhseBk3yQleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=02b75d0ecc71c7897b9590be5e50b094158c8097&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEPzYku74lY62eBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFVRHhqeXdpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVTdvWm5odnNPUV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhOXc0dF9nNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=0ae5558a7b0cc87eaa0c6811522629963b41bac5" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "617065604518434488", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFELitu4PevJDICBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIUFqMVNSZ2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaUzdZYTg5Ny13XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFTUTlYR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9HYBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAAAAAAAAAAAAAAAAAAAAEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=f59bdb7b0f7020f75c6019f23686915b72d61779", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABG41m7g5UGQCBk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=912a721db8e85d4d64a8869d7cf9b56cd0c24907&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFELitu4PevJDICBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFBajFTUmdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWlM3WWE4OTctd18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhU1E5WEd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBGAHABQDJBQAFARTwP9IFCQkFC3wAAADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgEhMAAA8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=9b4372ae0674305d9cd7152959910d1fa7d4daec" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "8957511111704921777", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFELGNpebanN6nfBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIXVqdHppQWlta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFUM1dNOVpkQU9JXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0BBRHdQdy4umgKJASFIZzhRRDo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56VXdRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCADgBADwBK_ln0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPC_0Ab1L9oGFgoQAAAAaakNAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=a8817d9dc3326ba1b59fe308f126ddaca5710a9c", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABGxRsms5XhPfBk3yQleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=a0ac94e902cbc609881fa9f39537bbc67ba046e7&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFELGNpebanN6nfBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiF1anR6aUFpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVDNXTTlaZEFPSV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNAQUR3UHcuLpoCiQEhSGc4UUQ6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTDaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEUAcAFAMkFacEU8D_SBQkJCQx0AADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSQo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=75b3ad3e867323196da165cd655b3ae51c8b44d0" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "2680240375770812721", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFELGi6rO9jYiZJRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIWd6eTMtZ2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYcFdVTk9rai1jXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFOUTg3RkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAAGmpDQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=f8458c6a48fed591c269169a9744aba11cb90285", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABExkXrWayAyJRk3yQleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=e2dbd082b353a37db9f632efc2532913a0c48166&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFELGi6rO9jYiZJRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFnenkzLWdpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWHBXVU5Pa2otY18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhTlE4N0ZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPDtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAIkDFQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=5475ac640321ae51a06b5c05ac62519e97e90114" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "8439286287321689724", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFEPzciY2kxZePdRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIU1UeWZ6d2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFWalR1QThjek9FXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFOUTg3RkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAAGmpDQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=73e760427d2aec3d47824994cf35c35f1eeddcf8", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABF8bqJBKl4edRk3yQleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=dac1e836a6f2c4dc036c50d0b3128dfefb34915d&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFEPzciY2kxZePdRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFNVHlmendpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVmpUdUE4Y3pPRV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhTlE4N0ZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPDtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAIkDFQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=6c1fb35564d2ffd08fb4c5b290aadd6e1e3d83ec" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "5519278898732145414", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEIa29Pmn3ZrMTBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCITFEc0hwUWlta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFkQUZ3YVliRWVNXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFTQThFR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATf359HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=d01f411e7cc9126e912daca85136b2ca6f99a347", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABEGGz1_6mqYTBk3yQleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=81115280cee86ae0bc259627410fa5dbbc178646&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEIa29Pmn3ZrMTBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiExRHNIcFFpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZEFGd2FZYkVlTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhU0E4RUd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=90f21feeb2c798cd77b3cadbc961240238825f0d" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "6754624236211478320", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFELC-hPXI3s_eXRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIVJqc0hVUWlta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaRjJPd05MVnVvXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFOUTg3RkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAAGmpDQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=34811f7e5c917550619274f5b75a0cd214119812", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABEwH6GO9D69XRk3yQleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=d811faa48963b18d33c0a1f9d1e64ff97640a415&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFELC-hPXI3s_eXRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFSanNIVVFpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWkYyT3dOTFZ1b18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhTlE4N0ZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPDtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAIkDFQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=c0a0a2d65dd091bd2ed81f95da1a9f7ff16ad70e" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/description.md b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/description.md new file mode 100644 index 00000000000..159ebbcc30b --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_wo_brandCategoryExclusion.html' +Test Spec File - 'test/spec/e2e/longform/basic_wo_brandCategoryExclusion.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: false + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/request.json b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/request.json new file mode 100644 index 00000000000..5a5ddce7d54 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/request.json @@ -0,0 +1,136 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/response.json b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/response.json new file mode 100644 index 00000000000..9273f8e0c7b --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/response.json @@ -0,0 +1,224 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "4631210661889362034", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEPKQq-_0sdeiQBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIXF6eU1HUWlua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFVQk5fYTFxbHU0XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASFTd19PR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0M9oEAggA4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=0dae5294ed5bb48b7d3a156e5e587a26da27c7e1", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABFyyOpNj11FQBk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=9085e4dbb4849b0e6d3714d84a2754bbab578e16&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEPKQq-_0sdeiQBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4z7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFxenlNR1FpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVUJOX2ExcWx1NF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhU3dfT0d3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=aa5533d04e16ee398f8028ab3af03a48d7d8cc17" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "714778825826946473", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEKmbi7Ph8dn1CRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIU56dmJOZ2lua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFRbjlXUzRmY09jXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0BBRHdQdy4umgKJASEtUTZrXzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56UXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCADgBADwBIvhn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAaakRAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=8917b1722eed5b6d85c6d5a01eea7862089bee32", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABGpzWIWjmfrCRk3yQleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=9ec7e7de16b948b60d74b47f1917faf5d3b6dbf0&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEKmbi7Ph8dn1CRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4z7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFOenZiTmdpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBUW45V1M0ZmNPY18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNAQUR3UHcuLpoCiQEhLVE2a186PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8N5JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAeAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgAAYfQo8D_QBvUv2gYWChABDy4BAFAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=8198652a5ee16abf4595ab1bfc6b051f81f0579d" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "231404788116786844", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEJydmpjcrYebAxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIUVqMFlVZ2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhLXFPTExmZ2VrXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASFTd19PR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0M9oEAggA4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=775dfc49086467337dee9a5e8d78b361931c6aaa", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABGcjgbDbR02Axk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=914256a92514df787ccb1eae7dea7578d23c8fba&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEJydmpjcrYebAxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4z7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFFajBZVWdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYS1xT0xMZmdla18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhU3dfT0d3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=f624619431372f9a248d0fa0dd8d09c4977bb544" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "7557072342526904599", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFEJeS-7GaqIfwaBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIUFqdmVKQWlta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFSY2lLblVqeU9VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0BBRHdQdy4umgKJASFJQS1IRDo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56UXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0dQFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCADgBADwBK_ln0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPC_0Ab1L9oGFgoQAAAAAAAAAAAAAAAAAAAAABAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=552663ed1246fd2a3cc5824164f57d32f18078ee", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABEXyT6mQR3gaBk3yQleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=e1c80e622aa60bf7683413f4371b0055d0d16f47&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFEJeS-7GaqIfwaBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4z7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFBanZlSkFpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBUmNpS25VanlPVV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNAQUR3UHcuLpoCiQEhSUEtSEQ6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEYAcAFAMkFAAUBFPA_0gUJCQULeAAAANgFAeAFAfAF4Fj6BQQIABAAkAYBmAYAuAYAwQYBIDAAAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=ccf266d1b02551a2ad0af0871d4af43e4aee4bba" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "5093465143102876632", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFENjX7JP78efXRhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIUJUeXRwUWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYamVBMVdNcXUwXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASEtUTZrX2c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0M9oEAggA4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=6651c1436b699842aabb3ae53d96d07caf5b4938", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABHYK3uyj5-vRhk3yQleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=f62098bf5037b22ca4e5583289a1527fdfa87e43&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFENjX7JP78efXRhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4z7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFCVHl0cFFpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWGplQTFXTXF1MF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhLVE2a19nNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPDeSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBIvhn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYAAGH0KPA_0Ab1L9oGFgoQAQ8uAQBQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=4b43aaab766ee7d2e4c900ec32cb3c8b7ccef1d0" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/description.md b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/description.md new file mode 100644 index 00000000000..c1781561af5 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_wo_requireExactDuration.html' +Test Spec File - 'test/spec/e2e/longform/basic_wo_requireExactDuration.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/request.json b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/request.json new file mode 100644 index 00000000000..aba76398093 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/request.json @@ -0,0 +1,387 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/response.json b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/response.json new file mode 100644 index 00000000000..c35a47781f7 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/response.json @@ -0,0 +1,366 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "8905202273088829598", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCLWXp_AFEJ7x1-ORyejKexiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIWlEeE84Z2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhV09TRWpDY09NXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0BBRHdQdy4umgKJASFQZzlaRjo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56YzNRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0DgFlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc3N9oEAggA4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAZWQU8D_SBQkJBQt4AAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgEgMAAA8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=21195aa3e27f8eb88ba43d5da32e6b78c2aa03f8", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQm1ywleAAAAABGe-HUcSaKVexm1ywleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=3c05b8509dd5c7c4459886f4c69fdd9cd07caa66&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCLWXp_AFEJ7x1-ORyejKexiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFpRHhPOGdpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYVdPU0VqQ2NPTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjM04tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCYWtscVFVCRNAQUR3UHcuLpoCiQEhUGc5WkY6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTQUWPExFQUZfTkFNRRIA8gIeChoyMwDwwkxBU1RfTU9ESUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBNXmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0Nzc32gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAGXObNgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYFISwA8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=203ae79160a460b18f20165e5de53bb1f45e4933" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "2428831247136753876", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFENSR0sfppLzaIRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIXRUeV9FQWlta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFTek5nNXJvQi0wXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFVUThpSFE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAE39-fR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=af2d5096aa4f934e84b59ad16cd18dfe5b9bbc77", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABHUiPSYJvG0IRm1ywleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=440a389c7f556dac70c650bb1e593a10cbcdf2af&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFENSR0sfppLzaIRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiF0VHlfRUFpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBU3pOZzVyb0ItMF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjM04tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCYWtscVFVCRNEQUR3UHcuLpoCiQEhVVE4aUhRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpjM1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc3N9oEAggB4AQA8ATf359HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlznDYBQHgBQHwBay8FPoFBAgAEACQBgGYBgC4BgDBBgUiLADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=9b00ed17c420f328d63b72519d2d578c5921d0d7" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "1625697369389546128", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEJD1gLbO5OjHFhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIXVqeHMtUWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhcDVwSkxuSXVVXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFBQTlhQUE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=0e70f535a95c82238d685147f41e0bd2f86631c0", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABGQOsDmJKOPFhm1ywleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=144214d77cc4ced0893c9fe64132ad01c429c43c&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFEJD1gLbO5OjHFhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiF1anhzLVFpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYXA1cEpMbkl1VV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjM04tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCYWtscVFVCRNEQUR3UHcuLpoCiQEhQUE5YUFBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpjM1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc3N9oEAggB4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlznDYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgUiLADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=f6bc475b66c167036dcb9f10c7c5f176124829a6" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "5434800203981031918", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCLWXp_AFEO6TivzZv5K2Sxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIW5Ud3I5QWlta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFXVVcwV1Y1LU9JXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFKdzh1RGc2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULeAAAANgFAeAFAfAF4Fj6BQQIABAAkAYBmAYAuAYAwQYBIDAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=c3ba85f0eb0293896e02066385f82b4450af2cfb", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQm1ywleAAAAABHuiYKf_UlsSxm1ywleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=9eb2d880fa9b524a6a0807eef0c65b7b1393f48a&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCLWXp_AFEO6TivzZv5K2Sxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFuVHdyOUFpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBV1VXMFdWNS1PSV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjM04tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCYWtscVFVCRNEQUR3UHcuLpoCiQEhSnc4dURnNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpjM1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc3N9oEAggB4AQA8ASv5Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlzmzYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGBSEsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=17038c2671b58d2fd6ea98dd3f3e1166ee664dd0" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "8071104954749355970", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEMKP7OWZ5pSBcBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIXBUeEJEQWlsa184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFRbWtta1pXNGVZXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFSZ19sR1E2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAE0uyfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=005579c0ff91586a887354409f637a63a1d69031", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABHCB7ucMVMCcBm1ywleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=edbfae73be0f41d672298d5c3ec9dd28a5307233&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6CKB6BAAAAwDWAAUBCLWXp_AFEMKP7OWZ5pSBcBiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDS7J9HWJzxW2AAaM26dXjWuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc3MDAyNzcpO3VmKCdyJywgMTQ5NDE5NjAyLCAxNRkf8P2SArkCIXBUeEJEQWlsa184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFRbWtta1pXNGVZXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFSZ19sR1E2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTQUWPExFQUZfTkFNRRIA8gIeChoyMwDwwkxBU1RfTU9ESUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBNXmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0Nzc32gQCCAHgBADwBNLsn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAGXOcNgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGBSIsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=0ac18b64a6c0d58a114085d8b565b4c98de56448" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "6893555531330982923", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEIuopuO2h7XVXxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE0MTg4Nh8A8P2SArkCIVFqd1R0Z2lHa184UEVLekNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFZS1J6NEZQV2V3XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASEzUTZnOHc2PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAErMKfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAF8owB-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=f9ddb1066825dfc556d108168ffc0d16cf567ae8", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABELlGlsO9SqXxm1ywleAAAAACCswp9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jyjAFiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAazCn0ewAQE.&s=db3a0d52f97edd94aa7e4213c437d8e4a5bd16ce&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149414188, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 32, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 29000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFEIuopuO2h7XVXxiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQrMKfR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxNDE4OCwgMTUZH_D9kgK5AiFRandUdGdpR2tfOFBFS3pDbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBWUtSejRGUFdld18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjM04tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCYWtscVFVCRNEQUR3UHcuLpoCiQEhM1E2Zzh3Nj0BJG5QRmJJQVFvQUQVSFRxUURvSlUwbE9Nem8wTnpjM1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc3N9oEAggB4AQA8ASswp9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlznDYBQHgBQHwBfKMAfoFBAgAEACQBgGYBgC4BgDBBgUiLADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=917c8192c7dc7e382c0bb7296ab0df261e69f572" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "5615186251901272031", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "6647218197537074925", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "4707051182303115567", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "4831890668873532085", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "7151522995196673389", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "4077353832159380438", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFENaHwKvS9urKOBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIWJqeHo1UWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFZd1VQNVZMNi1VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFLZzhBRUE2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAExd2fR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=e96d121a0a7d49e05c1d2b4fab2da60d0b544287", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABHWA3AltauVOBm1ywleAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=8d90e3ce42fe47da19cb85f8fb2d78822c590464&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6CKB6BAAAAwDWAAUBCLWXp_AFENaHwKvS9urKOBiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXjWuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc3MDAyNzcpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIWJqeHo1UWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFZd1VQNVZMNi1VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFLZzhBRUE2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTQUWPExFQUZfTkFNRRIA8gIeChoyMwDwwkxBU1RfTU9ESUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBNXmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0Nzc32gQCCAHgBADwBMXdn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAGXOcNgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGBSIsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=db30796cc71c3bee3aa8fc2890c75ad7186f9d73" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "2099457773367093540", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "7214207858308840891", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "4564285281969145467", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/description.md b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/description.md new file mode 100644 index 00000000000..c1781561af5 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_wo_requireExactDuration.html' +Test Spec File - 'test/spec/e2e/longform/basic_wo_requireExactDuration.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/request.json b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/request.json new file mode 100644 index 00000000000..f2f20700ffe --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/request.json @@ -0,0 +1,137 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/response.json b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/response.json new file mode 100644 index 00000000000..5f2118095d4 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/response.json @@ -0,0 +1,224 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "2704229116537156015", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEK_j3NPcwdbDJRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIXpUczJvQWlta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFURVBwVy1oVE9ZXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwT2VBRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZMGxxUVUJE0BBRHdQdy4umgKJASFVQV9qSDo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56UTVRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0DgFlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0OdoEAggA4AQA8ATf359HiAUBmAUAoAX___________8BwAUAyQUAZWQU8D_SBQkJBQt8AAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYBITAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=64565aadf65d370e9730e9ce82c93c9bd2fcfc14", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABGvMXfKDVqHJRm1ywleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=3b1f10f67b3253e38770fff694edbe6052795602&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFEK_j3NPcwdbDJRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4t7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiF6VHMyb0FpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVEVQcFctaFRPWV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME9lQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTBscVFVCRNAQUR3UHcuLpoCiQEhVUFfakg6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelE1UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTQUWPExFQUZfTkFNRRIA8gIeChoyMwDwwkxBU1RfTU9ESUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBNXmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ52gQCCAHgBADwBN_fn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAGXOcNgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGBSIsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=5316c3262f36e4d89735b1ba252c64651a84f479" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "7987581685263122854", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEKaDmaSQ5-Xsbhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIU16MXpZd2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYLVkxZU5tY3VRXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwT2VBRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZMGxxUVUJE0RBRHdQdy4umgKJASFVUTgySFE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelE1UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDnaBAIIAOAEAPAE0uyfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=17f2a3f5e78c188cc6ca23e677ced305198a8a05", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABGmQYYEOZfZbhm1ywleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=28e8f96efdfb9bc1e33e4d087ff5ed992e4692b1&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFEKaDmaSQ5-Xsbhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4t7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFNejF6WXdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWC1ZMWVObWN1UV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME9lQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTBscVFVCRNEQUR3UHcuLpoCiQEhVVE4MkhRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRNVFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0OdoEAggB4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlznDYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgUiLADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=89d4586d9597cd2f9a4a918d1e6985aee45ade01" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "653115326806257319", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCLWXp_AFEKfdmd3enZWICRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCITlEd0hNZ2lta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFjTnlESmJxeS13XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwT2VBRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZMGxxUVUJE0RBRHdQdy4umgKJASFKZ192RFE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelE1UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDnaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULeAAAANgFAeAFAfAF4Fj6BQQIABAAkAYBmAYAuAYAwQYBIDAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=1928a9daadbd431792adace7620880dda961eefb", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQm1ywleAAAAABGnbqbr7VQQCRm1ywleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=7617d08e0c16fe1dea8ec80cd6bf73ec0a736b41&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCLWXp_AFEKfdmd3enZWICRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4t7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiE5RHdITWdpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBY055REpicXktd18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME9lQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTBscVFVCRNEQUR3UHcuLpoCiQEhSmdfdkRRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRNVFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0OdoEAggB4AQA8ASv5Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlzmzYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGBSEsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=0d1d3f42fa225995a2f57ab84877dce3d24e9901" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "866435845408148233", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEImW35H52YyDDBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIXJEenNfZ2lua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFjMmZTZ1BpMi1BXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwT2VBRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZMGxxUVUJE0RBRHdQdy4umgKJASFfdzRiQUE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelE1UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDnaBAIIAOAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=83f65f38b4fd56344b3aceb70df7bac1b9b5f229", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABEJyzeSzzIGDBm1ywleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=9130c13cca7a1d3eb05c2b96585ccfdc2faa6844&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFEImW35H52YyDDBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4t7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFyRHpzX2dpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYzJmU2dQaTItQV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME9lQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTBscVFVCRNEQUR3UHcuLpoCiQEhX3c0YkFBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRNVFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0OdoEAggB4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlznDYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgUiLADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=1f88d8b0a467d528291f90a54fd810b8fdac4488" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "1540903203561034860", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCLWXp_AFEOyokYzL6ZixFRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIXdUekVId2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaeE00NUxjRXVNXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwT2VBRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZMGxxUVUJE0RBRHdQdy4umgKJASFQUThhRmc2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelE1UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDnaBAIIAOAEAPAExOefR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULeAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYBIDAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=a4de0e4084ce04a5cb2d347c07fde867aa9ff5c1", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQm1ywleAAAAABFsVISxTGNiFRm1ywleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=cf600d825cec85f83c06119e5e383f8548b469a2&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCLWXp_AFEOyokYzL6ZixFRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4t7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiF3VHpFSHdpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWnhNNDVMY0V1TV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME9lQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTBscVFVCRNEQUR3UHcuLpoCiQEhUFE4YUZnNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRNVFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0OdoEAggB4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlzmzYBQHgBQHwBZk9-gUECAAQAJAGAZgGALgGAMEGBSEsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=17c466ea45d5d4beff02aa2b0eb87bc6c4d5aff3" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/modules/description.md b/test/fake-server/fixtures/modules/description.md new file mode 100644 index 00000000000..db13453b8aa --- /dev/null +++ b/test/fake-server/fixtures/modules/description.md @@ -0,0 +1,68 @@ +Test Pages: + - 'test/pages/bidderSettings.html' + - 'test/pages/consent_mgt_gdpr.html' + - 'test/pages/currency.html' + - 'test/pages/priceGranularity.html' + - 'test/pages/sizeConfig.html' + - 'test/pages/userSync.html' +Test Spec Files: + - 'test/spec/e2e/modules/e2e_bidderSettings.spec.js' + - 'test/spec/e2e/modules/e2e_consent_mgt_gdpr.spec.js' + - 'test/spec/e2e/modules/e2e_currency.spec.js' + - 'test/spec/e2e/modules/e2e_priceGranularity.spec.js' + - 'test/spec/e2e/modules/e2e_sizeConfig.spec.js' + - 'test/spec/e2e/modules/e2e_userSync.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'div-gpt-ad-1460505748561-0', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + // Replace this object to test a new Adapter! + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13144370 + } + }] + +}, { + code: '/19968336/prebid_native_example_2', + sizes: [ + [1, 1] + ], + mediaTypes: { + native: { + title: { + required: true + }, + body: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + }, + icon: { + required: false + }, + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232354, + allowSmallerSizes: true + } + }] +}]; +``` + +Refer to individual test pages to see the proper setConfigs for each test. diff --git a/test/fake-server/fixtures/modules/request.json b/test/fake-server/fixtures/modules/request.json new file mode 100644 index 00000000000..35dd6e2d499 --- /dev/null +++ b/test/fake-server/fixtures/modules/request.json @@ -0,0 +1,74 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 300, + "height": 250 + }, + { + "width": 300, + "height": 600 + } + ], + "primary_size": { + "width": 300, + "height": 250 + }, + "ad_types": [ + "banner" + ], + "id": 13144370, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 1 + }, + { + "sizes": [ + { + "width": 1, + "height": 1 + } + ], + "ad_types": [ + "native" + ], + "id": 13232354, + "allow_smaller_sizes": true, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "native": { + "layouts": [ + { + "title": { + "required": true + }, + "description": { + "required": true + }, + "main_image": { + "required": true + }, + "sponsored_by": { + "required": true + }, + "icon": { + "required": false + } + } + ] + }, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/modules/response.json b/test/fake-server/fixtures/modules/response.json new file mode 100644 index 00000000000..9b708fa1534 --- /dev/null +++ b/test/fake-server/fixtures/modules/response.json @@ -0,0 +1,106 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13144370, + "auction_id": "4842409943576641356", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmodules%2Fcurrency.html%3Fpbjs_debug%3Dtrue&e=wqT_3QK7CKA7BAAAAwDWAAUBCNvV-_AFEMz-0f3_xeyZQxjCs_b6q5D9_0oqNgkAAAkCABEJBywAABkAAACA61HgPyEREgApEQkAMREb8GkwsqKiBjjtSEDtSEgAUABYnPFbYABotc95eACAAQGKAQCSAQNVU0SYAawCoAHYBKgBAbABALgBAcABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3OTA4NDUwNyk7AR0scicsIDk4NDkzNTgxNh4A8NCSArUCIVpqeldtZ2l1c0s0S0VJM0oteTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlNSUdhQUJ3RG5qd0U0QUJUSWdCOEJPUUFRQ1lBUUNnQVFHb0FRT3dBUUM1QVNtTGlJTUFBT0Ffd1FFcGk0aURBQURnUDhrQmxiMDhGYV9INERfWkFRQUFBQUFBQVBBXzRBRUE5UUVBQUFBQW1BSUFvQUlBdFFJQUFBQUF2UUlBQUFBQTRBSUE2QUlBLUFJQWdBTUJtQU1CcUFPdQHEiHVnTUpVMGxPTXpvME56TTE0QU80R1lnRUFKQUVBSmdFQWNFCV0FAQhESkIFCAkBGDJBUUE4UVEJDQEBLFBnRUFJZ0ZfeVNwQhEXNFBBX5oCiQEhblE4cUxBNjkBJG5QRmJJQVFvQUQRZBBEZ1B6bzKRABBRTGdaUx1NAFURDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJLDTpIdGVzdC5sb2NhbGhvc3Q6OTk5OQUUWC9wYWdlcy9tb2R1bGVzL2N1cnJlbmN5BUbwQD9wYmpzX2RlYnVnPXRydWWAAwCIAwGQAwCYAxegAwGqAwDAA6wCyAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzDbDwXpgEAKIECzEwLjc1Ljc0LjY5qATikAGyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggA4AQB8ASNyfsuiAUBmAUAoAX_____BQMYAcAFAMkFAAUBFPA_0gUJCQULfAAAANgFAeAFAfAFmfQh-gUECAAQAJAGAJgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGAfIGAggAgAcBiAcAoAcB&s=16a5ea7c8d5eb050a368495961803753dd6086c2", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "banner", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 98493581, + "media_type_id": 1, + "media_subtype_id": 1, + "cpm": 0.5, + "cpm_publisher_currency": 0.5, + "publisher_currency_code": "$", + "brand_category_id": 53, + "client_initiated_ad_counting": true, + "rtb": { + "banner": { + "content": "
", + "width": 300, + "height": 600 + }, + "trackers": [ + { + "impression_urls": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmodules%2Fcurrency.html%3Fpbjs_debug%3Dtrue&e=wqT_3QLDCKBDBAAAAwDWAAUBCNvV-_AFEMz-0f3_xeyZQxjCs_b6q5D9_0oqNgkAAAECCOA_EQEHNAAA4D8ZAAAAgOtR4D8hERIAKREJADERG6gwsqKiBjjtSEDtSEgCUI3J-y5YnPFbYABotc95eJ64BYABAYoBA1VTRJIBAQbwUpgBrAKgAdgEqAEBsAEAuAEBwAEEyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc5MDg0NTA3KTt1ZigncicsIDk4NDkzNTgxNh4A8NCSArUCIVpqeldtZ2l1c0s0S0VJM0oteTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlNSUdhQUJ3RG5qd0U0QUJUSWdCOEJPUUFRQ1lBUUNnQVFHb0FRT3dBUUM1QVNtTGlJTUFBT0Ffd1FFcGk0aURBQURnUDhrQmxiMDhGYV9INERfWkFRQUFBQUFBQVBBXzRBRUE5UUVBQUFBQW1BSUFvQUlBdFFJQUFBQUF2UUlBQUFBQTRBSUE2QUlBLUFJQWdBTUJtQU1CcUFPdQHEiHVnTUpVMGxPTXpvME56TTE0QU80R1lnRUFKQUVBSmdFQWNFCV0FAQhESkIFCAkBGDJBUUE4UVEJDQEBLFBnRUFJZ0ZfeVNwQhEXNFBBX5oCiQEhblE4cUxBNjkBJG5QRmJJQVFvQUQRZBBEZ1B6bzKRABBRTGdaUx1NAFURDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJLDTpIdGVzdC5sb2NhbGhvc3Q6OTk5OQUUWC9wYWdlcy9tb2R1bGVzL2N1cnJlbmN5BUbwQD9wYmpzX2RlYnVnPXRydWWAAwCIAwGQAwCYAxegAwGqAwDAA6wCyAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzDbDwXpgEAKIECzEwLjc1Ljc0LjY5qATikAGyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggB4AQB8ASNyfsuiAUBmAUAoAX_____BQMYAcAFAMkFAAUBFPA_0gUJCQULfAAAANgFAeAFAfAFmfQh-gUECAAQAJAGAJgGALgGAMEGASEwAADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGAfIGAggAgAcBiAcAoAcB&s=9c378bb4ca21a7509f69955fb4e6fe72035190c6" + ], + "video_events": {} + } + ] + } + } + ] + }, + { + "tag_id": 13232354, + "auction_id": "8100967561168057198", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmodules%2Fcurrency.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKECKAEBAAAAwDWAAUBCNvV-_AFEO7mieO34pq2cBjCs_b6q5D9_0oqNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMOLRpwY47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc5MDg0NTA3KTsBHSxyJywgOTc0OTQyMDQ2HgDwmpICtQIhMVR6c3lRajgtTHdLRUx6SnZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1JR2FBQndBSGdBZ0FGTWlBSHdFNUFCQUpnQkFLQUJBYWdCQTdBQkFMa0I4NjFxcEFBQUpFREJBZk90YXFRQUFDUkF5UUc5QzZTMEtFampQOWtCQUFBQUFBQUE4RF9nQVFEMUFRAQ8sQ1lBZ0NnQWdDMUFnBRAAOQkI8EBEZ0FnRG9BZ0Q0QWdDQUF3R1lBd0dvQV96NHZBcTZBd2xUU1U0ek9qUTNNelhnQTdnWmlBUUFrQVFBbUFRQndRUQFNCQEITWtFCQkBARhEWUJBRHhCAQsNASwtQVFBaUFYX0pLa0YNEzxBOEQ4LpoCiQEhZUE4dE1BNjkBJG5QRmJJQVFvQUQVWFhrUURvSlUwbE9Nem8wTnpNMVFMZ1pTUQ1PDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQygZUFBLtgCAOACrZhI6gJLaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkFFPDXL3BhZ2VzL21vZHVsZXMvY3VycmVuY3kuaHRtbD9wYmpzX2RlYnVnPXRydWWAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagE4pABsgQOCAAQARgAIAAoADAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggA4AQB8AS8yb4uiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAaVZ0ANgFAeAFAfAFmfQh-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgzyBgIIAIAHAYgHAKAHQQ..&s=428486554947609aac96ed5569d9bb2dd2be5502", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "native", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97494204, + "media_type_id": 12, + "media_subtype_id": 65, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 53, + "client_initiated_ad_counting": true, + "viewability": { + "config": "" + }, + "rtb": { + "native": { + "title": "This is a Prebid Native Creative", + "desc": "This is a Prebid Native Creative. There are many like it, but this one is mine.", + "sponsored": "Prebid.org", + "icon": { + "url": "http://vcdn.adnxs.com/p/creative-image/1a/3e/e9/5b/1a3ee95b-06cd-4260-98c7-0258627c9197.png", + "width": 127, + "height": 83, + "prevent_crop": false + }, + "main_img": { + "url": "http://vcdn.adnxs.com/p/creative-image/f8/7f/0f/13/f87f0f13-230c-4f05-8087-db9216e393de.jpg", + "width": 989, + "height": 742, + "prevent_crop": false + }, + "link": { + "url": "http://prebid.org/dev-docs/show-native-ads.html", + "click_trackers": [ + "http://sin3-ib.adnxs.com/click?AAAAAAAAJEAAAAAAAAAkQAAAAAAAACRAAAAAAAAAJEAAAAAAAAAkQG5zYnwTa2xwwpldv4L0_0rb6h5eAAAAAOLoyQBtJAAAbSQAAAIAAAC8pM8FnPgWAAAAAABVU0QAVVNEAAEAAQBNXQAAAAABAQQCAAAAALoAYBc26wAAAAA./bcr=AAAAAAAA8D8=/cnd=%21eA8tMAj8-LwKELzJvi4YnPFbIAQoADEAAAAAAAAkQDoJU0lOMzo0NzM1QLgZSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA./cca=OTMyNSNTSU4zOjQ3MzU=/bn=89118/" + ] + }, + "impression_trackers": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmodules%2Fcurrency.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKMCKAMBAAAAwDWAAUBCNvV-_AFEO7mieO34pq2cBjCs_b6q5D9_0oqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlC8yb4uWJzxW2AAaM26dXieuAWAAQGKAQNVU0SSAQEG8FKYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzkwODQ1MDcpO3VmKCdyJywgOTc0OTQyMDQsIC4eAPCakgK1AiExVHpzeVFqOC1Md0tFTHpKdmk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNHRHbkJsZ0FZTUlHYUFCd0FIZ0FnQUZNaUFId0U1QUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRRzlDNlMwS0VqalA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BX3o0dkFxNkF3bFRTVTR6T2pRM016WGdBN2daaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhfSktrRg0TPEE4RDgumgKJASFlQTh0TUE2OQEkblBGYklBUW9BRBVYWGtRRG9KVTBsT016bzBOek0xUUxnWlNRDU8MUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDKBlQUEu2AIA4AKtmEjqAktodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OQUU8NcvcGFnZXMvbW9kdWxlcy9jdXJyZW5jeS5odG1sP3BianNfZGVidWc9dHJ1ZYADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qATikAGyBA4IABABGAAgACgAMAA4ArgEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM12gQCCAHgBAHwBLzJvi6IBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQBpXnQA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYJJCjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGDPIGAggAgAcBiAcAoAdB&s=d6c58ebc137658c5dd258579c2575ad499e7a7b4" + ], + "id": 97494204 + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/description.md b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/description.md new file mode 100644 index 00000000000..c5b114e8bb3 --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/description.md @@ -0,0 +1,43 @@ +Test Page - 'test/pages/multiple_bidders.html' +Test Spec File - 'test/spec/e2e/multi-bidder/e2e_multiple_bidders.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'div-banner-native-1', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232392, + } + }] +}, +{ + code: 'div-banner-native-2', + mediaTypes: { + native: { + title: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + } + } + }, + bids: [{ + bidder: 'adasta', + params: { + placementId: 13232392, + } + }] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/request.json b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/request.json new file mode 100644 index 00000000000..c4c862adc20 --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/request.json @@ -0,0 +1,43 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 1, + "height": 1 + } + ], + "ad_types": [ + "native" + ], + "id": 13232392, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "native": { + "layouts": [ + { + "title": { + "required": true + }, + "main_image": { + "required": true + }, + "sponsored_by": { + "required": true + } + } + ] + }, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/response.json b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/response.json new file mode 100644 index 00000000000..56894e97e05 --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/response.json @@ -0,0 +1,59 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13232392, + "auction_id": "6287559286677633407", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmultiple_bidders.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKICKAIBAAAAwDWAAUBCM3FpfEFEP_yg9W7u_mgVxi7_-bKzp3kuD8qNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMIjSpwY47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc5NzcwNTczKTsBHSxyJywgOTc1MjA0MzQ2HgDw0JICtQIhQWp4NUh3aUgtYndLRUxLV3dDNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUWlOS25CbGdBWUtzR2FBQndBbmlLQVlBQkhvZ0JpZ0dRQVFDWUFRQ2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCb2FZc1BwVDM0VF9aQVFBQUFBQUFBUEFfNEFFQTlRRUFBQUFBbUFJQW9BSUF0UUlBQUFBQXZRSUFBQUFBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQU9IAcSIdWdNSlUwbE9Nem8wT0RRMDRBUDRHWWdFQUpBRUFKZ0VBY0UJXQUBCERKQgUICQEYMkFRQThRUQkNAQEsUGdFQUlnRjdDV3BCERc0UEFfmgKJASFDZy1TX2c2OQEkblBGYklBUW9BRBVkDGtRRG8ykQAQUVBnWlMdTQBVEQwMQUFBVx0MAFkdDABhHQwAYx0MoGVBQS7YAgDgAq2YSOoCS2h0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5BRTw3i9wYWdlcy9tdWx0aXBsZV9iaWRkZXJzLmh0bWw_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQOMTAzLjc5LjEwMC4xODCoBOZCsgQQCAQQARgAIAAoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0ODQ02gQCCADgBAHwBLKWwC6IBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAABDnDYBQHgBQHwBZn0IfoFBAgAEACQBgGYBgC4BgDBBgEhMAAA8L_QBvUv2gYWChAJERkBUBAAGADgBgzyBgIIAIAHAYgHAKAHQQ..&s=8b14b952b73092945ef66436be991786b53f7a68", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "native", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97520434, + "media_type_id": 12, + "media_subtype_id": 65, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 53, + "client_initiated_ad_counting": true, + "viewability": { + "config": "" + }, + "rtb": { + "native": { + "title": "This is a Prebid Native Creative", + "sponsored": "Prebid.org", + "main_img": { + "url": "https://vcdn.adnxs.com/p/creative-image/f8/7f/0f/13/f87f0f13-230c-4f05-8087-db9216e393de.jpg", + "width": 989, + "height": 742, + "prevent_crop": false + }, + "link": { + "url": "http://prebid.org/dev-docs/show-multi-format-ads.html", + "click_trackers": [ + "https://sin3-ib.adnxs.com/click?AAAAAAAAJEAAAAAAAAAkQAAAAAAAACRAAAAAAAAAJEAAAAAAAAAkQH_5oLrb5UFXu79Z6eyQcT_NYileAAAAAAjpyQBtJAAAbSQAAAIAAAAyC9AFnPgWAAAAAABVU0QAVVNEAAEAAQBNXQAAAAABAQQCAAAAALoAnRbC8wAAAAA./bcr=AAAAAAAA8D8=/cnd=%21Cg-S_giH-bwKELKWwC4YnPFbIAQoADEAAAAAAAAkQDoJU0lOMzo0ODQ0QPgZSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA./cca=OTMyNSNTSU4zOjQ4NDQ=/bn=89112/" + ] + }, + "impression_trackers": [ + "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmultiple_bidders.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKQCKAQBAAAAwDWAAUBCM3FpfEFEP_yg9W7u_mgVxi7_-bKzp3kuD8qNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIjSpwY47UhA7UhIAlCylsAuWJzxW2AAaM26dXiYuAWAAQGKAQNVU0SSAQEG8FKYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1Nzk3NzA1NzMpO3VmKCdyJywgOTc1MjA0MzQsIC4eAPDQkgK1AiFBang1SHdpSC1id0tFTEtXd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRaU5LbkJsZ0FZS3NHYUFCd0FuaUtBWUFCSG9nQmlnR1FBUUNZQVFDZ0FRR29BUU93QVFDNUFmT3RhcVFBQUNSQXdRSHpyV3FrQUFBa1FNa0JvYVlzUHBUMzRUX1pBUUFBQUFBQUFQQV80QUVBOVFFQUFBQUFtQUlBb0FJQXRRSUFBQUFBdlFJQUFBQUE0QUlBNkFJQS1BSUFnQU1CbUFNQnFBT0gBxIh1Z01KVTBsT016bzBPRFEwNEFQNEdZZ0VBSkFFQUpnRUFjRQldBQEIREpCBQgJARgyQVFBOFFRCQ0BASxQZ0VBSWdGN0NXcEIRFzRQQV-aAokBIUNnLVNfZzY5ASRuUEZiSUFRb0FEFWQMa1FEbzKRABBRUGdaUx1NAFURDAxBQUFXHQwAWR0MAGEdDABjHQygZUFBLtgCAOACrZhI6gJLaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkFFPDeL3BhZ2VzL211bHRpcGxlX2JpZGRlcnMuaHRtbD9wYmpzX2RlYnVnPXRydWWAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA4xMDMuNzkuMTAwLjE4MKgE5kKyBBAIBBABGAAgACgBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ4NDTaBAIIAeAEAfAEspbALogFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAEOcNgFAeAFAfAFmfQh-gUECAAQAJAGAZgGALgGAMEGASEwAADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGDPIGAggAgAcBiAcAoAdB&s=2061bd85ce022a41bc16ebb20c193aabbbc07809" + ], + "id": 97520434 + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/description.md b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/description.md new file mode 100644 index 00000000000..c5b114e8bb3 --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/description.md @@ -0,0 +1,43 @@ +Test Page - 'test/pages/multiple_bidders.html' +Test Spec File - 'test/spec/e2e/multi-bidder/e2e_multiple_bidders.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'div-banner-native-1', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232392, + } + }] +}, +{ + code: 'div-banner-native-2', + mediaTypes: { + native: { + title: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + } + } + }, + bids: [{ + bidder: 'adasta', + params: { + placementId: 13232392, + } + }] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/request.json b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/request.json new file mode 100644 index 00000000000..8399bed631c --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/request.json @@ -0,0 +1,36 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 300, + "height": 250 + }, + { + "width": 300, + "height": 600 + } + ], + "primary_size": { + "width": 300, + "height": 250 + }, + "ad_types": [ + "banner" + ], + "id": 13232392, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/response.json b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/response.json new file mode 100644 index 00000000000..54ad643b82d --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/response.json @@ -0,0 +1,49 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13232392, + "auction_id": "6917498423334366136", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmultiple_bidders.html%3Fpbjs_debug%3Dtrue&e=wqT_3QLBCKBBBAAAAwDWAAUBCNGcpvEFELjXrYmmhfn_Xxi7_-bKzp3kuD8qNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQn0gQEkQDCI0qcGOO1IQO1ISABQAFic8VtgAGjNunV4AIABAYoBAJIBA1VTRJgBrAKgAfoBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc5NzgxNzEzKTt1ZigncicsIDk2ODQ2MDM1LCAxNTc5NzgxNzEzKTuSArUCITZEb2NyZ2lILWJ3S0VOT0JseTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFpTktuQmxnQVlLc0dhQUJ3R25oaWdBR1lBWWdCWXBBQkFKZ0JBS0FCQWFnQkE3QUJBTGtCODYxcXBBQUFKRURCQWZPdGFxUUFBQ1JBeVFHQ1VBT2x6Q0xkUDlrQkFBQUFBQUFBOERfZ0FRRDFBUUFBQUFDWUFnQ2dBZ0MxQWdBQUFBQzlBZ0FBQUFEZ0FnRG9BZ0Q0QWdDQUF3R1lBd0dvQTRmNXZBcTZBd2xUU1U0ek9qUTNNem5nQV9nWmlBUUFrQVFBbUFRQndRUQFNCQEITWtFCQkBARhEWUJBRHhCAQsNASwtQVFBaUFXREpha0YNE0BBOEQ4LpoCiQEhOEE1YjlRaTI5ASRuUEZiSUFRb0FEFVhYa1FEb0pVMGxPTXpvME56TTVRUGdaU1ENTwxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8EZlQUEuwgI1aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc2hvdy1tdWx0aS1mb3JtYXQtYWRzLmh0bWzYAgDgAq2YSOoCSw1ASHRlc3QubG9jYWxob3N0Ojk5OTkFFBgvcGFnZXMvBUYocGxlX2JpZGRlcnMFRvBAP3BianNfZGVidWc9dHJ1ZYADAIgDAZADAJgDF6ADAaoDAMADrALIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMNtvBhmAQAogQOMTAzLjc5LjEwMC4xODCoBJ9EsgQSCAQQARisAiD6ASgBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MznaBAIIAOAEAfAE04GXLogFAZgFAKAF______8BAxQBwAUAyQVpiBTwP9IFCQkJDHAAANgFAeAFAfAFAfoFBAgAEACQBgCYBgC4BgDBBgkjKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYB8gYCCACABwGIBwCgBwE.&s=8d42ac30ca2d2a8a63215f5aba2a43bd23af0023", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "banner", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 96846035, + "media_type_id": 1, + "media_subtype_id": 1, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 0, + "client_initiated_ad_counting": true, + "rtb": { + "banner": { + "content": "
", + "width": 300, + "height": 250 + }, + "trackers": [ + { + "impression_urls": [ + "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmultiple_bidders.html%3Fpbjs_debug%3Dtrue&e=wqT_3QLJCKBJBAAAAwDWAAUBCNGcpvEFELjXrYmmhfn_Xxi7_-bKzp3kuD8qNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIjSpwY47UhA7UhIAlDTgZcuWJzxW2AAaM26dXicuAWAAQGKAQNVU0SSAQEG8FKYAawCoAH6AagBAbABALgBAcABBMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3OTc4MTcxMyk7dWYoJ3InLCA5Njg0NjAzNTYeAPCakgK1AiE2RG9jcmdpSC1id0tFTk9CbHk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRaU5LbkJsZ0FZS3NHYUFCd0duaGlnQUdZQVlnQllwQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRR0NVQU9sekNMZFA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BNGY1dkFxNkF3bFRTVTR6T2pRM016bmdBX2daaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVdESmFrRg0TPEE4RDgumgKJASE4QTViOVE2OQEkblBGYklBUW9BRBVYWGtRRG9KVTBsT016bzBOek01UVBnWlNRDU8MUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBGZUFBLsICNWh0dHA6Ly9wcmViaWQub3JnL2Rldi1kb2NzL3Nob3ctbXVsdGktZm9ybWF0LWFkcy5odG1s2AIA4AKtmEjqAksNQEh0ZXN0LmxvY2FsaG9zdDo5OTk5BRQYL3BhZ2VzLwVGKHBsZV9iaWRkZXJzBUbwQD9wYmpzX2RlYnVnPXRydWWAAwCIAwGQAwCYAxegAwGqAwDAA6wCyAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzDbbwYZgEAKIEDjEwMy43OS4xMDAuMTgwqASfRLIEEggEEAEYrAIg-gEoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM52gQCCAHgBAHwBNOBly6IBQGYBQCgBf______AQMUAcAFAMkFaZAU8D_SBQkJCQxwAADYBQHgBQHwBQH6BQQIABAAkAYAmAYAuAYAwQYJIyjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGAfIGAggAgAcBiAcAoAcB&s=6c6fb8a005b60bc5535b528c16ed74cd66c08dd0" + ], + "video_events": {} + } + ] + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/index.js b/test/fake-server/index.js new file mode 100644 index 00000000000..752648c6746 --- /dev/null +++ b/test/fake-server/index.js @@ -0,0 +1,37 @@ +/* eslint-disable no-console */ + +const express = require('express'); +const morgan = require('morgan'); +const bodyParser = require('body-parser'); +const argv = require('yargs').argv; +const fakeResponder = require('./fake-responder.js'); + +const PORT = argv.port || '3000'; + +// Initialize express app +const app = express(); + +// Middlewares +app.use(bodyParser.urlencoded({ extended: false })); +app.use(bodyParser.json()); +app.use(bodyParser.text({ type: 'text/plain' })); +app.use(morgan('dev')); // used to log incoming requests + +// Allow Cross Origin request from 'test.localhost:9999' +app.use(function(req, res, next) { + res.header('Access-Control-Allow-Origin', req.headers.origin); + res.header('Access-Control-Allow-Credentials', true); + next(); +}); + +app.post('/', fakeResponder, (req, res) => { + res.send(); +}); + +app.use((req, res) => { + res.status(404).send('Not Found'); +}); + +app.listen(PORT, () => { + console.log(`fake-server listening on http://localhost:${PORT}`); +}); diff --git a/test/fixtures/fixtures.js b/test/fixtures/fixtures.js index 050ff90bc7a..2a0a7638fc4 100644 --- a/test/fixtures/fixtures.js +++ b/test/fixtures/fixtures.js @@ -53,11 +53,14 @@ export function getBidRequests() { 90 ] ], + 'mediaTypes': { + 'banner': { + 'sizes': [[728, 90], [970, 90]] + } + }, 'bidId': '392b5a6b05d648', 'bidderRequestId': '2946b569352ef2', 'auctionId': '1863e370099523', - 'startTime': 1462918897462, - 'status': 1, 'transactionId': 'fsafsa' }, { @@ -76,11 +79,14 @@ export function getBidRequests() { 600 ] ], + 'mediaTypes': { + 'banner': { + 'sizes': [[728, 90], [970, 90]] + } + }, 'bidId': '4dccdc37746135', 'bidderRequestId': '2946b569352ef2', 'auctionId': '1863e370099523', - 'startTime': 1462918897463, - 'status': 1, 'transactionId': 'fsafsa' } ], @@ -108,6 +114,11 @@ export function getBidRequests() { 600 ] ], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, 'bidId': '6d11aa2d5b3659', 'bidderRequestId': '5e1525bae3eb11', 'auctionId': '1863e370099523', @@ -157,6 +168,11 @@ export function getBidRequests() { 600 ] ], + 'mediaType': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, 'bidId': '96aff279720d39', 'bidderRequestId': '8778750ee15a77', 'auctionId': '1863e370099523', @@ -186,10 +202,14 @@ export function getBidRequests() { 600 ] ], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, 'bidId': '1144e2f0de84363', 'bidderRequestId': '107f5e6e98dcf09', 'auctionId': '1863e370099523', - 'startTime': 1462918897477, 'transactionId': 'fsafsa' } ], @@ -216,10 +236,14 @@ export function getBidRequests() { 600 ] ], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, 'bidId': '135e89c039705da', 'bidderRequestId': '12eeded736650b4', 'auctionId': '1863e370099523', - 'status': 1, 'transactionId': 'fsafsa' } ], @@ -246,11 +270,14 @@ export function getBidRequests() { 600 ] ], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, 'bidId': '17dd1d869bed44e', 'bidderRequestId': '167c4d79b615948', 'auctionId': '1863e370099523', - 'startTime': 1462918897480, - 'status': 1, 'transactionId': 'fsafsa' } ], @@ -277,11 +304,14 @@ export function getBidRequests() { 600 ] ], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, 'bidId': '192c8c1df0f5d1d', 'bidderRequestId': '18bed198c172a69', 'auctionId': '1863e370099523', - 'startTime': 1462918897481, - 'status': 1, 'transactionId': 'fsafsa' } ], @@ -308,6 +338,11 @@ export function getBidRequests() { 600 ] ], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, 'bidId': '21ae8131ec04f6e', 'bidderRequestId': '20d0d30333715a7', 'auctionId': '1863e370099523', @@ -323,6 +358,7 @@ export function getBidResponses() { return [ { 'bidderCode': 'triplelift', + 'mediaType': 'banner', 'width': 0, 'height': 0, 'statusMessage': 'Bid available', @@ -354,6 +390,7 @@ export function getBidResponses() { }, { 'bidderCode': 'appnexus', + 'mediaType': 'banner', 'width': 300, 'height': 250, 'statusMessage': 'Bid available', @@ -387,6 +424,7 @@ export function getBidResponses() { }, { 'bidderCode': 'appnexus', + 'mediaType': 'banner', 'width': 728, 'height': 90, 'statusMessage': 'Bid available', @@ -420,6 +458,7 @@ export function getBidResponses() { }, { 'bidderCode': 'pagescience', + 'mediaType': 'banner', 'width': 300, 'height': 250, 'statusMessage': 'Bid available', @@ -452,6 +491,7 @@ export function getBidResponses() { }, { 'bidderCode': 'brightcom', + 'mediaType': 'banner', 'width': 300, 'height': 250, 'statusMessage': 'Bid available', @@ -483,6 +523,7 @@ export function getBidResponses() { }, { 'bidderCode': 'brealtime', + 'mediaType': 'banner', 'width': 300, 'height': 250, 'statusMessage': 'Bid available', @@ -515,6 +556,7 @@ export function getBidResponses() { }, { 'bidderCode': 'pubmatic', + 'mediaType': 'banner', 'width': '300', 'height': '250', 'statusMessage': 'Bid available', @@ -548,6 +590,7 @@ export function getBidResponses() { }, { 'bidderCode': 'rubicon', + 'mediaType': 'banner', 'width': 300, 'height': 600, 'statusMessage': 'Bid available', @@ -616,138 +659,54 @@ export function getAdUnits() { return [ { 'code': '/19968336/header-bid-tag1', - 'sizes': [ - [ - 728, - 90 - ], - [ - 970, - 90 - ] - ], + 'mediaTypes': { + 'banner': { + 'sizes': [[728, 90], [970, 90]] + }, + }, 'bids': [ { 'bidder': 'adequant', 'params': { 'publisher_id': '1234567', 'bidfloor': 0.01 - }, - 'adUnitCode': '/19968336/header-bid-tag1', - 'sizes': [ - [ - 728, - 90 - ], - [ - 970, - 90 - ] - ], - 'bidId': '3692954f816efc', - 'bidderRequestId': '2b1a75d5e826c4', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'appnexus', 'params': { 'placementId': '543221', 'test': 'me' - }, - 'adUnitCode': '/19968336/header-bid-tag1', - 'sizes': [ - [ - 728, - 90 - ], - [ - 970, - 90 - ] - ], - 'bidId': '68136e1c47023d', - 'bidderRequestId': '55e24a66bed717', - 'auctionId': '1ff753bd4ae5cb', - 'startTime': 1463510220995, - 'status': 1 + } } ] }, { 'code': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, 'bids': [ { 'bidder': 'appnexus', 'params': { 'placementId': '5324321' - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '7e5d6af25ed188', - 'bidderRequestId': '55e24a66bed717', - 'auctionId': '1ff753bd4ae5cb', - 'startTime': 1463510220996 + } }, { 'bidder': 'adequant', 'params': { 'publisher_id': '12353433', 'bidfloor': 0.01 - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '4448d80ac1374e', - 'bidderRequestId': '2b1a75d5e826c4', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'triplelift', 'params': { 'inventoryCode': 'inv_code_here' - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '9514d586c52abf', - 'bidderRequestId': '8c4f03b838d7ee', - 'auctionId': '1ff753bd4ae5cb', - 'startTime': 1463510220997 + } }, { 'bidder': 'springserve', @@ -755,21 +714,7 @@ export function getAdUnits() { 'impId': 1234, 'supplyPartnerId': 1, 'test': true - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '113079fed03f58c', - 'bidderRequestId': '1048e0df882e965', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'rubicon', @@ -795,105 +740,33 @@ export function getAdUnits() { 15, 10 ] - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '13c2c2a79d155ea', - 'bidderRequestId': '129e383ac549e5d', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'openx', 'params': { 'jstag_url': 'http://servedbyopenx.com/w/1.0/jstag?nc=account_key', 'unit': 2345677 - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '154f9cbf82df565', - 'bidderRequestId': '1448569c2453b84', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'pubmatic', 'params': { 'publisherId': 1234567, 'adSlot': '1234567@300x250' - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '17f8c3a8fb13308', - 'bidderRequestId': '16095445eeb05e4', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'pagescience', 'params': { 'placementId': '1234567' - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '2074d5757675542', - 'bidderRequestId': '19883380ef5453a', - 'auctionId': '1ff753bd4ae5cb', - 'startTime': 1463510221014 + } }, { 'bidder': 'brealtime', 'params': { 'placementId': '1234567' - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '222b6ad5a9b835d', - 'bidderRequestId': '2163409fdf6f333', - 'auctionId': '1ff753bd4ae5cb', - 'startTime': 1463510221015 + } }, { 'bidder': 'indexExchange', @@ -901,21 +774,7 @@ export function getAdUnits() { 'id': '1', 'siteID': 123456, 'timeout': 10000 - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '2499961ab3f937a', - 'bidderRequestId': '23b57a2de4ae50b', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'adform', @@ -923,82 +782,26 @@ export function getAdUnits() { 'adxDomain': 'adx.adform.net', 'mid': 123456, 'test': 1 - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '26605265bf5e9c5', - 'bidderRequestId': '25a0902299c17d3', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'amazon', 'params': { 'aId': 3080 - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '2935d8f6764fe45', - 'bidderRequestId': '28afa21ca9246c1', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'aol', 'params': { 'network': '112345.45', 'placement': 12345 - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '31d1489681dc539', - 'bidderRequestId': '30bf32da9080fdd', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'sovrn', 'params': { 'tagid': '123556' - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '33c1a8028d91563', - 'bidderRequestId': '324bcb47cfcf034', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'pulsepoint', @@ -1006,41 +809,13 @@ export function getAdUnits() { 'cf': '300X250', 'cp': 1233456, 'ct': 12357 - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '379219f0506a26f', - 'bidderRequestId': '360ec66bbb0719c', - 'auctionId': '1ff753bd4ae5cb' + } }, { 'bidder': 'brightcom', 'params': { 'tagId': 75423 - }, - 'adUnitCode': '/19968336/header-bid-tag-0', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '395cfcf496e7d6d', - 'bidderRequestId': '38a776c7f001ea', - 'auctionId': '1ff753bd4ae5cb' + } } ] } @@ -1055,6 +830,7 @@ export function getBidResponsesFromAPI() { 'bidderCode': 'brightcom', 'width': 300, 'height': 250, + 'mediaType': 'banner', 'statusMessage': 'Bid available', 'adId': '26e0795ab963896', 'cpm': 0.17, @@ -1086,6 +862,7 @@ export function getBidResponsesFromAPI() { 'bidderCode': 'brealtime', 'width': 300, 'height': 250, + 'mediaType': 'banner', 'statusMessage': 'Bid available', 'adId': '275bd666f5a5a5d', 'creative_id': 29681110, @@ -1118,6 +895,7 @@ export function getBidResponsesFromAPI() { 'bidderCode': 'pubmatic', 'width': '300', 'height': '250', + 'mediaType': 'banner', 'statusMessage': 'Bid available', 'adId': '28f4039c636b6a7', 'adSlot': '39620189@300x250', @@ -1151,6 +929,7 @@ export function getBidResponsesFromAPI() { 'bidderCode': 'rubicon', 'width': 300, 'height': 600, + 'mediaType': 'banner', 'statusMessage': 'Bid available', 'adId': '29019e2ab586a5a', 'cpm': 2.74, @@ -1484,3 +1263,64 @@ export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, ad } return bid; } + +export function getServerTestingsAds() { + return [ + { + code: 'test_div_1', + sizes: [[728, 90]], + bids: [ + { + 'bidSource': { 'client': 0, 'server': 100 }, + 'bidder': 'rubicon' + }, + { + 'bidSource': { 'client': 100, 'server': 0 }, + 'bidder': 'appnexus' + } + ] + }, + { + code: 'test_div_2', + sizes: [[300, 250]], + bids: [ + { + 'bidSource': { 'client': 100, 'server': 0 }, + 'bidder': 'rubicon' + }, + { + 'bidSource': { 'client': 100, 'server': 0 }, + 'bidder': 'appnexus' + } + ] + }, + { + code: 'test_div_3', + sizes: [[300, 250]], + bids: [{ bidder: 'adequant' }] + }, + { + code: 'test_div_4', + sizes: [[300, 250]], + bids: [{ bidder: 'openx' }] + } + ]; +}; + +export const getServerTestingConfig = (config, override = {}) => + Object.assign({}, config, { + enabled: true, + testing: true, + testServerOnly: true, + bidders: ['appnexus', 'rubicon', 'openx'], + bidderControl: { + rubicon: { + bidSource: { server: 100, client: 0 }, + includeSourceKvp: true + }, + appnexus: { + bidSource: { server: 0, client: 100 }, + includeSourceKvp: true + } + } + }, override); diff --git a/test/helpers/testing-utils.js b/test/helpers/testing-utils.js index 21d5992873e..76e2b652a79 100644 --- a/test/helpers/testing-utils.js +++ b/test/helpers/testing-utils.js @@ -1,4 +1,13 @@ +/* eslint-disable no-console */ module.exports = { host: (process.env.TEST_SERVER_HOST) ? process.env.TEST_SERVER_HOST : 'localhost', - protocol: (process.env.TEST_SERVER_PROTOCOL) ? 'https' : 'http' + protocol: (process.env.TEST_SERVER_PROTOCOL) ? 'https' : 'http', + waitForElement: function(elementRef, time = 2000) { + let element = $(elementRef); + element.waitForExist({timeout: time}); + }, + switchFrame: function(frameRef, frameName) { + let iframe = $(frameRef); + browser.switchToFrame(iframe); + } } diff --git a/test/mocks/adloaderStub.js b/test/mocks/adloaderStub.js index 9b9e62a4c3b..b52ca5e9280 100644 --- a/test/mocks/adloaderStub.js +++ b/test/mocks/adloaderStub.js @@ -1,23 +1,23 @@ -import * as adloader from 'src/adloader'; +import * as adloader from 'src/adloader.js'; -let sandbox; +// this export is for adloader's tests against actual implementation +export let loadExternalScript = adloader.loadExternalScript; -export let loadScript; -export let loadExternalScript; -export let loadScriptStub; -export let loadExternalScriptStub; +let stub = createStub(); -beforeEach(function() { - sandbox = sinon.sandbox.create(); - loadScript = adloader.loadScript; - loadExternalScript = adloader.loadExternalScript; - loadScriptStub = sandbox.stub(adloader, 'loadScript').callsFake((...args) => { - args[1](); +function createStub() { + return sinon.stub(adloader, 'loadExternalScript').callsFake((...args) => { + if (typeof args[2] === 'function') { + args[2](); + } else if (typeof args[3] === 'function') { + args[3](); + } + return document.createElement('script'); }); - loadExternalScriptStub = sandbox.stub(adloader, 'loadExternalScript'); -}); +} -afterEach(function() { - sandbox.restore(); +beforeEach(function() { + stub.restore(); + stub = createStub(); }); diff --git a/test/mocks/videoCacheStub.js b/test/mocks/videoCacheStub.js index 39f5d67b6a9..7ce899cae35 100644 --- a/test/mocks/videoCacheStub.js +++ b/test/mocks/videoCacheStub.js @@ -1,4 +1,4 @@ -import * as videoCache from 'src/videoCache'; +import * as videoCache from 'src/videoCache.js'; /** * Function which can be called from unit tests to stub out the video cache. diff --git a/test/mocks/xhr.js b/test/mocks/xhr.js new file mode 100644 index 00000000000..9fb8fe87fa0 --- /dev/null +++ b/test/mocks/xhr.js @@ -0,0 +1,9 @@ + +export let server = sinon.createFakeServer(); +export let xhr = global.XMLHttpRequest; + +beforeEach(function() { + server.restore(); + server = sinon.createFakeServer(); + xhr = global.XMLHttpRequest; +}); diff --git a/test/pages/banner.html b/test/pages/banner.html new file mode 100644 index 00000000000..75993cefb39 --- /dev/null +++ b/test/pages/banner.html @@ -0,0 +1,96 @@ + + + + + + + Prebid.js Banner Example + + + + + + + + + + + + + + + +

Prebid.js Banner Ad Unit Test

+
+ +
+
+ + + diff --git a/test/pages/bidderSettings.html b/test/pages/bidderSettings.html new file mode 100644 index 00000000000..015ad3ca45f --- /dev/null +++ b/test/pages/bidderSettings.html @@ -0,0 +1,127 @@ + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+
+ +
+ + + \ No newline at end of file diff --git a/test/pages/consent_mgt_gdpr.html b/test/pages/consent_mgt_gdpr.html new file mode 100644 index 00000000000..02b367b3c7c --- /dev/null +++ b/test/pages/consent_mgt_gdpr.html @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+
+ +
+ + + \ No newline at end of file diff --git a/test/pages/currency.html b/test/pages/currency.html new file mode 100644 index 00000000000..7f196e60d5e --- /dev/null +++ b/test/pages/currency.html @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+
+ +
+ + diff --git a/test/pages/video.html b/test/pages/instream.html similarity index 74% rename from test/pages/video.html rename to test/pages/instream.html index e040b65fe23..c1e2358b754 100644 --- a/test/pages/video.html +++ b/test/pages/instream.html @@ -16,7 +16,7 @@ - + @@ -101,6 +91,7 @@

Prebid Video -- video.js

+