diff --git a/.circleci/config.yml b/.circleci/config.yml index 58e379dced2..ea5fb916a91 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,8 +7,8 @@ aliases: - &environment docker: # specify the version you desire here - - image: circleci/node:8.9.0 - + - image: circleci/node:12.16.1 + resource_class: xlarge # Specify service dependencies here if necessary # CircleCI maintains a library of pre-built images # documented at https://circleci.com/docs/2.0/circleci-images/ @@ -94,4 +94,4 @@ workflows: - e2etest experimental: - pipelines: true \ No newline at end of file + pipelines: true diff --git a/.nvmrc b/.nvmrc index fa97ecedc28..66df3b7ab2d 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -8.9 +12.16.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 016f4055216..962e057fbc5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,6 +6,8 @@ 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). +There are more details available if you'd like to contribute a [bid adapter](https://docs.prebid.org/dev-docs/bidder-adaptor.html) or [analytics adapter](https://docs.prebid.org/dev-docs/integrate-with-the-prebid-analytics-api.html). + ## Issues [prebid.org](http://prebid.org/) contains documentation that may help answer questions you have about using Prebid.js. If you can't find the answer there, try searching for a similar issue on the [issues page](https://github.com/prebid/Prebid.js/issues). diff --git a/PR_REVIEW.md b/PR_REVIEW.md index 3af98f37be0..d7703cf20ae 100644 --- a/PR_REVIEW.md +++ b/PR_REVIEW.md @@ -14,13 +14,17 @@ 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): - - Add support for GDPR consentManagement module > add `gdpr_supported: true` - - Add support for US Privacy consentManagement module > add `usp_supported: true` - - Add support for userId module > add `userId: pubCommon, digitrust, newProviderHere` - - Add support for video and/or native mediaTypes > add `media_types: video, native` - - Add support for COPPA > add `coppa_supported: true` - - Add support for SChain > add `schain_supported: true` + - 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 setting a deal ID in some scenarios, add `bidder_supports_deals: true` + - If they have an IAB Global Vendor List ID, add `gvl_id: ID`. There's no default. - 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. @@ -31,17 +35,17 @@ 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 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. -- Requests to the bidder should support HTTPS -- Responses from the bidder should be compressed (such as gzip, compress, deflate) -- Bid responses may not use JSONP: All requests must be AJAX with JSON responses -- All user-sync (aka pixel) activity must be registered via the provided functions -- Adapters may not use the $$PREBID_GLOBAL$$ variable -- All adapters must support the creation of multiple concurrent instances. This means, for example, that adapters cannot rely on mutable global variables. -- Adapters may not globally override or default the standard ad server targeting values: hb_adid, hb_bidder, hb_pb, hb_deal, or hb_size, hb_source, hb_format. +- All required global and bidder-adapter rules defined in the [Module Rules](https://docs.prebid.org/dev-docs/module-rules.html) must be followed. Please review these rules often - we depend on reviewers to enforce them. +- All bidder parameter conventions must be followed: + - Video params must be read from AdUnit.mediaTypes.video when available; however bidder config can override the ad unit. + - First party data must be read from [`fpd.context` and `fpd.user`](https://docs.prebid.org/dev-docs/publisher-api-reference.html#setConfig-fpd). + - Adapters that accept a floor parameter must also support the [floors module](https://docs.prebid.org/dev-docs/modules/floors.html) -- look for a call to the `getFloors()` function. + - Adapters cannot accept an schain parameter. Rather, they must look for the schain parameter at bidRequest.schain. + - The bidRequest page referrer must checked in addition to any bidder-specific parameter. + - If they're getting the COPPA flag, it must come from config.getConfig('coppa'); + - After a new adapter is approved, let the submitter know they may open a PR in the [headerbid-expert repository](https://github.com/prebid/headerbid-expert) to have their adapter recognized by the [Headerbid Expert extension](https://chrome.google.com/webstore/detail/headerbid-expert/cgfkddgbnfplidghapbbnngaogeldmop). The PR should be to the [bidder patterns file](https://github.com/prebid/headerbid-expert/blob/master/bidderPatterns.js), adding an entry with their adapter's name and the url the adapter uses to send and receive bid responses. ## Ticket Coordinator diff --git a/README.md b/README.md index 0e07521ac3b..44882570d89 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ This README is for developers who want to contribute to Prebid.js. Additional documentation can be found at [the Prebid homepage](http://prebid.org). Working examples can be found in [the developer docs](http://prebid.org/dev-docs/getting-started.html). +Prebid.js is open source software that is offered for free as a convenience. While it is designed to help companies address legal requirements associated with header bidding, we cannot and do not warrant that your use of Prebid.js will satisfy legal requirements. You are solely responsible for ensuring that your use of Prebid.js complies with all applicable laws. We strongly encourage you to obtain legal advice when using Prebid.js to ensure your implementation complies with all laws where you operate. + **Table of Contents** - [Usage](#Usage) @@ -112,7 +114,7 @@ prebid.requestBids({ $ cd Prebid.js $ npm install -*Note:* You need to have `NodeJS` 8.9.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 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. @@ -266,7 +268,7 @@ As you make code changes, the bundles will be rebuilt and the page reloaded auto ## Contribute -Many SSPs, bidders, and publishers have contributed to this project. [60+ Bidders](https://github.com/prebid/Prebid.js/tree/master/src/adapters) are supported by Prebid.js. +Many SSPs, bidders, and publishers have contributed to this project. [Hundreds of bidders](https://github.com/prebid/Prebid.js/tree/master/src/adapters) are supported by Prebid.js. For guidelines, see [Contributing](./CONTRIBUTING.md). @@ -274,9 +276,7 @@ Our PR review process can be found [here](https://github.com/prebid/Prebid.js/tr ### Add a Bidder Adapter -To add a bidder adapter module, see the instructions in [How to add a bidder adaptor](http://prebid.org/dev-docs/bidder-adaptor.html). - -Please **do NOT load Prebid.js inside your adapter**. If you do this, we will reject or remove your adapter as appropriate. +To add a bidder adapter module, see the instructions in [How to add a bidder adapter](https://docs.prebid.org/dev-docs/bidder-adaptor.html). ### Code Quality diff --git a/allowedModules.js b/allowedModules.js index 2a521f781f9..d8e8b69f593 100644 --- a/allowedModules.js +++ b/allowedModules.js @@ -21,7 +21,6 @@ module.exports = { 'fun-hooks/no-eval', 'just-clone', 'dlv', - 'dset', - 'deep-equal' + 'dset' ] }; diff --git a/gulpfile.js b/gulpfile.js index 1b5cd85abd6..879e34ae588 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ 'use strict'; var _ = require('lodash'); @@ -32,8 +33,8 @@ 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 mockServerPort = 4444; -const host = argv.host ? argv.host : 'localhost'; +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 @@ -109,6 +110,7 @@ function watch(done) { connect.server({ https: argv.https, port: port, + host: FAKE_SERVER_HOST, root: './', livereload: true }); @@ -238,25 +240,25 @@ function test(done) { ]; } - //run mock-server - const mockServer = spawn('node', ['./test/mock-server/index.js', '--port=' + mockServerPort]); - mockServer.stdout.on('data', (data) => { + // 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}`); }); - mockServer.stderr.on('data', (data) => { + fakeServer.stderr.on('data', (data) => { console.log(`stderr: ${data}`); }); execa(wdioCmd, wdioOpts, { stdio: 'inherit' }) .then(stdout => { - // kill mock server - mockServer.kill('SIGINT'); + // kill fake server + fakeServer.kill('SIGINT'); done(); process.exit(0); }) .catch(err => { - // kill mock server - mockServer.kill('SIGINT'); + // kill fake server + fakeServer.kill('SIGINT'); done(new Error(`Tests failed with error: ${err}`)); process.exit(1); }); @@ -326,11 +328,27 @@ function setupE2e(done) { done(); } -gulp.task('updatepath', function () { +function injectFakeServerEndpoint() { return gulp.src(['build/dist/*.js']) - .pipe(replace('https://ib.adnxs.com/ut/v3/prebid', 'http://' + host + ':' + mockServerPort + '/')) + .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); @@ -355,9 +373,12 @@ 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-fast', gulp.series(clean, gulp.parallel('build-bundle-dev', watch))); +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-prod', watch), 'updatepath', 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/responsiveAds_sizeMappingV2.html b/integrationExamples/gpt/advanced_size_mapping.html similarity index 62% rename from integrationExamples/gpt/responsiveAds_sizeMappingV2.html rename to integrationExamples/gpt/advanced_size_mapping.html index d262af5199a..4f1ba085c77 100644 --- a/integrationExamples/gpt/responsiveAds_sizeMappingV2.html +++ b/integrationExamples/gpt/advanced_size_mapping.html @@ -1,3 +1,6 @@ + + @@ -8,15 +11,16 @@ const FAILSAFE_TIMEOUT = 3300; const PREBID_TIMEOUT = 1000; + // Example of a multi-format ad unit setup with uses the module `sizeMappingV2.js`. const adUnits = [{ code: 'div-gpt-ad-1460505748561-0', mediaTypes: { banner: { sizeConfig: [ { minViewPort: [0, 0], sizes: [] }, // remove if < 750px - { minViewPort: [750, 0], sizes: [[300, 250], [300, 600]] }, // between 750px and 1199px - { minViewPort: [1200, 0], sizes: [[970, 90], [728, 90], [300, 250]] }, // between 1200px and 1599px - { minViewPort: [1600, 0], sizes: [[1000, 300], [970, 90], [728, 90], [300, 250]] } // greater than 1600px + { minViewPort: [750, 0], sizes: [[300, 250], [300, 600]] }, // between 750px and 1199px, use sizes: [[300, 250], [300, 600]] + { minViewPort: [1200, 0], sizes: [[970, 90], [728, 90], [300, 250]] }, // between 1200px and 1599px, use sizes: [[970, 90], [728, 90], [300, 250]] + { minViewPort: [1600, 0], sizes: [[1000, 300], [970, 90], [728, 90], [300, 250]] } // greater than 1600px, use sizes: [[1000, 300], [970, 90], [728, 90], [300, 250]] ] }, video: { @@ -31,9 +35,9 @@ required: true, sizes: [150, 50] }, - + // native media type enters auction only if device width is > 600px sizeConfig: [ - { minViewPort: [0, 0], active: false }, + { minViewPort: [0, 0], active: false }, { minViewPort: [600, 0], active: true } ] } @@ -54,12 +58,33 @@ siteId: 70608, zoneId: 498816 }, + // example of a bidder level size config. In the scenario below, bidder 'rubicon' enters auction only if the device width + // is between 850-1200 and it'll only send request for the 'native' media type. sizeConfig: [ { minViewPort: [0, 0], relevantMediaTypes: ['none'] }, { minViewPort: [850, 0], relevantMediaTypes: ['native'] }, { minViewPort: [1200, 0], relevantMediaTypes: ['none'] } ] }] + }, { + // Example of an 'Identical Ad Unit' (same 'code' as previous ad unit but different 'mediaTypes' object) + // Ad Unit makes use of the 'labelAll' operator. (the label operators can be applied at the bidder lever as well) + code: 'div-gpt-ad-1460505748561-0', + labelAll: ['tablet'], // Label check fails since labels passed to pbjs.requestBids() equals ['mobile']. This disables the entire ad unit. + mediaTypes: { + banner: { + sizeConfig: [ + { minViewPort: [800, 0], sizes: [[360, 400], [640, 200]] }, + { minViewPort: [1000, 0], sizes: [] } + ] + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 4232323 + } + }] }]; var pbjs = pbjs || {}; pbjs.que = pbjs.que || []; @@ -75,9 +100,11 @@ pbjs.que.push(function () { pbjs.addAdUnits(adUnits); + pbjs.setConfig({debug: true}); pbjs.requestBids({ bidsBackHandler: sendAdserverRequest, - timeout: PREBID_TIMEOUT + timeout: PREBID_TIMEOUT, + labels: ['mobile'] }); }); diff --git a/integrationExamples/gpt/audigentSegments_example.html b/integrationExamples/gpt/audigentSegments_example.html index 9b72da76d23..7739b558327 100644 --- a/integrationExamples/gpt/audigentSegments_example.html +++ b/integrationExamples/gpt/audigentSegments_example.html @@ -162,11 +162,6 @@ params: { // change to Parrable Partner Client ID(s) you received from the Parrable Partners you are using partner: '30182847-e426-4ff9-b2b5-9ca1324ea09b' - }, - storage: { - type: "cookie", - name: "_parrable_eid", // create a cookie with this name - expires: 365 // cookie can last for a year } }, { name: "pubCommonId", diff --git a/integrationExamples/gpt/digitrust_Full.html b/integrationExamples/gpt/digitrust_Full.html deleted file mode 100644 index fc7704776f4..00000000000 --- a/integrationExamples/gpt/digitrust_Full.html +++ /dev/null @@ -1,222 +0,0 @@ - - - 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 deleted file mode 100644 index 2581c6ce7cc..00000000000 --- a/integrationExamples/gpt/digitrust_Simple.html +++ /dev/null @@ -1,230 +0,0 @@ - - - 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 deleted file mode 100644 index 6f0a70188f3..00000000000 --- a/integrationExamples/gpt/digitrust_cmp_test.html +++ /dev/null @@ -1,192 +0,0 @@ - - - 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/jwplayerRtdProvider_example.html b/integrationExamples/gpt/jwplayerRtdProvider_example.html new file mode 100644 index 00000000000..3791ab42137 --- /dev/null +++ b/integrationExamples/gpt/jwplayerRtdProvider_example.html @@ -0,0 +1,98 @@ + + + + + + + JW Player RTD Provider Example + + + + + + + + +
Div-1
+
+ +
+ + diff --git a/integrationExamples/gpt/revcontent_example.html b/integrationExamples/gpt/revcontent_example.html index ad0933885f3..d7a44df3014 100644 --- a/integrationExamples/gpt/revcontent_example.html +++ b/integrationExamples/gpt/revcontent_example.html @@ -45,7 +45,7 @@ apiKey: '8a33fa9cf220ae685dcc3544f847cdda858d3b1c', userId: 673, domain: 'test.com', - endpoint: 'trends-s0.revcontent.com' + endpoint: 'trends.revcontent.com' } }] }]; diff --git a/integrationExamples/gpt/userId_example.html b/integrationExamples/gpt/userId_example.html index 6d2c2ce677a..dddc0915db2 100644 --- a/integrationExamples/gpt/userId_example.html +++ b/integrationExamples/gpt/userId_example.html @@ -83,7 +83,11 @@ var adUnits = [ { code: 'test-div', - sizes: [[300,250],[300,600],[728,90]], + mediaTypes: { + banner: { + sizes: [[300,250],[300,600],[728,90]] + } + }, bids: [ { bidder: 'rubicon', @@ -115,7 +119,7 @@ consentManagement: { cmpApi: 'iab', timeout: 1000, - allowAuctionWithoutConsent: true + defaultGdprScope: true }, // consentManagement: { // cmpApi: 'static', @@ -128,8 +132,32 @@ // } // } // }, - usersync: { + userSync: { userIds: [{ + name: "pubProvidedId", + params: { + eids: [{ + source: "domain.com", + uids:[{ + id: "value read from cookie or local storage", + atype: 1, + ext: { + stype: "ppuid" // allowable options are sha256email, DMP, ppuid for now + } + }] + },{ + source: "3rdpartyprovided.com", + uids:[{ + id: "value read from cookie or local storage", + atype: 3, + ext: { + stype: "sha256email" + } + }] + }], + eidsFunction: getHashedEmail // any user defined function that exists in the page + } + },{ name: "unifiedId", params: { partner: "prebid", @@ -140,7 +168,18 @@ name: "unifiedid", expires: 30 }, - }, { + },{ + name: "intentIqId", + params: { + partner: 0, //Set your real IntentIQ partner ID here for production. + }, + storage: { + type: "cookie", + name: "intentIqId", + 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 @@ -153,15 +192,22 @@ }, }, { + name: "merkleId", + params: { + ptk: '12345678-aaaa-bbbb-cccc-123456789abc', //Set your real merkle partner key here + pubid: 'EXAMPLE' //Set your real merkle publisher id here + }, + storage: { + type: "html5", + name: "merkleId", + expires: 30 + }, + + },{ 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' - }, - storage: { - type: "cookie", - name: "_parrable_eid", // create a cookie with this name - expires: 365 // cookie can last for a year } }, { name: "pubCommonId", @@ -184,9 +230,49 @@ name: 'idl_env', expires: 30 } - }], + }, + { + name: "sharedId", + params: { + syncTime: 60 // in seconds, default is 24 hours + }, + storage: { + type: "cookie", + name: "sharedid", + expires: 28 + } + }, + { + name: 'lotamePanoramaId' + }, + { + name: "liveIntentId", + params: { + publisherId: "9896876" + }, + storage: { + type: "cookie", + name: "_li_pbid", + expires: 28 + } + }, + { + name: "zeotapIdPlus" + }, + { + name: 'haloId', + storage: { + type: "cookie", + name: "haloId", + expires: 28 + } + }, + { + name: "quantcastId" + } + ], syncDelay: 5000, - auctionDelay: 1000 + auctionDelay: 1000 } }); pbjs.addAdUnits(adUnits); diff --git a/integrationExamples/gpt/x-domain/creative.html b/integrationExamples/gpt/x-domain/creative.html index a6981706227..fce46bb380f 100644 --- a/integrationExamples/gpt/x-domain/creative.html +++ b/integrationExamples/gpt/x-domain/creative.html @@ -6,7 +6,6 @@ var urlParser = document.createElement('a'); urlParser.href = '%%PATTERN:url%%'; var publisherDomain = urlParser.protocol + '//' + urlParser.hostname; -var adServerDomain = windowLocation.protocol + '//tpc.googlesyndication.com'; function renderAd(ev) { var key = ev.message ? 'message' : 'data'; @@ -58,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 index f9389686b1f..fb87ea5d990 100644 --- a/integrationExamples/longform/basic_w_bidderSettings.html +++ b/integrationExamples/longform/basic_w_bidderSettings.html @@ -5,6 +5,10 @@ Prebid Freewheel Integration Demo + + + - + + - + + - + + - + @@ -20,10 +24,9 @@ integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> - + - + + - `; + trackedAd += tracker; + }); + } + + return trackedAd; +} + +function getScreenParams() { + return `${window.screen.width}x${window.screen.height}@${window.devicePixelRatio}`; +} + +function getBids(bids) { + const bidArr = bids.map(bid => { + const bidId = bid.bidId; + + let mediaType = ''; + const mediaTypes = Object.keys(bid.mediaTypes) + switch (mediaTypes[0]) { + case 'video': + mediaType = 'v'; + break; + + case 'native': + mediaType = 'n'; + break; + + case 'audio': + mediaType = 'a'; + break; + + default: + mediaType = 'b'; + break; + } + + let adUnitCode = `,c=${bid.adUnitCode}`; + if (bid.params.code) { + adUnitCode = `,c=${encodeURIComponent(bid.params.code)}`; + } + if (bid.params.adunitId) { + adUnitCode = `,u=${encodeURIComponent(bid.params.adunitId)}`; + } + + return `${bidId}:t=${mediaType},s=${serializeSizes(bid.sizes)}${adUnitCode}`; + }); + + return bidArr.join(';'); +}; + +function getEndpointsGroups(bidRequests) { + let endpoints = []; + const getEndpoint = bid => { + const publisherId = bid.params.publisherId || config.getConfig('apstream.publisherId'); + const isTestConfig = bid.params.test || config.getConfig('apstream.test'); + + if (isTestConfig) { + return `https://mock-bapi.userreport.com/v2/${publisherId}/bid`; + } + + if (bid.params.endpoint) { + return `${bid.params.endpoint}${publisherId}/bid`; + } + + return `https://bapi.userreport.com/v2/${publisherId}/bid`; + } + bidRequests.forEach(bid => { + const endpoint = getEndpoint(bid); + const exist = endpoints.filter(item => item.endpoint.indexOf(endpoint) > -1)[0]; + if (exist) { + exist.bids.push(bid); + } else { + endpoints.push({ + endpoint: endpoint, + bids: [bid] + }); + } + }); + + return endpoints; +} + +function isBidRequestValid(bid) { + const publisherId = config.getConfig('apstream.publisherId'); + const isPublisherIdExist = !!(publisherId || bid.params.publisherId); + const isOneMediaType = Object.keys(bid.mediaTypes).length === 1; + + return isPublisherIdExist && isOneMediaType; +} + +function buildRequests(bidRequests, bidderRequest) { + const data = { + med: encodeURIComponent(window.location.href), + auid: bidderRequest.auctionId, + ref: document.referrer, + dnt: utils.getDNT() ? 1 : 0, + sr: getScreenParams() + }; + + const consentData = getRawConsentString(bidderRequest.gdprConsent); + data.iab_consent = consentData; + + const options = { + withCredentials: true + }; + + const isConsent = getIabConsentString(bidderRequest); + const noDsu = config.getConfig('apstream.noDsu'); + if (!isConsent || noDsu) { + data.dsu = ''; + } else { + data.dsu = dsuModule.readOrCreateDsu(); + } + + if (!isConsent || isConsent === 'disabled') { + options.withCredentials = false; + } + + const endpoints = getEndpointsGroups(bidRequests); + const serverRequests = endpoints.map(item => ({ + method: 'GET', + url: item.endpoint, + data: { + ...data, + bids: getBids(item.bids), + rnd: Math.random() + }, + options: options + })); + + return serverRequests; +} + +function interpretResponse(serverResponse) { + let bidResponses = serverResponse && serverResponse.body; + + if (!bidResponses || !bidResponses.length) { + return []; + } + + return bidResponses.map(x => ({ + requestId: x.bidId, + cpm: x.bidDetails.cpm, + width: x.bidDetails.width, + height: x.bidDetails.height, + creativeId: x.bidDetails.creativeId, + currency: x.bidDetails.currency || 'USD', + netRevenue: x.bidDetails.netRevenue, + dealId: x.bidDetails.dealId, + ad: injectPixels(x.bidDetails.ad, x.bidDetails.noticeUrls, x.bidDetails.impressionScripts), + ttl: x.bidDetails.ttl, + })); +} + +export const spec = { + code: CONSTANTS.BIDDER_CODE, + gvlid: CONSTANTS.GVLID, + isBidRequestValid: isBidRequestValid, + buildRequests: buildRequests, + interpretResponse: interpretResponse +} + +registerBidder(spec); diff --git a/modules/apstreamBidAdapter.md b/modules/apstreamBidAdapter.md new file mode 100644 index 00000000000..6b87b33489a --- /dev/null +++ b/modules/apstreamBidAdapter.md @@ -0,0 +1,111 @@ +# Overview + +``` +Module Name: AP Stream Bidder Adapter +Module Type: Bidder Adapter +Maintainer: tech@audienceproject.com +gdpr_supported: true +tcf2_supported: true +``` + +# Description + +Module that connects to AP Stream source + +# Inherit from prebid.js +``` + var adUnits = [ + { + code: '/19968336/header-bid-tag-1', + mediaTypes: { // mandatory and should be only one + banner: { + sizes: [[920,180], [920, 130]] + } + }, + bids: [{ + bidder: 'apstream', + params: { + publisherId: STREAM_PIBLISHER_ID // mandatory + } + }] + } + ]; +``` + +# Explicit ad-unit code +``` + var website = null; + switch (location.hostname) { + case "site1.com": + website = "S1"; + break; + case "site2.com": + website = "S2"; + break; + } + + var adUnits = [ + { + code: '/19968336/header-bid-tag-1', + mediaTypes: { // mandatory and should be only one + banner: { + sizes: [[920,180], [920, 130]] + } + }, + bids: [{ + bidder: 'apstream', + params: { + publisherId: STREAM_PIBLISHER_ID, // mandatory + code: website + '_Leaderboard' + } + }] + } + ]; +``` + +# Explicit ad-unit ID +``` + var adUnits = [ + { + code: '/19968336/header-bid-tag-1', + mediaTypes: { // mandatory and should be only one + banner: { + sizes: [[920,180], [920, 130]] + } + }, + bids: [{ + bidder: 'apstream', + params: { + publisherId: STREAM_PIBLISHER_ID, // mandatory + adunitId: 1234 + } + }] + } + ]; +``` + +# DSU + +To disable DSU use config option: + +``` + pbjs.setConfig({ + apstream: { + noDsu: true + } + }); +``` + +To set `test` and `publisherId` parameters globally use config options (it can be overrided if set in specific bid): + +``` +pbjs.setBidderConfig({ + bidders: ["apstream"], + config: { + appstream: { + publisherId: '1234 + test: true + } + } +}); +``` diff --git a/modules/atsAnalyticsAdapter.js b/modules/atsAnalyticsAdapter.js index 7bf2ca75c17..9811c306738 100644 --- a/modules/atsAnalyticsAdapter.js +++ b/modules/atsAnalyticsAdapter.js @@ -18,7 +18,7 @@ function bidRequestedHandler(args) { bidder: bid.bidder, bid_id: bid.bidId, auction_id: args.auctionId, - user_browser: (browserIsFirefox() || browserIsEdge() || browserIsChrome() || browserIsSafari()), + user_browser: checkUserBrowser(), user_platform: navigator.platform, auction_start: new Date(args.auctionStart).toJSON(), domain: window.location.hostname, @@ -38,6 +38,24 @@ function bidResponseHandler(args) { }; } +export function checkUserBrowser() { + let firefox = browserIsFirefox(); + let chrome = browserIsChrome(); + let edge = browserIsEdge(); + let safari = browserIsSafari(); + if (firefox) { + return firefox; + } if (chrome) { + return chrome; + } if (edge) { + return edge; + } if (safari) { + return safari; + } else { + return 'Unknown' + } +} + export function browserIsFirefox() { if (typeof InstallTrigger !== 'undefined') { return 'Firefox'; @@ -67,7 +85,7 @@ export function browserIsChrome() { } export function browserIsSafari() { - if (navigator.vendor.indexOf('Apple')) { + if (window.safari !== undefined) { return 'Safari' } else { return false; @@ -147,7 +165,8 @@ atsAnalyticsAdapter.enableAnalytics = function (config) { adaptermanager.registerAnalyticsAdapter({ adapter: atsAnalyticsAdapter, - code: 'atsAnalytics' + code: 'atsAnalytics', + gvlid: 97 }); export default atsAnalyticsAdapter; diff --git a/modules/audienceNetworkBidAdapter.js b/modules/audienceNetworkBidAdapter.js deleted file mode 100644 index 816a6abd0e8..00000000000 --- a/modules/audienceNetworkBidAdapter.js +++ /dev/null @@ -1,308 +0,0 @@ -/** - * @file AudienceNetwork adapter. - */ -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'; -const method = 'GET'; -const url = 'https://an.facebook.com/v2/placementbid.json'; -const supportedMediaTypes = ['banner', 'video']; -const netRevenue = true; -const hbBidder = 'fan'; -const ttl = 600; -const videoTtl = 3600; -const platver = '$prebid.version$'; -const platform = '241394079772386'; -const adapterver = '1.3.0'; - -/** - * Does this bid request contain valid parameters? - * @param {Object} bid - * @returns {Boolean} - */ -const isBidRequestValid = bid => - typeof bid.params === 'object' && - typeof bid.params.placementId === 'string' && - bid.params.placementId.length > 0 && - Array.isArray(bid.sizes) && bid.sizes.length > 0 && - (isFullWidth(bid.params.format) ? bid.sizes.map(flattenSize).some(size => size === '300x250') : true) && - (isValidNonSizedFormat(bid.params.format) || bid.sizes.map(flattenSize).some(isValidSize)); - -/** - * Flattens a 2-element [W, H] array as a 'WxH' string, - * otherwise passes value through. - * @param {Array|String} size - * @returns {String} - */ -const flattenSize = size => - (Array.isArray(size) && size.length === 2) ? `${size[0]}x${size[1]}` : size; - -/** - * Expands a 'WxH' string as a 2-element [W, H] array - * @param {String} size - * @returns {Array} - */ -const expandSize = size => size.split('x').map(Number); - -/** - * Is this a valid slot size? - * @param {String} size - * @returns {Boolean} - */ -const isValidSize = size => includes(['300x250', '320x50'], size); - -/** - * Is this a valid, non-sized format? - * @param {String} size - * @returns {Boolean} - */ -const isValidNonSizedFormat = format => includes(['video', 'native'], format); - -/** - * Is this a valid size and format? - * @param {String} size - * @returns {Boolean} - */ -const isValidSizeAndFormat = (size, format) => - (isFullWidth(format) && flattenSize(size) === '300x250') || - isValidNonSizedFormat(format) || - isValidSize(flattenSize(size)); - -/** - * Find a preferred entry, if any, from an array of valid sizes. - * @param {Array} acc - * @param {String} cur - */ -const sortByPreferredSize = (acc, cur) => - (cur === '300x250') ? [cur, ...acc] : [...acc, cur]; - -/** - * Map any deprecated size/formats to new values. - * @param {String} size - * @param {String} format - */ -const mapDeprecatedSizeAndFormat = (size, format) => - isFullWidth(format) ? ['300x250', null] : [size, format]; - -/** - * Is this a video format? - * @param {String} format - * @returns {Boolean} - */ -const isVideo = format => format === 'video'; - -/** - * Is this a fullwidth format? - * @param {String} format - * @returns {Boolean} - */ -const isFullWidth = format => format === 'fullwidth'; - -/** - * Which SDK version should be used for this format? - * @param {String} format - * @returns {String} - */ -const sdkVersion = format => isVideo(format) ? '' : '6.0.web'; - -/** - * Which platform identifier should be used? - * @param {Array} platforms Possible platform identifiers - * @returns {String} First valid platform found, or default if none found - */ -const findPlatform = platforms => [...platforms.filter(Boolean), platform][0]; - -/** - * Does the search part of the URL contain "anhb_testmode" - * and therefore indicate testmode should be used? - * @returns {String} "true" or "false" - */ -const isTestmode = () => Boolean( - window && window.location && - typeof window.location.search === 'string' && - window.location.search.indexOf('anhb_testmode') !== -1 -).toString(); - -/** - * Generate ad HTML for injection into an iframe - * @param {String} placementId - * @param {String} format - * @param {String} bidId - * @returns {String} HTML - */ -const createAdHtml = (placementId, format, bidId) => { - const nativeStyle = format === 'native' ? '' : ''; - const nativeContainer = format === 'native' ? '
' : ''; - return ` - ${nativeStyle} - -
- - - ${nativeContainer} -
- -`; -}; - -/** - * Convert each bid request to a single URL to fetch those bids. - * @param {Array} bids - list of bids - * @param {String} bids[].placementCode - Prebid placement identifier - * @param {Object} bids[].params - * @param {String} bids[].params.placementId - Audience Network placement identifier - * @param {String} bids[].params.platform - Audience Network platform identifier (optional) - * @param {String} bids[].params.format - Optional format, one of 'video' or 'native' if set - * @param {Array} bids[].sizes - list of desired advert sizes - * @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, bidderRequest) => { - // Build lists of placementids, adformats, sizes and SDK versions - const placementids = []; - const adformats = []; - const sizes = []; - const sdk = []; - const platforms = []; - const requestIds = []; - - bids.forEach(bid => bid.sizes - .map(flattenSize) - .filter(size => isValidSizeAndFormat(size, bid.params.format)) - .reduce(sortByPreferredSize, []) - .slice(0, 1) - .forEach(preferredSize => { - const [size, format] = mapDeprecatedSizeAndFormat(preferredSize, bid.params.format); - placementids.push(bid.params.placementId); - adformats.push(format || size); - sizes.push(size); - sdk.push(sdkVersion(format)); - platforms.push(bid.params.platform); - requestIds.push(bid.bidId); - }) - ); - // Build URL - const testmode = isTestmode(); - const pageurl = encodeURIComponent(deepAccess(bidderRequest, 'refererInfo.canonicalUrl') || deepAccess(bidderRequest, 'refererInfo.referer')); - const platform = findPlatform(platforms); - const cb = generateUUID(); - const search = { - placementids, - adformats, - testmode, - pageurl, - sdk, - adapterver, - platform, - platver, - cb - }; - const video = findIndex(adformats, isVideo); - if (video !== -1) { - [search.playerwidth, search.playerheight] = expandSize(sizes[video]); - } - const data = formatQS(search); - - return [{ adformats, data, method, requestIds, sizes, url, pageurl }]; -}; - -/** - * Convert a server response to a bid response. - * @param {Object} response - object representing the response - * @param {Object} response.body - response body, already converted from JSON - * @param {Object} bidRequests - the original bid requests - * @param {Array} bidRequest.adformats - list of formats for the original bid requests - * @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, pageurl }) => { - const { bids = {} } = body; - return Object.keys(bids) - // extract Array of bid responses - .map(placementId => bids[placementId]) - // flatten - .reduce((a, b) => a.concat(b), []) - // transform to bidResponse - .map((bid, i) => { - const { - bid_id: fbBidid, - placement_id: creativeId, - bid_price_cents: cpm - } = bid; - - const format = adformats[i]; - const [width, height] = expandSize(flattenSize(sizes[i])); - const ad = createAdHtml(creativeId, format, fbBidid); - const requestId = requestIds[i]; - - const bidResponse = { - // Prebid attributes - requestId, - cpm: cpm / 100, - width, - height, - ad, - ttl, - creativeId, - netRevenue, - currency, - // Audience Network attributes - hb_bidder: hbBidder, - fb_bidid: fbBidid, - fb_format: format, - fb_placementid: creativeId - }; - // Video attributes - if (isVideo(format)) { - 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; - } - return bidResponse; - }); -}; - -/** - * Covert bid param types for S2S - * @param {Object} params bid params - * @param {Boolean} isOpenRtb boolean to check openrtb2 protocol - * @return {Object} params bid params - */ -const transformBidParams = (params, isOpenRtb) => { - return convertTypes({ - 'placementId': 'string' - }, params); -} - -export const spec = { - code, - supportedMediaTypes, - isBidRequestValid, - buildRequests, - interpretResponse, - transformBidParams -}; - -registerBidder(spec); diff --git a/modules/audienceNetworkBidAdapter.md b/modules/audienceNetworkBidAdapter.md deleted file mode 100644 index 6147191f4b7..00000000000 --- a/modules/audienceNetworkBidAdapter.md +++ /dev/null @@ -1,49 +0,0 @@ -# Overview - -Module Name: Audience Network Bid Adapter - -Module Type: Bidder Adapter - -Maintainer: Lovell Fuller - -# Parameters - -| Name | Scope | Description | Example | -| :------------ | :------- | :---------------------------------------------- | :--------------------------------- | -| `placementId` | required | The Placement ID from Audience Network | "555555555555555\_555555555555555" | -| `format` | optional | Format, one of "native" or "video" | "native" | - -# Example ad units - -```javascript -const adUnits = [{ - code: "test-iab", - sizes: [[300, 250]], - bids: [{ - bidder: "audienceNetwork", - params: { - placementId: "555555555555555_555555555555555" - } - }] -}, { - code: "test-native", - sizes: [[300, 250]], - bids: [{ - bidder: "audienceNetwork", - params: { - format: "native", - placementId: "555555555555555_555555555555555" - } - }] -}, { - code: "test-video", - sizes: [[640, 360]], - bids: [{ - bidder: "audienceNetwork", - params: { - format: "video", - placementId: "555555555555555_555555555555555" - } - }] -}]; -``` diff --git a/modules/automatadBidAdapter.js b/modules/automatadBidAdapter.js index 4a9e6b6a1e4..6b66044f5e5 100644 --- a/modules/automatadBidAdapter.js +++ b/modules/automatadBidAdapter.js @@ -27,17 +27,20 @@ export const spec = { } 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], - })) - }, - })) + const impressions = validBidRequests.map(bidRequest => { + return { + id: bidRequest.bidId, + adUnitCode: bidRequest.adUnitCode, + placement: bidRequest.params.placementId, + banner: { + format: bidRequest.sizes.map(sizeArr => ({ + w: sizeArr[0], + h: sizeArr[1], + })) + }, + } + }) // params from bid request const openrtbRequest = { @@ -45,7 +48,6 @@ export const spec = { imp: impressions, site: { id: siteId, - placement: placementId, domain: window.location.hostname, page: window.location.href, ref: bidderRequest.refererInfo ? bidderRequest.refererInfo.referer || null : null, @@ -69,20 +71,22 @@ export const spec = { 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, + if (response && response.seatbid && response.seatbid[0].bid && response.seatbid[0].bid.length) { + response.seatbid.forEach(bidObj => { + bidObj.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 { @@ -99,15 +103,17 @@ export const spec = { }, 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\}/, - bid.cpm + winCpm ).replace( /\$\{AUCTION_IMP_ID\}/, bid.requestId ).replace( /\$\{AUCTION_CURRENCY\}/, - bid.currency + winCurr ).replace( /\$\{AUCTION_ID\}/, bid.auctionId diff --git a/modules/avocetBidAdapter.js b/modules/avocetBidAdapter.js new file mode 100644 index 00000000000..7a9e5062c0f --- /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 && bidRequests[0].userId.id5id.uid) { + id5id = bidRequests[0].userId.id5id.uid; + } + + // 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 b5ac0321cae..12e78c684ad 100644 --- a/modules/beachfrontBidAdapter.js +++ b/modules/beachfrontBidAdapter.js @@ -6,7 +6,7 @@ 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.9'; +const ADAPTER_VERSION = '1.11'; const ADAPTER_NAME = 'BFIO_PREBID'; const OUTSTREAM = 'outstream'; @@ -272,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, @@ -285,7 +286,8 @@ 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 }], diff --git a/modules/betweenBidAdapter.js b/modules/betweenBidAdapter.js index 72bf592ff77..fb3fcdb8d89 100644 --- a/modules/betweenBidAdapter.js +++ b/modules/betweenBidAdapter.js @@ -1,5 +1,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import { getAdUnitSizes, parseSizesInput } from '../src/utils.js'; +import { getRefererInfo } from '../src/refererDetection.js'; + const BIDDER_CODE = 'between'; export const spec = { @@ -24,6 +26,7 @@ export const spec = { buildRequests: function(validBidRequests, bidderRequest) { let requests = []; const gdprConsent = bidderRequest && bidderRequest.gdprConsent; + const refInfo = getRefererInfo(); validBidRequests.forEach(i => { let params = { @@ -56,6 +59,8 @@ export const spec = { } } + if (refInfo && refInfo.referer) params.ref = refInfo.referer; + if (gdprConsent) { if (typeof gdprConsent.gdprApplies !== 'undefined') { params.gdprApplies = !!gdprConsent.gdprApplies; @@ -107,7 +112,7 @@ export const spec = { if (syncOptions.iframeEnabled) { syncs.push({ type: 'iframe', - url: 'https://acdn.adnxs.com/ib/static/usersync/v3/async_usersync.html' + url: 'https://acdn.adnxs.com/dmp/async_usersync.html' }); } if (syncOptions.pixelEnabled && serverResponses.length > 0) { @@ -119,7 +124,7 @@ export const spec = { // syncs.push({ // type: 'iframe', - // url: 'https://acdn.adnxs.com/ib/static/usersync/v3/async_usersync.html' + // url: 'https://acdn.adnxs.com/dmp/async_usersync.html' // }); syncs.push({ type: 'iframe', diff --git a/modules/bluebillywigBidAdapter.js b/modules/bluebillywigBidAdapter.js index 9e4f5b62e48..afacc48aa8e 100644 --- a/modules/bluebillywigBidAdapter.js +++ b/modules/bluebillywigBidAdapter.js @@ -1,4 +1,5 @@ import * as utils from '../src/utils.js'; +import find from 'core-js-pure/features/array/find.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { VIDEO } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; @@ -17,7 +18,10 @@ const BB_CONSTANTS = { DEFAULT_TTL: 300, DEFAULT_WIDTH: 768, DEFAULT_HEIGHT: 432, - DEFAULT_NET_REVENUE: true + DEFAULT_NET_REVENUE: true, + 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'] }; // Aliasing @@ -26,10 +30,12 @@ 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 if (pageUrl) request.site = { page: pageUrl }; + 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 = {}; @@ -37,21 +43,15 @@ export const BB_HELPERS = { 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); @@ -59,10 +59,6 @@ export const BB_HELPERS = { 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); }, @@ -75,41 +71,59 @@ export const BB_HELPERS = { getRendererUrl: function(publication, renderer) { return BB_HELPERS.substituteUrl(BB_CONSTANTS.RENDERER_URL, publication, renderer); }, - getDigiTrustParams: function(bidRequest) { - const digiTrustId = BB_HELPERS.getDigiTrustId(bidRequest); + transformVideoParams: function(videoParams, videoParamsExt) { + videoParams = utils.deepClone(videoParams); - 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; + let playerSize = videoParams.playerSize || [BB_CONSTANTS.DEFAULT_WIDTH, BB_CONSTANTS.DEFAULT_HEIGHT]; + if (Array.isArray(playerSize[0])) playerSize = playerSize[0]; + + videoParams.w = playerSize[0]; + videoParams.h = playerSize[1]; + videoParams.placement = 3; + + if (videoParamsExt) videoParams = Object.assign(videoParams, videoParamsExt); + + const videoParamsProperties = Object.keys(videoParams); - const digiTrustUser = getConfig('digiTrustId'); - return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || null; + videoParamsProperties.forEach(property => { + if (BB_CONSTANTS.VIDEO_PARAMS.indexOf(property) === -1) delete videoParams[property]; + }); + + return videoParams; }, 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; + const bidObject = { + cpm: bid.price, + currency: serverResponse.cur, + netRevenue: BB_CONSTANTS.DEFAULT_NET_REVENUE, + bidId: bid.impid, + requestId: bid.impid, + creativeId: bid.crid, + mediaType: VIDEO, + width: bid.w || BB_CONSTANTS.DEFAULT_WIDTH, + height: bid.h || BB_CONSTANTS.DEFAULT_HEIGHT, + ttl: BB_CONSTANTS.DEFAULT_TTL + }; + + const extPrebidTargeting = utils.deepAccess(bid, 'ext.prebid.targeting'); + const extPrebidCache = utils.deepAccess(bid, 'ext.prebid.cache'); + + if (extPrebidCache && typeof extPrebidCache.vastXml === 'object' && extPrebidCache.vastXml.cacheId && extPrebidCache.vastXml.url) { + bidObject.videoCacheKey = extPrebidCache.vastXml.cacheId; + bidObject.vastUrl = extPrebidCache.vastXml.url; + } else if (extPrebidTargeting && extPrebidTargeting.hb_uuid && extPrebidTargeting.hb_cache_host && extPrebidTargeting.hb_cache_path) { + bidObject.videoCacheKey = extPrebidTargeting.hb_uuid; + bidObject.vastUrl = `https://${extPrebidTargeting.hb_cache_host}${extPrebidTargeting.hb_cache_path}?uuid=${extPrebidTargeting.hb_uuid}`; + } if (bid.adm) { - bid.ad = bid.adm; - bid.vastXml = bid.adm; - delete bid.adm; + bidObject.ad = bid.adm; + bidObject.vastXml = 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; + if (!bidObject.vastUrl && bid.nurl && !bid.adm) { // ad markup is on win notice url, and adm is ommited according to OpenRTB 2.5 + bidObject.vastUrl = 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; + + return bidObject; }, }; @@ -128,18 +142,14 @@ const BB_RENDERER = { return; } - const rendererId = BB_RENDERER.getRendererId(bid.publicationName, bid.rendererCode); + if (!(window.bluebillywig && window.bluebillywig.renderers)) { + utils.logWarn(`${BB_CONSTANTS.BIDDER_CODE}: renderer code failed to initialize...`); + 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; - } - } + const renderer = find(window.bluebillywig.renderers, r => r._id === rendererId); if (renderer) renderer.bootstrap(config, ele); else utils.logWarn(`${BB_CONSTANTS.BIDDER_CODE}: Couldn't find a renderer with ${rendererId}`); @@ -208,9 +218,8 @@ export const spec = { 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)) { + for (let i = 0; i < bid.params.connections.length; i++) { + if (!bid.params.hasOwnProperty(bid.params.connections[i])) { utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: connection specified in params.connections, but not configured in params. Rejecting bid: `, bid); return false; } @@ -221,6 +230,11 @@ export const spec = { return false; } + if (bid.params.hasOwnProperty('video') && (bid.params.video === null || typeof bid.params.video !== 'object')) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: params.video must be of type object. 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); @@ -241,20 +255,21 @@ export const spec = { buildRequests(validBidRequests, bidderRequest) { const imps = []; - for (let validBidRequestIndex = 0; validBidRequestIndex < validBidRequests.length; validBidRequestIndex++) { - const validBidRequest = validBidRequests[validBidRequestIndex]; - const _this = this; + validBidRequests.forEach(validBidRequest => { + if (!this.syncStore.publicationName) this.syncStore.publicationName = validBidRequest.params.publicationName; + if (!this.syncStore.accountId) this.syncStore.accountId = validBidRequest.params.accountId; - const ext = validBidRequest.params.connections.reduce(function(extBuilder, connection) { + const ext = validBidRequest.params.connections.reduce((extBuilder, connection) => { extBuilder[connection] = validBidRequest.params[connection]; - if (_this.syncStore.bidders.indexOf(connection) === -1) _this.syncStore.bidders.push(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 videoParams = BB_HELPERS.transformVideoParams(utils.deepAccess(validBidRequest, 'mediaTypes.video'), utils.deepAccess(validBidRequest, 'params.video')); + imps.push({ id: validBidRequest.bidId, ext, secure: window.location.protocol === 'https' ? 1 : 0, video: videoParams }); + }); const request = { id: bidderRequest.auctionId, @@ -289,7 +304,6 @@ export const spec = { BB_HELPERS.addSchain(request, validBidRequests); BB_HELPERS.addCurrency(request); BB_HELPERS.addUserIds(request, validBidRequests); - BB_HELPERS.addDigiTrust(request, validBidRequests); return { method: 'POST', @@ -307,74 +321,43 @@ export const spec = { 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; - } - } + serverResponse.seatbid.forEach(seatbid => { + if (!seatbid.bid || !Array.isArray(seatbid.bid)) return; + seatbid.bid.forEach(bid => { + bid = BB_HELPERS.transformRTBToPrebidProps(bid, serverResponse); - if (bidParams) { - bid.publicationName = bidParams.publicationName; - bid.rendererCode = bidParams.rendererCode; - bid.accountId = bidParams.accountId; - } + const bidParams = find(request.bidderRequest.bids, bidderRequestBid => bidderRequestBid.bidId === bid.bidId).params; + 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(`accountId=${this.syncStore.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('&')}`; + const syncUrl = `${BB_HELPERS.getSyncUrl(this.syncStore.publicationName)}&${queryString.join('&')}`; return [{ type: 'iframe', diff --git a/modules/boldwinBidAdapter.js b/modules/boldwinBidAdapter.js new file mode 100644 index 00000000000..04f4085ba24 --- /dev/null +++ b/modules/boldwinBidAdapter.js @@ -0,0 +1,110 @@ +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 = 'boldwin'; +const AD_URL = 'https://ssp.videowalldirect.com/?c=o&m=multi'; +const SYNC_URL = 'https://cs.videowalldirect.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 && bid.native.title && bid.native.image && bid.native.impressionTrackers); + default: + return false; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + + 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 sizes + if (bid.mediaTypes) { + if (bid.mediaTypes[BANNER] && bid.mediaTypes[BANNER].sizes) { + sizes = bid.mediaTypes[BANNER].sizes + } else if (bid.mediaTypes[VIDEO] && bid.mediaTypes[VIDEO].playerSize) { + sizes = bid.mediaTypes[VIDEO].playerSize + } + } + placements.push({ + placementId: bid.params.placementId, + bidId: bid.bidId, + sizes: sizes || [], + wPlayer: sizes ? sizes[0] : 0, + hPlayer: sizes ? sizes[1] : 0, + traffic: bid.params.traffic || BANNER, + 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: () => { + return [{ + type: 'image', + url: SYNC_URL + }]; + } +}; + +registerBidder(spec); diff --git a/modules/boldwinBidAdapter.md b/modules/boldwinBidAdapter.md new file mode 100644 index 00000000000..4bf272c4de3 --- /dev/null +++ b/modules/boldwinBidAdapter.md @@ -0,0 +1,53 @@ +# Overview + +``` +Module Name: boldwin Bidder Adapter +Module Type: boldwin Bidder Adapter +``` + +# Description + +Module that connects to boldwin demand sources + +# Test Parameters +``` + var adUnits = [ + // Will return static test banner + { + code: 'placementId_0', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: 'boldwin', + 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: 'boldwin', + params: { + placementId: 0, + traffic: 'video' + } + } + ] + } + ]; +``` diff --git a/modules/bridgewellBidAdapter.js b/modules/bridgewellBidAdapter.js index 0303e4f74bd..5fca9acc0b3 100644 --- a/modules/bridgewellBidAdapter.js +++ b/modules/bridgewellBidAdapter.js @@ -5,7 +5,7 @@ import find from 'core-js-pure/features/array/find.js'; const BIDDER_CODE = 'bridgewell'; const REQUEST_ENDPOINT = 'https://prebid.scupio.com/recweb/prebid.aspx?cb=' + Math.random(); -const BIDDER_VERSION = '0.0.2'; +const BIDDER_VERSION = '0.0.3'; export const spec = { code: BIDDER_CODE, @@ -19,11 +19,13 @@ export const spec = { */ isBidRequestValid: function (bid) { let valid = false; - - if (bid && bid.params && bid.params.ChannelID) { - valid = true; + if (bid && bid.params) { + if ((bid.params.cid) && (typeof bid.params.cid === 'number')) { + valid = true; + } else if (bid.params.ChannelID) { + valid = true; + } } - return valid; }, @@ -36,15 +38,29 @@ export const spec = { buildRequests: function (validBidRequests, bidderRequest) { const adUnits = []; utils._each(validBidRequests, function (bid) { - adUnits.push({ - ChannelID: bid.params.ChannelID, - adUnitCode: bid.adUnitCode, - mediaTypes: bid.mediaTypes || { - banner: { - sizes: bid.sizes + if (bid.params.cid) { + adUnits.push({ + cid: bid.params.cid, + adUnitCode: bid.adUnitCode, + requestId: bid.bidId, + mediaTypes: bid.mediaTypes || { + banner: { + sizes: bid.sizes + } } - } - }); + }); + } else { + adUnits.push({ + ChannelID: bid.params.ChannelID, + adUnitCode: bid.adUnitCode, + requestId: bid.bidId, + mediaTypes: bid.mediaTypes || { + banner: { + sizes: bid.sizes + } + } + }); + } }); let topUrl = ''; @@ -63,7 +79,8 @@ export const spec = { inIframe: utils.inIframe(), url: topUrl, referrer: getTopWindowReferrer(), - adUnits: adUnits + adUnits: adUnits, + refererInfo: bidderRequest.refererInfo, }, validBidRequests: validBidRequests }; diff --git a/modules/bridgewellBidAdapter.md b/modules/bridgewellBidAdapter.md index 6bcab4b8820..97e11f6eaf9 100644 --- a/modules/bridgewellBidAdapter.md +++ b/modules/bridgewellBidAdapter.md @@ -20,7 +20,7 @@ Module that connects to Bridgewell demand source to fetch bids. bids: [{ bidder: 'bridgewell', params: { - ChannelID: 'CgUxMjMzOBIBNiIFcGVubnkqCQisAhD6ARoBOQ' + cid: 12345 } }] }, { @@ -33,7 +33,7 @@ Module that connects to Bridgewell demand source to fetch bids. bids: [{ bidder: 'bridgewell', params: { - ChannelID: 'CgUxMjMzOBIBNiIGcGVubnkzKggI2AUQWhoBOQ' + cid: 56789 } }] }, { @@ -70,7 +70,7 @@ Module that connects to Bridgewell demand source to fetch bids. bids: [{ bidder: 'bridgewell', params: { - ChannelID: 'CgUxMjMzOBIBNiIGcGVubnkzKggI2AUQWhoBOQ' + cid: 2394 } }] }]; diff --git a/modules/brightMountainMediaBidAdapter.js b/modules/brightMountainMediaBidAdapter.js new file mode 100644 index 00000000000..aa1076e798a --- /dev/null +++ b/modules/brightMountainMediaBidAdapter.js @@ -0,0 +1,89 @@ +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 = 'brightmountainmedia'; +const AD_URL = 'https://console.brightmountainmedia.com/hb/bid'; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + + isBidRequestValid: (bid) => { + return Boolean(bid.bidId && bid.params && bid.params.placement_id); + }, + + 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 : '', + 'secure': 1, + 'host': location.host, + 'page': location.pathname, + 'placements': placements + }; + if (bidderRequest) { + 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.mediaTypes[traff].sizes, + traffic: traff + }; + if (bid.schain) { + placement.schain = bid.schain; + } + placements.push(placement); + } + return { + method: 'POST', + url: AD_URL, + data: request + }; + }, + + interpretResponse: (serverResponse) => { + let response = []; + try { + serverResponse = serverResponse.body; + for (let i = 0; i < serverResponse.length; i++) { + let resItem = serverResponse[i]; + + response.push(resItem); + } + } catch (e) { + utils.logMessage(e); + }; + return response; + }, + + getUserSyncs: (syncOptions) => { + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: 'https://console.brightmountainmedia.com:8443/cookieSync' + }]; + } + }, + +}; + +registerBidder(spec); diff --git a/modules/brightMountainMediaBidAdapter.md b/modules/brightMountainMediaBidAdapter.md new file mode 100644 index 00000000000..a9900b5264d --- /dev/null +++ b/modules/brightMountainMediaBidAdapter.md @@ -0,0 +1,34 @@ +# Overview + +``` +Module Name: Bright Mountain Media Bidder Adapter +Module Type: Bidder Adapter +Maintainer: dev@brightmountainmedia.com +``` + +# Description + +Connects to Bright Mountain Media exchange for bids. + +Bright Mountain Media bid adapter currently supports Banner. + +# Test Parameters +``` + var adUnits = [ + code: 'placementid_0', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [ + { + bidder: 'brightmountainmedia', + params: { + placement_id: '5f21784949be82079d08c', + traffic: 'banner' + } + } + ] + ]; +``` \ No newline at end of file diff --git a/modules/brightcomBidAdapter.js b/modules/brightcomBidAdapter.js index a4b013a2fe2..2aad211b186 100644 --- a/modules/brightcomBidAdapter.js +++ b/modules/brightcomBidAdapter.js @@ -70,6 +70,11 @@ function buildRequests(bidReqs, bidderRequest) { tmax: config.getConfig('bidderTimeout') }; + if (bidderRequest && bidderRequest.gdprConsent) { + utils.deepSetValue(brightcomBidReq, 'regs.ext.gdpr', +bidderRequest.gdprConsent.gdprApplies); + utils.deepSetValue(brightcomBidReq, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + return { method: 'POST', url: URL, diff --git a/modules/britepoolIdSystem.js b/modules/britepoolIdSystem.js index 17a39e96aad..90fd159571f 100644 --- a/modules/britepoolIdSystem.js +++ b/modules/britepoolIdSystem.js @@ -8,6 +8,7 @@ import * as utils from '../src/utils.js' import {ajax} from '../src/ajax.js'; import {submodule} from '../src/hook.js'; +const PIXEL = 'https://px.britepool.com/new?partner_id=t'; /** @type {Submodule} */ export const britepoolIdSubmodule = { @@ -28,7 +29,8 @@ export const britepoolIdSubmodule = { /** * Performs action to obtain id and return a value in the callback's response argument * @function - * @param {SubmoduleParams} [configParams] + * @param {SubmoduleParams} [submoduleConfigParams] + * @param {ConsentData|undefined} consentData * @returns {function(callback:function)} */ getId(submoduleConfigParams, consentData) { @@ -44,6 +46,9 @@ export const britepoolIdSubmodule = { }; } } + if (utils.isEmpty(params)) { + utils.triggerPixel(PIXEL); + } // Return for async operation return { callback: function(callback) { @@ -79,13 +84,17 @@ export const britepoolIdSubmodule = { }, /** * Helper method to create params for our API call - * @param {SubmoduleParams} [configParams] + * @param {SubmoduleParams} [submoduleConfigParams] + * @param {ConsentData|undefined} consentData * @returns {object} Object with parsed out params */ createParams(submoduleConfigParams, consentData) { + const hasGdprData = consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies; + const gdprConsentString = hasGdprData ? consentData.consentString : undefined; let errors = []; const headers = {}; - let params = Object.assign({}, submoduleConfigParams); + const dynamicVars = typeof britepool_pubparams !== 'undefined' ? britepool_pubparams : {}; // eslint-disable-line camelcase, no-undef + let params = Object.assign({}, submoduleConfigParams, dynamicVars); if (params.getter) { // Custom getter will not require other params if (typeof params.getter !== 'function') { @@ -98,7 +107,7 @@ export const britepoolIdSubmodule = { headers['x-api-key'] = params.api_key; } } - const url = params.url || 'https://api.britepool.com/v1/britepool/id'; + const url = params.url || `https://api.britepool.com/v1/britepool/id${gdprConsentString ? '?gdprString=' + encodeURIComponent(gdprConsentString) : ''}`; const getter = params.getter; delete params.api_key; delete params.url; diff --git a/modules/britepoolIdSystem.md b/modules/britepoolIdSystem.md index 89287aed7ca..a15f601aee3 100644 --- a/modules/britepoolIdSystem.md +++ b/modules/britepoolIdSystem.md @@ -7,7 +7,7 @@ BritePool User ID Module. For assistance setting up your module please contact u Individual params may be set for the BritePool User ID Submodule. At least one identifier must be set in the params. ``` pbjs.setConfig({ - usersync: { + userSync: { userIds: [{ name: 'britepoolId', storage: { diff --git a/modules/browsiRtdProvider.js b/modules/browsiRtdProvider.js index 3765b6603af..3aff3c6aac6 100644 --- a/modules/browsiRtdProvider.js +++ b/modules/browsiRtdProvider.js @@ -23,6 +23,7 @@ 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(); @@ -36,6 +37,8 @@ let _moduleParams = {}; let _data = null; /** @type {null | function} */ let _dataReadyCallback = null; +/** @type {string} */ +const DEF_KEYNAME = 'browsiViewability'; /** * add browsi script to page @@ -75,7 +78,7 @@ function collectData() { sk: _moduleParams.siteKey, sw: (win.screen && win.screen.width) || -1, sh: (win.screen && win.screen.height) || -1, - url: encodeURIComponent(`${doc.location.protocol}//${doc.location.host}${doc.location.pathname}`), + url: `${doc.location.protocol}//${doc.location.host}${doc.location.pathname}`, }, ...(browsiData ? {us: browsiData} : {us: '{}'}), ...(document.referrer ? {r: document.referrer} : {}), @@ -116,25 +119,18 @@ function waitForData(callback) { function sendDataToModule(adUnits, onDone) { try { waitForData(_predictionsData => { - const _predictions = _predictionsData.p; - if (!_predictions || !Object.keys(_predictions).length) { - return onDone({}); - } - const slots = getAllSlots(); - if (!slots || !slots.length) { - return onDone({}); - } + const _predictions = _predictionsData.p || {}; let dataToReturn = adUnits.reduce((rp, cau) => { const adUnitCode = cau && cau.code; if (!adUnitCode) { return rp } - const adSlot = getSlotById(adUnitCode); - if (!adSlot) { return rp } - const macroId = getMacroId(_predictionsData.pmd, adUnitCode, adSlot); - const predictionData = _predictions[macroId]; + const adSlot = getSlotByCode(adUnitCode); + const identifier = adSlot ? getMacroId(_predictionsData.pmd, adSlot) : adUnitCode; + const predictionData = _predictions[identifier]; + rp[adUnitCode] = getKVObject(-1, _predictionsData.kn); if (!predictionData) { return rp } if (predictionData.p) { - if (!isIdMatchingAdUnit(adUnitCode, adSlot, predictionData.w)) { + if (!isIdMatchingAdUnit(adSlot, predictionData.w)) { return rp; } rp[adUnitCode] = getKVObject(predictionData.p, _predictionsData.kn); @@ -153,7 +149,7 @@ function sendDataToModule(adUnits, onDone) { * @return {Object[]} slot GoogleTag slots */ function getAllSlots() { - return utils.isGptPubadsDefined && window.googletag.pubads().getSlots(); + return utils.isGptPubadsDefined() && window.googletag.pubads().getSlots(); } /** * get prediction and return valid object for key value set @@ -164,18 +160,17 @@ function getAllSlots() { 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(); + prObject[((_moduleParams['keyName'] || keyName || DEF_KEYNAME).toString())] = prValue.toString(); return prObject; } /** * check if placement id matches one of given ad units - * @param {number} id placement id * @param {Object} slot google slot * @param {string[]} whitelist ad units * @return {boolean} */ -export function isIdMatchingAdUnit(id, slot, whitelist) { - if (!whitelist || !whitelist.length) { +export function isIdMatchingAdUnit(slot, whitelist) { + if (!whitelist || !whitelist.length || !slot) { return true; } const slotAdUnits = slot.getAdUnitPath(); @@ -184,25 +179,24 @@ export function isIdMatchingAdUnit(id, slot, whitelist) { /** * get GPT slot by placement id - * @param {string} id placement id + * @param {string} code placement id * @return {?Object} */ -function getSlotById(id) { +function getSlotByCode(code) { const slots = getAllSlots(); if (!slots || !slots.length) { return null; } - return slots.filter(s => s.getSlotElementId() === id)[0] || null; + return find(slots, s => s.getSlotElementId() === code || s.getAdUnitPath() === code) || null; } /** * generate id according to macro script - * @param {string} macro replacement macro - * @param {string} id placement id + * @param {Object} macro replacement macro * @param {Object} slot google slot * @return {?Object} */ -function getMacroId(macro, id, slot) { +export function getMacroId(macro, slot) { if (macro) { try { const macroResult = evaluate(macro, slot.getSlotElementId(), slot.getAdUnitPath(), (match, p1) => { @@ -213,7 +207,7 @@ function getMacroId(macro, id, slot) { utils.logError(`failed to evaluate: ${macro}`); } } - return id; + return slot.getSlotElementId(); } function evaluate(macro, divId, adUnit, replacer) { @@ -237,7 +231,7 @@ function evaluate(macro, divId, adUnit, replacer) { * @param {string} url server url with query params */ function getPredictionsFromServer(url) { - let ajax = ajaxBuilder(_moduleParams.auctionDelay || _moduleParams.timeout || DEF_TIMEOUT); + let ajax = ajaxBuilder(_moduleParams.auctionDelay || _moduleParams.timeout); ajax(url, { @@ -292,21 +286,26 @@ export const browsiSubmodule = { * @param {adUnit[]} adUnits * @param {function} onDone */ - getData: sendDataToModule + getData: sendDataToModule, + init: init }; -export function init(config) { +function init(config, gdpr, usp) { + return true; +} + +export function beforeInit(config) { const confListener = config.getConfig(MODULE_NAME, ({realTimeData}) => { try { _moduleParams = realTimeData.dataProviders && realTimeData.dataProviders.filter( pr => pr.name && pr.name.toLowerCase() === 'browsi')[0].params; + confListener(); _moduleParams.auctionDelay = realTimeData.auctionDelay; - _moduleParams.timeout = realTimeData.timeout; + _moduleParams.timeout = realTimeData.timeout || DEF_TIMEOUT; } catch (e) { _moduleParams = {}; } if (_moduleParams.siteKey && _moduleParams.pubKey && _moduleParams.url) { - confListener(); collectData(); } else { utils.logError('missing params for Browsi provider'); @@ -314,5 +313,8 @@ export function init(config) { }); } -submodule('realTimeData', browsiSubmodule); -init(config); +function registerSubModule() { + submodule('realTimeData', browsiSubmodule); +} +registerSubModule(); +beforeInit(config); diff --git a/modules/categoryTranslation.js b/modules/categoryTranslation.js index 5342220d13a..9a9289fcd73 100644 --- a/modules/categoryTranslation.js +++ b/modules/categoryTranslation.js @@ -52,8 +52,8 @@ export function getAdserverCategoryHook(fn, adUnitCode, bid) { } 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; @@ -68,23 +68,28 @@ export function getAdserverCategoryHook(fn, adUnitCode, bid) { export function initTranslation(url, localStorageKey) { setupBeforeHookFnOnce(addBidResponse, getAdserverCategoryHook, 50); let mappingData = storage.getDataFromLocalStorage(localStorageKey); - 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'); + 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/cointrafficBidAdapter.js b/modules/cointrafficBidAdapter.js new file mode 100644 index 00000000000..aa6860d1fc6 --- /dev/null +++ b/modules/cointrafficBidAdapter.js @@ -0,0 +1,81 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js' + +const BIDDER_CODE = 'cointraffic'; +const ENDPOINT_URL = 'https://appspb.cointraffic.io/pb/tmp'; + +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: function (bid) { + return !!(bid.params.placementId); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param validBidRequests + * @param bidderRequest + * @return Array Info describing the request to the server. + */ + buildRequests: function (validBidRequests, bidderRequest) { + return validBidRequests.map(bidRequest => { + const sizes = utils.parseSizesInput(bidRequest.params.size || bidRequest.sizes); + + const payload = { + placementId: bidRequest.params.placementId, + sizes: sizes, + bidId: bidRequest.bidId, + referer: bidderRequest.refererInfo.referer, + }; + + return { + method: 'POST', + url: ENDPOINT_URL, + data: payload + }; + }); + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} 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) { + const bidResponses = []; + const response = serverResponse.body; + + if (utils.isEmpty(response)) { + return bidResponses; + } + + const bidResponse = { + requestId: response.requestId, + cpm: response.cpm, + currency: response.currency, + netRevenue: response.netRevenue, + width: response.width, + height: response.height, + creativeId: response.creativeId, + ttl: response.ttl, + ad: response.ad + }; + + bidResponses.push(bidResponse); + + return bidResponses; + } +}; + +registerBidder(spec); diff --git a/modules/cointrafficBidAdapter.md b/modules/cointrafficBidAdapter.md new file mode 100644 index 00000000000..ad608a1319e --- /dev/null +++ b/modules/cointrafficBidAdapter.md @@ -0,0 +1,28 @@ +# Overview + +``` +Module Name: Cointraffic Bidder Adapter +Module Type: Cointraffic Adapter +Maintainer: tech@cointraffic.io +``` + +# Description +The Cointraffic client module makes it easy to implement Cointraffic directly into your website. To get started, simply replace the ``placementId`` with your assigned tracker key. This is dependent on the size required by your account dashboard. For additional information on this module, please contact us at ``support@cointraffic.io``. + +# Test Parameters +``` + var adUnits = [{ + code: 'test-ad-div', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [{ + bidder: 'cointraffic', + params: { + placementId: 'testPlacementId' + } + }] + }]; +``` diff --git a/modules/colombiaBidAdapter.js b/modules/colombiaBidAdapter.js index 59257babdbe..55109dbaab2 100644 --- a/modules/colombiaBidAdapter.js +++ b/modules/colombiaBidAdapter.js @@ -54,7 +54,7 @@ export const spec = { if (width == 320 && height == 50) { cpm = cpm * 0.55; } - if (cpm < 1) { + if (cpm <= 0) { return bidResponses; } if (width !== 0 && height !== 0 && cpm !== 0 && crid !== 0) { diff --git a/modules/colossussspBidAdapter.js b/modules/colossussspBidAdapter.js index baa60a76a0d..a3beb723528 100644 --- a/modules/colossussspBidAdapter.js +++ b/modules/colossussspBidAdapter.js @@ -102,7 +102,7 @@ export const spec = { 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, utils.deepAccess(bid, 'userId.id5id.uid'), 'id5-sync.com', utils.deepAccess(bid, 'userId.id5id.ext')); getUserId(placement.eids, bid.userId.tdid, 'adserver.org', { rtiPartner: 'TDID' }); diff --git a/modules/concertAnalyticsAdapter.js b/modules/concertAnalyticsAdapter.js new file mode 100644 index 00000000000..a81d07e63b5 --- /dev/null +++ b/modules/concertAnalyticsAdapter.js @@ -0,0 +1,120 @@ +import {ajax} from '../src/ajax.js'; +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'; + +const analyticsType = 'endpoint'; + +// We only want to send about 1% of events for sampling purposes +const SAMPLE_RATE_PERCENTAGE = 1 / 100; +const pageIncludedInSample = sampleAnalytics(); + +const url = 'https://bids.concert.io/analytics'; + +const { + EVENTS: { + BID_RESPONSE, + BID_WON, + AUCTION_END + } +} = CONSTANTS; + +let queue = []; + +let concertAnalytics = Object.assign(adapter({url, analyticsType}), { + track({ eventType, args }) { + switch (eventType) { + case BID_RESPONSE: + if (args.bidder !== 'concert') break; + queue.push(mapBidEvent(eventType, args)); + break; + + case BID_WON: + if (args.bidder !== 'concert') break; + queue.push(mapBidEvent(eventType, args)); + break; + + case AUCTION_END: + // Set a delay, as BID_WON events will come after AUCTION_END events + setTimeout(() => sendEvents(), 3000); + break; + + default: + break; + } + } +}); + +function mapBidEvent(eventType, args) { + const { adId, auctionId, cpm, creativeId, width, height, timeToRespond } = args; + const [gamCreativeId, concertRequestId] = getConcertRequestId(creativeId); + + const payload = { + event: eventType, + concert_rid: concertRequestId, + adId, + auctionId, + creativeId: gamCreativeId, + position: args.adUnitCode, + url: window.location.href, + cpm, + width, + height, + timeToRespond + } + + return payload; +} + +/** + * In order to pass back the concert_rid from CBS, it is tucked into the `creativeId` + * slot in the bid response and combined with a pipe `|`. This method splits the creative ID + * and the concert_rid. + * + * @param {string} creativeId + */ +function getConcertRequestId(creativeId) { + if (!creativeId || creativeId.indexOf('|') < 0) return [null, null]; + + return creativeId.split('|'); +} + +function sampleAnalytics() { + return Math.random() <= SAMPLE_RATE_PERCENTAGE; +} + +function sendEvents() { + concertAnalytics.eventsStorage = queue; + + if (!queue.length) return; + + if (!pageIncludedInSample) { + utils.logMessage('Page not included in sample for Concert Analytics'); + return; + } + + try { + const body = JSON.stringify(queue); + ajax(url, () => queue = [], body, { + contentType: 'application/json', + method: 'POST' + }); + } catch (err) { utils.logMessage('Concert Analytics error') } +} + +// save the base class function +concertAnalytics.originEnableAnalytics = concertAnalytics.enableAnalytics; +concertAnalytics.eventsStorage = []; + +// override enableAnalytics so we can get access to the config passed in from the page +concertAnalytics.enableAnalytics = function (config) { + concertAnalytics.originEnableAnalytics(config); +}; + +adapterManager.registerAnalyticsAdapter({ + adapter: concertAnalytics, + code: 'concert' +}); + +export default concertAnalytics; diff --git a/modules/concertAnalyticsAdapter.md b/modules/concertAnalyticsAdapter.md new file mode 100644 index 00000000000..7c9b6d22703 --- /dev/null +++ b/modules/concertAnalyticsAdapter.md @@ -0,0 +1,11 @@ +# Overview + +``` +Module Name: Concert Analytics Adapter +Module Type: Analytics Adapter +Maintainer: support@concert.io +``` + +# Description + +Analytics adapter for concert. \ No newline at end of file diff --git a/modules/concertBidAdapter.js b/modules/concertBidAdapter.js new file mode 100644 index 00000000000..d153ddf9ee2 --- /dev/null +++ b/modules/concertBidAdapter.js @@ -0,0 +1,208 @@ + +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { getStorageManager } from '../src/storageManager.js' + +const BIDDER_CODE = 'concert'; +const CONCERT_ENDPOINT = 'https://bids.concert.io'; +const USER_SYNC_URL = 'https://cdn.concert.io/lib/bids/sync.html'; + +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) { + if (!bid.params.partnerId) { + utils.logWarn('Missing partnerId bid parameter'); + return false; + } + + return true; + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @param {bidderRequest} - + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests, bidderRequest) { + utils.logMessage(validBidRequests); + utils.logMessage(bidderRequest); + let payload = { + meta: { + prebidVersion: '$prebid.version$', + pageUrl: bidderRequest.refererInfo.referer, + screen: [window.screen.width, window.screen.height].join('x'), + debug: utils.debugTurnedOn(), + uid: getUid(bidderRequest), + optedOut: hasOptedOutOfPersonalization(), + adapterVersion: '1.1.0', + uspConsent: bidderRequest.uspConsent, + gdprConsent: bidderRequest.gdprConsent + } + } + + payload.slots = validBidRequests.map(bidRequest => { + let slot = { + name: bidRequest.adUnitCode, + bidId: bidRequest.bidId, + transactionId: bidRequest.transactionId, + sizes: bidRequest.sizes, + partnerId: bidRequest.params.partnerId, + slotType: bidRequest.params.slotType + } + + return slot; + }); + + utils.logMessage(payload); + + return { + method: 'POST', + url: `${CONCERT_ENDPOINT}/bids/prebid`, + data: JSON.stringify(payload) + } + }, + /** + * 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, bidRequest) { + utils.logMessage(serverResponse); + utils.logMessage(bidRequest); + + const serverBody = serverResponse.body; + + if (!serverBody || typeof serverBody !== 'object') { + return []; + } + + let bidResponses = []; + + bidResponses = serverBody.bids.map(bid => { + return { + requestId: bid.bidId, + cpm: bid.cpm, + width: bid.width, + height: bid.height, + ad: bid.ad, + ttl: bid.ttl, + creativeId: bid.creativeId, + netRevenue: bid.netRevenue, + currency: bid.currency + } + }); + + if (utils.debugTurnedOn() && serverBody.debug) { + utils.logMessage(`CONCERT`, serverBody.debug); + } + + utils.logMessage(bidResponses); + 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. + * @param {gdprConsent} object GDPR consent object. + * @param {uspConsent} string US Privacy String. + * @return {UserSync[]} The user syncs which should be dropped. + */ + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { + const syncs = [] + if (syncOptions.iframeEnabled && !hasOptedOutOfPersonalization()) { + let params = []; + + if (gdprConsent && (typeof gdprConsent.gdprApplies === 'boolean')) { + params.push(`gdpr_applies=${gdprConsent.gdprApplies ? '1' : '0'}`); + } + if (gdprConsent && (typeof gdprConsent.consentString === 'string')) { + params.push(`gdpr_consent=${gdprConsent.consentString}`); + } + if (uspConsent && (typeof uspConsent === 'string')) { + params.push(`usp_consent=${uspConsent}`); + } + + syncs.push({ + type: 'iframe', + url: USER_SYNC_URL + (params.length > 0 ? `?${params.join('&')}` : '') + }); + } + return syncs; + }, + + /** + * Register bidder specific code, which will execute if bidder timed out after an auction + * @param {data} Containing timeout specific data + */ + onTimeout: function(data) { + utils.logMessage('concert bidder timed out'); + utils.logMessage(data); + }, + + /** + * Register bidder specific code, which will execute if a bid from this bidder won the auction + * @param {Bid} The bid that won the auction + */ + onBidWon: function(bid) { + utils.logMessage('concert bidder won bid'); + utils.logMessage(bid); + } + +} + +registerBidder(spec); + +const storage = getStorageManager(); + +/** + * Check or generate a UID for the current user. + */ +function getUid(bidderRequest) { + if (hasOptedOutOfPersonalization() || !consentAllowsPpid(bidderRequest)) { + return false; + } + + const CONCERT_UID_KEY = 'c_uid'; + + let uid = storage.getDataFromLocalStorage(CONCERT_UID_KEY); + + if (!uid) { + uid = utils.generateUUID(); + storage.setDataInLocalStorage(CONCERT_UID_KEY, uid); + } + + return uid; +} + +/** + * Whether the user has opted out of personalization. + */ +function hasOptedOutOfPersonalization() { + const CONCERT_NO_PERSONALIZATION_KEY = 'c_nap'; + + return storage.getDataFromLocalStorage(CONCERT_NO_PERSONALIZATION_KEY) === 'true'; +} + +/** + * Whether the privacy consent strings allow personalization. + * + * @param {BidderRequest} bidderRequest Object which contains any data consent signals + */ +function consentAllowsPpid(bidderRequest) { + /* NOTE: We cannot easily test GDPR consent, without the + * `consent-string` npm module; so will have to rely on that + * happening on the bid-server. */ + return !(bidderRequest.uspConsent === 'string' && + bidderRequest.uspConsent.toUpperCase().substring(0, 2) === '1YY') +} diff --git a/modules/concertBidAdapter.md b/modules/concertBidAdapter.md new file mode 100644 index 00000000000..faf774946d1 --- /dev/null +++ b/modules/concertBidAdapter.md @@ -0,0 +1,33 @@ +# Overview + +``` +Module Name: Concert Bid Adapter +Module Type: Bidder Adapter +Maintainer: support@concert.io +``` + +# Description + +Module that connects to Concert demand sources + +# Test Paramters +``` + var adUnits = [ + { + code: 'desktop_leaderboard_variable', + mediaTypes: { + banner: { + sizes: [[1030, 590]] + } + } + bids: [ + { + bidder: "concert", + params: { + partnerId: 'test_partner' + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/modules/connectadBidAdapter.js b/modules/connectadBidAdapter.js index 3dcb8da9838..d1811a1b7d1 100644 --- a/modules/connectadBidAdapter.js +++ b/modules/connectadBidAdapter.js @@ -2,6 +2,7 @@ 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'; +import {createEidsArray} from './userId/eids.js'; const BIDDER_CODE = 'connectad'; const BIDDER_CODE_ALIAS = 'connectadrealtime'; @@ -10,6 +11,7 @@ const SUPPORTED_MEDIA_TYPES = [BANNER]; export const spec = { code: BIDDER_CODE, + gvlid: 138, aliases: [ BIDDER_CODE_ALIAS ], supportedMediaTypes: SUPPORTED_MEDIA_TYPES, @@ -18,8 +20,6 @@ export const spec = { }, buildRequests: function(validBidRequests, bidderRequest) { - let digitrust; - let ret = { method: 'POST', url: '', @@ -41,7 +41,8 @@ export const spec = { screensize: getScreenSize(), dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0, language: navigator.language, - ua: navigator.userAgent + ua: navigator.userAgent, + pversion: '$prebid.version$' }); // coppa compliance @@ -69,81 +70,22 @@ export const spec = { 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 - }] - }); - } + // EIDS Support + if (validBidRequests[0].userId) { + data.user.ext.eids = createEidsArray(validBidRequests[0].userId); } validBidRequests.map(bid => { const placement = Object.assign({ id: bid.transactionId, divName: bid.bidId, + pisze: bid.mediaTypes.banner.sizes[0] || bid.sizes[0], sizes: bid.mediaTypes.banner.sizes, - adTypes: getSize(bid.mediaTypes.banner.sizes || bid.sizes) - }, bid.params); + adTypes: getSize(bid.mediaTypes.banner.sizes || bid.sizes), + bidfloor: getBidFloor(bid), + siteId: bid.params.siteId, + networkId: bid.params.networkId + }); if (placement.networkId && placement.siteId) { data.placements.push(placement); @@ -195,6 +137,13 @@ export const spec = { return bidResponses; }, + transformBidParams: function (params, isOpenRtb) { + return utils.convertTypes({ + 'siteId': 'number', + 'networkId': 'number' + }, params); + }, + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { let syncEndpoint = 'https://cdn.connectad.io/connectmyusers.php?'; @@ -277,6 +226,22 @@ sizeMap[331] = '320x250'; sizeMap[3301] = '320x267'; sizeMap[2730] = '728x250'; +function getBidFloor(bidRequest) { + let floorInfo = {}; + + if (typeof bidRequest.getFloor === 'function') { + floorInfo = bidRequest.getFloor({ + currency: 'USD', + mediaType: 'banner', + size: '*' + }); + } + + let floor = floorInfo.floor || bidRequest.params.bidfloor || bidRequest.params.floorprice || 0; + + return floor; +} + function getSize(sizes) { const result = []; sizes.forEach(function(size) { diff --git a/modules/consentManagement.js b/modules/consentManagement.js index c665eb1a29b..f44fde0554d 100644 --- a/modules/consentManagement.js +++ b/modules/consentManagement.js @@ -14,9 +14,12 @@ const DEFAULT_CMP = 'iab'; const DEFAULT_CONSENT_TIMEOUT = 10000; const DEFAULT_ALLOW_AUCTION_WO_CONSENT = true; +export const allowAuction = { + value: DEFAULT_ALLOW_AUCTION_WO_CONSENT, + definedInConfig: false +} export let userCMP; export let consentTimeout; -export let allowAuction; export let gdprScope; export let staticConsentData; @@ -97,9 +100,7 @@ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { 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) { + if (tcfData.gdprApplies === false || tcfData.eventStatus === 'tcloaded' || tcfData.eventStatus === 'useractioncomplete') { cmpSuccess(tcfData, hookConfig); } } else { @@ -220,7 +221,7 @@ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { window.addEventListener('message', readPostMessageResponse, false); // call CMP - window[apiName](commandName, null, moduleCallback); + window[apiName](commandName, undefined, moduleCallback); function readPostMessageResponse(event) { let cmpDataPkgName = `${apiName}Return`; @@ -301,7 +302,8 @@ function processCmpData(consentObject, hookConfig) { } function checkV2Data() { - let gdprApplies = consentObject && consentObject.gdprApplies; + // 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') || @@ -321,6 +323,13 @@ function processCmpData(consentObject, hookConfig) { // determine which set of checks to run based on cmpVersion let checkFn = (cmpVersion === 1) ? checkV1Data : (cmpVersion === 2) ? checkV2Data : null; + // Raise deprecation warning if 'allowAuctionWithoutConsent' is used with TCF 2. + if (allowAuction.definedInConfig && cmpVersion === 2) { + utils.logWarn(`'allowAuctionWithoutConsent' ignored for TCF 2`); + } else if (!allowAuction.definedInConfig && cmpVersion === 1) { + utils.logInfo(`'allowAuctionWithoutConsent' using system default: (${DEFAULT_ALLOW_AUCTION_WO_CONSENT}).`); + } + if (utils.isFn(checkFn)) { if (checkFn(consentObject)) { cmpFailed(`CMP returned unexpected value during lookup process.`, hookConfig, consentObject); @@ -351,14 +360,14 @@ function cmpFailed(errMsg, hookConfig, extraArgs) { clearTimeout(hookConfig.timer); // still set the consentData to undefined when there is a problem as per config options - if (allowAuction) { + if (allowAuction.value && cmpVersion === 1) { storeConsentData(undefined); } exitModule(errMsg, hookConfig, extraArgs); } /** - * Stores CMP data locally in module and then invokes gdprDataHandler.setConsentData() to make information available in adaptermanger.js for later in the auction + * Stores CMP data locally in module and then invokes gdprDataHandler.setConsentData() to make information available in adaptermanager.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 storeConsentData(cmpConsentObject) { @@ -372,7 +381,10 @@ function storeConsentData(cmpConsentObject) { consentData = { consentString: (cmpConsentObject) ? cmpConsentObject.tcString : undefined, vendorData: (cmpConsentObject) || undefined, - gdprApplies: (cmpConsentObject) ? cmpConsentObject.gdprApplies : gdprScope + gdprApplies: cmpConsentObject && typeof cmpConsentObject.gdprApplies === 'boolean' ? cmpConsentObject.gdprApplies : gdprScope + }; + if (cmpConsentObject && cmpConsentObject.addtlConsent && utils.isStr(cmpConsentObject.addtlConsent)) { + consentData.addtlConsent = cmpConsentObject.addtlConsent; }; } consentData.apiVersion = cmpVersion; @@ -405,8 +417,8 @@ function exitModule(errMsg, hookConfig, extraArgs) { let nextFn = hookConfig.nextFn; if (errMsg) { - if (allowAuction) { - utils.logWarn(errMsg + ' Resuming auction without consent data as per consentManagement config.', extraArgs); + if (allowAuction.value && cmpVersion === 1) { + utils.logWarn(errMsg + ` 'allowAuctionWithoutConsent' activated.`, extraArgs); nextFn.apply(context, args); } else { utils.logError(errMsg + ' Canceling auction as per consentManagement config.', extraArgs); @@ -459,10 +471,8 @@ export function setConsentConfig(config) { } if (typeof config.allowAuctionWithoutConsent === 'boolean') { - allowAuction = config.allowAuctionWithoutConsent; - } else { - allowAuction = DEFAULT_ALLOW_AUCTION_WO_CONSENT; - utils.logInfo(`consentManagement config did not specify allowAuctionWithoutConsent. Using system default setting (${DEFAULT_ALLOW_AUCTION_WO_CONSENT}).`); + allowAuction.value = config.allowAuctionWithoutConsent; + allowAuction.definedInConfig = true; } // if true, then gdprApplies should be set to true diff --git a/modules/consentManagementUsp.js b/modules/consentManagementUsp.js index 1a5879a40ff..e4d5c12eb46 100644 --- a/modules/consentManagementUsp.js +++ b/modules/consentManagementUsp.js @@ -158,11 +158,6 @@ export function requestBidsHook(fn, reqBidsConfigObj) { 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); diff --git a/modules/conversantBidAdapter.js b/modules/conversantBidAdapter.js index 2ecdb2b7e98..3b3d04dc498 100644 --- a/modules/conversantBidAdapter.js +++ b/modules/conversantBidAdapter.js @@ -7,7 +7,7 @@ const GVLID = 24; export const storage = getStorageManager(GVLID); const BIDDER_CODE = 'conversant'; -const URL = 'https://web.hb.ad.cpe.dotomi.com/s2s/header/24'; +const URL = 'https://web.hb.ad.cpe.dotomi.com/cvx/client/hb/ortb/25'; export const spec = { code: BIDDER_CODE, diff --git a/modules/cpmstarBidAdapter.js b/modules/cpmstarBidAdapter.js index 6146e704448..61ccc0e786b 100644 --- a/modules/cpmstarBidAdapter.js +++ b/modules/cpmstarBidAdapter.js @@ -1,7 +1,8 @@ import * as utils from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import {VIDEO, BANNER} from '../src/mediaTypes.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'cpmstar'; @@ -12,17 +13,23 @@ const ENDPOINT_PRODUCTION = 'https://server.cpmstar.com/view.aspx'; const DEFAULT_TTL = 300; const DEFAULT_CURRENCY = 'USD'; +function fixedEncodeURIComponent(str) { + return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { + return '%' + c.charCodeAt(0).toString(16); + }); +} + export const spec = { code: BIDDER_CODE, 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 +53,49 @@ 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 (bidRequest.schain && bidRequest.schain.nodes) { + var schain = bidRequest.schain; + var schainString = ''; + schainString += schain.ver + ',' + schain.complete; + for (var i2 = 0; i2 < schain.nodes.length; i2++) { + var node = schain.nodes[i2]; + schainString += '!' + + fixedEncodeURIComponent(node.asi || '') + ',' + + fixedEncodeURIComponent(node.sid || '') + ',' + + fixedEncodeURIComponent(node.hp || '') + ',' + + fixedEncodeURIComponent(node.rid || '') + ',' + + fixedEncodeURIComponent(node.name || '') + ',' + + fixedEncodeURIComponent(node.domain || ''); + } + url += '&schain=' + schainString + } + + 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, }); } @@ -113,6 +160,21 @@ export const spec = { } return bidResponses; + }, + + getUserSyncs: function (syncOptions, serverResponses) { + const syncs = []; + if (serverResponses.length == 0 || !serverResponses[0].body) return syncs; + var usersyncs = serverResponses[0].body[0].syncs; + if (!usersyncs || usersyncs.length < 0) return syncs; + for (var i = 0; i < usersyncs.length; i++) { + var us = usersyncs[i]; + if ((us.type === 'image' && syncOptions.pixelEnabled) || (us.type == 'iframe' && syncOptions.iframeEnabled)) { + syncs.push(us); + } + } + return syncs; } + }; registerBidder(spec); diff --git a/modules/cpmstarBidAdapter.md b/modules/cpmstarBidAdapter.md old mode 100644 new mode 100755 index 7dab435b0f0..c227f19bfaf --- 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 index 17277ca0fb2..3dabe911884 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -8,7 +8,7 @@ import { verify } from 'criteo-direct-rsa-validate/build/verify.js'; import { getStorageManager } from '../src/storageManager.js'; const GVLID = 91; -export const ADAPTER_VERSION = 31; +export const ADAPTER_VERSION = 32; const BIDDER_CODE = 'criteo'; const CDB_ENDPOINT = 'https://bidder.criteo.com/cdb'; const PROFILE_ID_INLINE = 207; @@ -156,10 +156,16 @@ export const spec = { * @param {TimedOutBid} timeoutData */ onTimeout: (timeoutData) => { - if (publisherTagAvailable()) { - // eslint-disable-next-line no-undef - const adapter = Criteo.PubTag.Adapters.Prebid.GetAdapter(timeoutData.auctionId); - adapter.handleBidTimeout(); + if (publisherTagAvailable() && Array.isArray(timeoutData)) { + var auctionsIds = []; + timeoutData.forEach((bid) => { + if (auctionsIds.indexOf(bid.auctionId) === -1) { + auctionsIds.push(bid.auctionId); + // eslint-disable-next-line no-undef + const adapter = Criteo.PubTag.Adapters.Prebid.GetAdapter(bid.auctionId); + adapter.handleBidTimeout(); + } + }); } }, @@ -167,7 +173,7 @@ export const spec = { * @param {Bid} bid */ onBidWon: (bid) => { - if (publisherTagAvailable()) { + if (publisherTagAvailable() && bid) { // eslint-disable-next-line no-undef const adapter = Criteo.PubTag.Adapters.Prebid.GetAdapter(bid.auctionId); adapter.handleBidWon(bid); @@ -471,10 +477,7 @@ export function tryGetCriteoFastBid() { 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); + eval(publisherTag); // eslint-disable-line no-eval } else { utils.logWarn('Invalid Criteo FastBid found'); storage.removeDataFromLocalStorage(fastBidStorageKey); diff --git a/modules/criteoIdSystem.js b/modules/criteoIdSystem.js index c44f0c843ae..017194d0e86 100644 --- a/modules/criteoIdSystem.js +++ b/modules/criteoIdSystem.js @@ -11,7 +11,9 @@ import { getRefererInfo } from '../src/refererDetection.js' import { submodule } from '../src/hook.js'; import { getStorageManager } from '../src/storageManager.js'; -export const storage = getStorageManager(); +const gvlid = 91; +const bidderCode = 'criteo'; +export const storage = getStorageManager(gvlid, bidderCode); const bididStorageKey = 'cto_bidid'; const bundleStorageKey = 'cto_bundle'; @@ -111,7 +113,8 @@ export const criteoIdSubmodule = { * used to link submodule with config * @type {string} */ - name: 'criteo', + name: bidderCode, + gvlid: gvlid, /** * decode the stored id value for passing to bid requests * @function diff --git a/modules/dailyhuntBidAdapter.js b/modules/dailyhuntBidAdapter.js index 5b28f086938..1018417300a 100644 --- a/modules/dailyhuntBidAdapter.js +++ b/modules/dailyhuntBidAdapter.js @@ -1,55 +1,337 @@ 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]; +const SUPPORTED_MEDIA_TYPES = [mediaTypes.BANNER, mediaTypes.NATIVE, mediaTypes.VIDEO]; -const PROD_PREBID_ENDPOINT_URL = 'https://money.dailyhunt.in/openrtb2/auction'; +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 PROD_ENDPOINT_URL = 'https://money.dailyhunt.in/openx/ads/index.php'; +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 + }, +}; -function buildParams(bid) { - let params = { ...bid.params }; - params.pagetype = 'sources'; - params.placementId = 12345; - params.env = 'prod'; - if (params.testmode && params.testmode === true) { - params.customEvent = 'pb-testmode'; +// 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; + } } - let hasWeb5Size = false; - let hasWeb3Size = false; - bid && bid.sizes && bid.sizes.forEach((size, i) => { - if (!hasWeb3Size && size[0] == 300 && size[1] == 250) { - hasWeb3Size = true; + 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 + } } - if (!hasWeb5Size && (size[0] == 300 || size[0] == 320) && size[1] == 50) { - hasWeb5Size = true; + }; + + // 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, } - }) - params.zone = 'web'; - if (!hasWeb3Size && hasWeb5Size) { - params.subSlots = 'web-5'; } else { - params.subSlots = 'web-3'; + obj = { + mimes: ['video/mp4'], + }; } - if (bid.nativeParams) { - params.subSlots = 'web-3'; - params.ad_type = '2,3'; + obj.ext = { + ...videoObj, } - if (!params.partnerId) { - params.partnerId = 'unknown-pb-partner'; + 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; } - params.pbRequestId = bid.bidId; - params.format = 'json'; - return params; + return videoBid; } -const _encodeURIComponent = function (a) { - let b = window.encodeURIComponent(a); - b = b.replace(/'/g, '%27'); - return b; +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 = { @@ -59,134 +341,55 @@ export const spec = { supportedMediaTypes: SUPPORTED_MEDIA_TYPES, - isBidRequestValid: bid => !!bid.params.partnerId, + isBidRequestValid: bid => !!bid.params.placement_id && !!bid.params.publisher_id && !!bid.params.partner_name, buildRequests: function (validBidRequests, bidderRequest) { let serverRequests = []; - const userAgent = navigator.userAgent; - const page = bidderRequest.refererInfo.referer; - - validBidRequests.forEach((bid, i) => { - let params = buildParams(bid); - let request = ''; - if (bid.nativeParams) { - request = { - method: 'GET', - url: PROD_ENDPOINT_URL, - data: utils.parseQueryStringParameters(params) - }; - } else { - let ortbReq = { - id: bidderRequest.auctionId, - imp: [{ - id: i.toString(), - banner: { - id: 'banner-' + bidderRequest.auctionId, - format: [ - { - 'h': 250, - 'w': 300 - }, - { - 'h': 50, - 'w': 320 - } - ] - }, - bidfloor: 0, - ext: { - dailyhunt: { - ...params - } - } - }], - site: { id: i.toString(), page }, - device: { userAgent }, - user: { - id: params.clientId || '', - } - }; - request = { - method: 'POST', - url: PROD_PREBID_ENDPOINT_URL, - data: JSON.stringify(ortbReq), - options: { - contentType: 'application/json', - withCredentials: true - }, - bids: validBidRequests - }; - } - serverRequests.push(request); + + // 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) { - let bidResponses = []; - if (!request.bids) { - let bid = serverResponse.body[0][0].ad; - if (bid.typeId != 2 && bid.typeId != 3) { - return bidResponses; - } - let impTrackers = []; - impTrackers.push(bid.beaconUrl); - impTrackers = (bid.beaconUrlAdditional && bid.beaconUrlAdditional.length !== 0) ? impTrackers.concat(bid.beaconUrlAdditional) : impTrackers; - let bidResponse = { - requestId: bid.pbRequestId, - cpm: bid.price, - creativeId: bid.bannerid, - currency: 'USD', - ttl: 360, - netRevenue: true, - }; - bidResponse.mediaType = 'native' - bidResponse.native = { - title: bid.content.itemTitle.data, - body: bid.content.itemSubtitle1.data, - body2: bid.content.itemSubtitle1.data, - cta: bid.content.itemSubtitle2.data, - clickUrl: _encodeURIComponent(bid.action), - impressionTrackers: impTrackers, - clickTrackers: bid.landingUrlAdditional && bid.landingUrlAdditional.length !== 0 ? bid.landingUrlAdditional : [], - image: { - url: bid.content.iconLink, - height: bid.height, - width: bid.width - }, - icon: { - url: bid.content.iconLink, - height: bid.height, - width: bid.width - } - } - bidResponses.push(bidResponse); - return bidResponses; - } else { - if (!serverResponse.body) { - return; + 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; } - const { seatbid } = serverResponse.body; - let bids = request.bids; - return bids.reduce((accumulator, bid, index) => { - const _cbid = seatbid && seatbid[index] && seatbid[index].bid; - const bidResponse = _cbid && _cbid[0]; - if (bidResponse) { - accumulator.push({ - requestId: bid.bidId, - cpm: bidResponse.price, - creativeId: bidResponse.crid, - width: bidResponse.w, - height: bidResponse.h, - ttl: 360, - netRevenue: bid.netRevenue === 'net', - currency: 'USD', - ad: bidResponse.adm - }); - } - return accumulator; - }, []); - } + }) + return prebidResponse; }, + + onBidWon: function(bid) { + ajax(bid.winUrl, null, null, { + method: 'GET' + }) + } } + registerBidder(spec); diff --git a/modules/dailyhuntBidAdapter.md b/modules/dailyhuntBidAdapter.md index d860d0817c2..acfd20a4de0 100644 --- a/modules/dailyhuntBidAdapter.md +++ b/modules/dailyhuntBidAdapter.md @@ -10,7 +10,7 @@ Maintainer: Dailyhunt Connects to dailyhunt for bids. -Dailyhunt bid adapter supports Banner and Native. +Dailyhunt bid adapter supports Banner, Native and Video. # Test Parameters ``` @@ -27,7 +27,12 @@ Dailyhunt bid adapter supports Banner and Native. { bidder: 'dailyhunt', params: { - partnerId: 'pb-partnerId' + placement_id: 1, + publisher_id: 1, + partner_name: 'dailyhunt', + device: { + ip: "182.23.143.212" + } } } ] @@ -55,15 +60,42 @@ Dailyhunt bid adapter supports Banner and Native. { bidder: 'dailyhunt', params: { - partnerId: 'pb-partnerId' + 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' + ] + } } } ] } ]; ``` - -# CheckList -``` -https://drive.google.com/open?id=1t4rmcyHl5OmRF3sYiqBi-VKEjzX6iN-A -``` diff --git a/modules/decenteradsBidAdapter.js b/modules/decenteradsBidAdapter.js new file mode 100644 index 00000000000..823a59a3768 --- /dev/null +++ b/modules/decenteradsBidAdapter.js @@ -0,0 +1,90 @@ +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 = 'decenterads' +const URL = 'https://supply.decenterads.com/?c=o&m=multi' +const URL_SYNC = 'https://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.getWindowLocation() + 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.hostname, + 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/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js index 71a8471d554..554c44aa708 100644 --- a/modules/dfpAdServerVideo.js +++ b/modules/dfpAdServerVideo.js @@ -8,6 +8,8 @@ import { deepAccess, isEmpty, logError, parseSizesInput, formatQS, parseUrl, bui import { config } from '../src/config.js'; import { getHook, submodule } from '../src/hook.js'; import { auctionManager } from '../src/auctionManager.js'; +import events from '../src/events.js'; +import CONSTANTS from '../src/constants.json'; /** * @typedef {Object} DfpVideoParams @@ -42,7 +44,7 @@ import { auctionManager } from '../src/auctionManager.js'; const defaultParamConstants = { env: 'vp', gdfp_req: 1, - output: 'xml_vast3', + output: 'vast', unviewed_position_start: 1, }; @@ -82,7 +84,7 @@ export function buildDfpVideoUrl(options) { const derivedParams = { correlator: Date.now(), - sz: parseSizesInput(adUnit.sizes).join('|'), + sz: parseSizesInput(deepAccess(adUnit, 'mediaTypes.video.playerSize')).join('|'), url: encodeURIComponent(location.href), }; const encodedCustomParams = getCustParams(bid, options); @@ -245,17 +247,20 @@ function getCustParams(bid, options) { allTargetingData = (allTargeting) ? allTargeting[adUnit.code] : {}; } - const optCustParams = deepAccess(options, 'params.cust_params'); - let customParams = Object.assign({}, + const prebidTargetingSet = Object.assign({}, // Why are we adding standard keys here ? Refer https://github.com/prebid/Prebid.js/issues/3664 { hb_uuid: bid && bid.videoCacheKey }, // hb_uuid will be deprecated and replaced by hb_cache_id { hb_cache_id: bid && bid.videoCacheKey }, allTargetingData, adserverTargeting, - optCustParams, ); - return encodeURIComponent(formatQS(customParams)); + events.emit(CONSTANTS.EVENTS.SET_TARGETING, {[adUnit.code]: prebidTargetingSet}); + + // merge the prebid + publisher targeting sets + const publisherTargetingSet = deepAccess(options, 'params.cust_params'); + const targetingSet = Object.assign({}, prebidTargetingSet, publisherTargetingSet); + return encodeURIComponent(formatQS(targetingSet)); } registerVideoSupport('dfp', { diff --git a/modules/digiTrustIdSystem.js b/modules/digiTrustIdSystem.js deleted file mode 100644 index d8aa8be9376..00000000000 --- a/modules/digiTrustIdSystem.js +++ /dev/null @@ -1,460 +0,0 @@ -/** - * 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 deleted file mode 100644 index c0b274d3292..00000000000 --- a/modules/digiTrustIdSystem.md +++ /dev/null @@ -1,156 +0,0 @@ -## 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 03dca0b607d..bcb2bb97210 100644 --- a/modules/districtmDMXBidAdapter.js +++ b/modules/districtmDMXBidAdapter.js @@ -1,14 +1,26 @@ import * as utils from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; const BIDDER_CODE = 'districtmDMX'; const DMXURI = 'https://dmx.districtm.io/b/v1'; +const VIDEO_MAPPING = { + playback_method: { + 'auto_play_sound_on': 1, + 'auto_play_sound_off': 2, + 'click_to_play': 3, + 'mouse_over': 4, + 'viewport_sound_on': 5, + 'viewport_sound_off': 6 + } +}; export const spec = { code: BIDDER_CODE, - supportedFormat: ['banner'], + supportedFormat: [BANNER, VIDEO], + supportedMediaTypes: [VIDEO, BANNER], isBidRequestValid(bid) { return !!(bid.params.dmxid && bid.params.memberid); }, @@ -27,14 +39,23 @@ export const spec = { nBid.requestId = nBid.impid; nBid.width = nBid.w || width; nBid.height = nBid.h || height; + nBid.mediaType = bid.mediaTypes && bid.mediaTypes.video ? 'video' : null; + if (nBid.mediaType) { + nBid.vastXml = cleanVast(nBid.adm); + } if (nBid.dealid) { nBid.dealId = nBid.dealid; } + nBid.uuid = nBid.bidId; nBid.ad = nBid.adm; nBid.netRevenue = true; nBid.creativeId = nBid.crid; nBid.currency = 'USD'; nBid.ttl = 60; + nBid.meta = nBid.meta || {}; + if (nBid.adomain && nBid.adomain.length > 0) { + nBid.meta.advertiserDomains = nBid.adomain; + } return nBid; } else { oBid.cpm = oBid.price; @@ -83,12 +104,19 @@ export const spec = { } 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); + if (bidRequest[0] && bidRequest[0].userId) { + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.idl_env`), 'liveramp.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.id5id.uid`), 'id5-sync.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.pubcid`), 'pubcid.org', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.tdid`), 'adserver.org', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.criteoId`), 'criteo.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.britepoolid`), 'britepool.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.lipb.lipbid`), 'liveintent.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.intentiqid`), 'intentiq.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.lotamePanoramaId`), 'lotame.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.parrableId`), 'parrable.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.netId`), 'netid.de', 1); + bindUserId(eids, utils.deepAccess(bidRequest[0], `userId.sharedid`), 'sharedid.org', 1); dmxRequest.user = dmxRequest.user || {}; dmxRequest.user.ext = dmxRequest.user.ext || {}; dmxRequest.user.ext.eids = eids; @@ -122,14 +150,34 @@ export const spec = { obj.id = dmx.bidId; obj.tagid = String(dmx.params.dmxid); obj.secure = 1; - obj.banner = { - topframe: 1, - 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') - }; + obj.bidfloor = getFloor(dmx); + if (dmx.mediaTypes && dmx.mediaTypes.video) { + obj.video = { + topframe: 1, + skip: dmx.mediaTypes.video.skippable || 0, + linearity: dmx.mediaTypes.video.linearity || 1, + minduration: dmx.mediaTypes.video.minduration || 5, + maxduration: dmx.mediaTypes.video.maxduration || 60, + playbackmethod: getPlaybackmethod(dmx.mediaTypes.video.playback_method), + api: getApi(dmx.mediaTypes.video), + mimes: dmx.mediaTypes.video.mimes || ['video/mp4'], + protocols: getProtocols(dmx.mediaTypes.video), + w: dmx.mediaTypes.video.playerSize[0][0], + h: dmx.mediaTypes.video.playerSize[0][1], + format: dmx.mediaTypes.video.playerSize.map(s => { + return {w: s[0], h: s[1]}; + }).filter(obj => typeof obj.w === 'number' && typeof obj.h === 'number') + }; + } else { + obj.banner = { + topframe: 1, + 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; }); @@ -169,6 +217,27 @@ export const spec = { } } +export function getFloor (bid) { + let floor = null; + if (typeof bid.getFloor === 'function') { + const floorInfo = bid.getFloor({ + currency: 'USD', + mediaType: bid.mediaTypes.video ? 'video' : 'banner', + size: bid.sizes.map(size => { + return { + w: size[0], + h: size[1] + } + }) + }); + if (typeof floorInfo === 'object' && + floorInfo.currency === 'USD' && !isNaN(parseFloat(floorInfo.floor))) { + floor = parseFloat(floorInfo.floor); + } + } + return floor !== null ? floor : bid.params.floor; +} + export function cleanSizes(sizes, value) { const supportedSize = [ { @@ -310,4 +379,65 @@ export function bindUserId(eids, value, source, atype) { }) } } + +export function getApi({protocols}) { + let defaultValue = [2]; + let listProtocols = [ + {key: 'VPAID_1_0', value: 1}, + {key: 'VPAID_2_0', value: 2}, + {key: 'MRAID_1', value: 3}, + {key: 'ORMMA', value: 4}, + {key: 'MRAID_2', value: 5}, + {key: 'MRAID_3', value: 6}, + ]; + if (protocols) { + return listProtocols.filter(p => { + return protocols.indexOf(p.key) !== -1; + }).map(p => p.value) + } else { + return defaultValue; + } +} +export function getPlaybackmethod(playback) { + if (Array.isArray(playback) && playback.length > 0) { + return playback.map(label => { + return VIDEO_MAPPING.playback_method[label] + }) + } + return [2] +} + +export function getProtocols({protocols}) { + let defaultValue = [2, 3, 5, 6, 7, 8]; + let listProtocols = [ + {key: 'VAST_1_0', value: 1}, + {key: 'VAST_2_0', value: 2}, + {key: 'VAST_3_0', value: 3}, + {key: 'VAST_1_0_WRAPPER', value: 4}, + {key: 'VAST_2_0_WRAPPER', value: 5}, + {key: 'VAST_3_0_WRAPPER', value: 6}, + {key: 'VAST_4_0', value: 7}, + {key: 'VAST_4_0_WRAPPER', value: 8} + ]; + if (protocols) { + return listProtocols.filter(p => { + return protocols.indexOf(p.key) !== -1 + }).map(p => p.value); + } else { + return defaultValue; + } +} + +export function cleanVast(str) { + const toberemove = /]*?src\s*=\s*['\"]([^'\"]*?)['\"][^>]*?>/ + const [img, url] = str.match(toberemove) + str = str.replace(toberemove, '') + if (img) { + if (url) { + const insrt = `` + str = str.replace('', `${insrt}`) + } + } + return str; +} registerBidder(spec); diff --git a/modules/districtmDmxBidAdapter.md b/modules/districtmDmxBidAdapter.md index 792cf2e7305..5d5dd2affe6 100644 --- a/modules/districtmDmxBidAdapter.md +++ b/modules/districtmDmxBidAdapter.md @@ -20,13 +20,14 @@ The `districtmDmxAdapter` module allows publishers to include DMX Exchange deman ## Media Types * Banner - +* Video ## Bidder Parameters | 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. +| `floor` | Optional | float | Most placement can have floor set in our platform, but this can now be set on the request too. # Ad Unit Configuration Example @@ -48,6 +49,35 @@ The `districtmDmxAdapter` module allows publishers to include DMX Exchange deman }]; ``` +# Ad Unit Configuration Example for video request + +```javascript + var videoAdUnit = { + code: 'video1', + sizes: [640,480], + mediaTypes: { video: {context: 'instream', //or 'outstream' + playerSize: [[640, 480]], + skipppable: true, + minduration: 5, + maxduration: 45, + playback_method: ['auto_play_sound_off', 'viewport_sound_off'], + mimes: ["application/javascript", + "video/mp4"], + + } }, + bids: [ + { + bidder: 'districtmDMX', + params: { + dmxid: '100001', + memberid: '100003', + } + } + + ] + }; +``` + # Ad Unit Configuration when COPPA is needed @@ -117,6 +147,35 @@ Our demand and adapter supports multiple sizes per placement, as such a single d }]; ``` +Our bidder only supports instream context at the moment and we strongly like to put the media types and setting in the ad unit settings. +If no value is set the default value will be applied. + +```javascript + var videoAdUnit = { + code: 'video1', + sizes: [640,480], + mediaTypes: { video: {context: 'instream', //or 'outstream' + playerSize: [[640, 480]], + skipppable: true, + minduration: 5, + maxduration: 45, + playback_method: ['auto_play_sound_off', 'viewport_sound_off'], + mimes: ["application/javascript", + "video/mp4"], + + } }, + bids: [ + { + bidder: 'districtmDMX', + params: { + dmxid: '250258', + memberid: '100600', + } + } + ] + }; +``` + ###### 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`. diff --git a/modules/docereeBidAdapter.md b/modules/docereeBidAdapter.md new file mode 100644 index 00000000000..9e3d4bbe1b8 --- /dev/null +++ b/modules/docereeBidAdapter.md @@ -0,0 +1,32 @@ +# Overview + +Module Name: Doceree Bidder Adapter +Module Type: Bidder Adapter + +# Description + +Connects to Doceree demand source to fetch bids. +Please use ```doceree``` as the bidder code. + +# Test Parameters +``` + var adUnits = [ + { + code: 'desktop-banner-ad-div', + sizes: [[300, 250]], + bids: [ + { + bidder: "doceree", + params: { + accountID: '167283', + zoneID: '445501', + domain: 'adbserver.doceree.com', + extra: { + tuid: '1234-abcd' + } + } + } + ] + }, + ]; +``` diff --git a/modules/dspxBidAdapter.js b/modules/dspxBidAdapter.js index 16764e76ede..d05549601e1 100644 --- a/modules/dspxBidAdapter.js +++ b/modules/dspxBidAdapter.js @@ -1,45 +1,82 @@ 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 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 isDev = params.devMode || false; - let bannerSizes = utils.parseSizesInput(utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes') || bidRequest.sizes); - let [width, height] = bannerSizes[0].split('x'); - 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, + }; + } - const 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; } @@ -75,9 +112,14 @@ export const spec = { currency: currency, netRevenue: netRevenue, type: response.type, - ttl: config.getConfig('_bidderTimeout'), - ad: response.adTag + ttl: config.getConfig('_bidderTimeout') }; + if (response.vastXml) { + bidResponse.vastXml = response.vastXml; + bidResponse.mediaType = 'video'; + } else { + bidResponse.ad = response.adTag; + } bidResponses.push(bidResponse); } return bidResponses; @@ -99,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 9945dc5e6dd..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 3.0 +DSPx adapter for Prebid. # Test Parameters ``` @@ -20,55 +20,46 @@ Dspx adapter for Prebid.js 3.0 sizes: [ [300, 250], [300, 600], - ], // a display size + ] } }, bids: [ { bidder: "dspx", params: { - placement: '101', - devMode: true, // if true: library uses dev server for tests - 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/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/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js index 6688d15d8e9..fa58481548a 100644 --- a/modules/emx_digitalBidAdapter.js +++ b/modules/emx_digitalBidAdapter.js @@ -162,6 +162,7 @@ export const emxAdapter = { export const spec = { code: BIDDER_CODE, + gvlid: 183, supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: function (bid) { if (!bid || !bid.params) { @@ -279,12 +280,21 @@ export const spec = { } return emxBidResponses; }, - getUserSyncs: function (syncOptions) { + getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { const syncs = []; if (syncOptions.iframeEnabled) { + let url = 'https://biddr.brealtime.com/check.html'; + if (gdprConsent && typeof gdprConsent.consentString === 'string') { + // add 'gdpr' only if 'gdprApplies' is defined + if (typeof gdprConsent.gdprApplies === 'boolean') { + url += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + url += `?gdpr_consent=${gdprConsent.consentString}`; + } + } syncs.push({ type: 'iframe', - url: 'https://biddr.brealtime.com/check.html' + url: url }); } return syncs; diff --git a/modules/eplanningBidAdapter.js b/modules/eplanningBidAdapter.js index a4b4f2d6728..ac5ba659ad7 100644 --- a/modules/eplanningBidAdapter.js +++ b/modules/eplanningBidAdapter.js @@ -44,7 +44,7 @@ export const spec = { params = {}; } else { 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); + const referrerUrl = bidderRequest.refererInfo.referer.reachedTop ? window.top.document.referrer : bidderRequest.refererInfo.referer; if (storage.hasLocalStorage()) { registerViewabilityAllBids(bidRequests); @@ -53,7 +53,7 @@ export const spec = { params = { rnd: rnd, e: spaces.str, - ur: encodeURIComponent(pageUrl || FILE), + ur: pageUrl || FILE, r: 'pbjs', pbv: '$prebid.version$', ncb: '1', @@ -317,11 +317,13 @@ function getViewabilityTracker() { } function isNotHiddenByNonFriendlyIframe() { - return (window === window.top) || window.frameElement; + try { return (window === window.top) || window.frameElement; } catch (e) {} } function defineContext(e) { - context = e && window.document.body.contains(e) ? window : (window.top.document.body.contains(e) ? top : undefined); + try { + context = e && window.document.body.contains(e) ? window : (window.top.document.body.contains(e) ? top : undefined); + } catch (err) {} return context; } @@ -357,7 +359,7 @@ function getViewabilityTracker() { } function itIsNotHiddenByTabFocus() { - return getContext().top.document.hasFocus(); + try { return getContext().top.document.hasFocus(); } catch (e) {} } function isDefined(e) { diff --git a/modules/fidelityBidAdapter.js b/modules/fidelityBidAdapter.js index f16a8ea96be..baf5384fbfe 100644 --- a/modules/fidelityBidAdapter.js +++ b/modules/fidelityBidAdapter.js @@ -6,6 +6,7 @@ const BIDDER_SERVER = 'x.fidelity-media.com'; const FIDELITY_VENDOR_ID = 408; export const spec = { code: BIDDER_CODE, + aliases: ['kubient'], gvlid: 408, isBidRequestValid: function isBidRequestValid(bid) { return !!(bid && bid.params && bid.params.zoneid); @@ -110,9 +111,12 @@ function setConsentParams(gdprConsent, uspConsent, 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; diff --git a/modules/freewheel-sspBidAdapter.js b/modules/freewheel-sspBidAdapter.js index e1db7d5e1d3..dce678362cb 100644 --- a/modules/freewheel-sspBidAdapter.js +++ b/modules/freewheel-sspBidAdapter.js @@ -72,7 +72,7 @@ function getPricing(xmlNode) { price: priceNode.textContent || priceNode.innerText }; } else { - utils.logWarn('PREBID - ' + BIDDER_CODE + ': Can\'t get pricing data. Is price awareness enabled?'); + utils.logWarn('PREBID - ' + BIDDER_CODE + ': No bid received or missing pricing extension.'); } return princingData; @@ -261,7 +261,8 @@ export const spec = { reqType: 'AdsSetup', protocolVersion: '2.0', zoneId: zone, - componentId: getComponentId(currentBidRequest.params.format), + componentId: 'prebid', + componentSubId: getComponentId(currentBidRequest.params.format), timestamp: timeInMillis, pKey: keyCode }; diff --git a/modules/gamoshiBidAdapter.js b/modules/gamoshiBidAdapter.js index 1316d74e430..2e09cf55d0a 100644 --- a/modules/gamoshiBidAdapter.js +++ b/modules/gamoshiBidAdapter.js @@ -157,7 +157,7 @@ export const spec = { let eids = []; if (bidRequest && bidRequest.userId) { - addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.id5id`), 'id5-sync.com', 'ID5ID'); + addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.id5id.uid`), 'id5-sync.com', 'ID5ID'); addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.tdid`), 'adserver.org', 'TDID'); } if (eids.length > 0) { diff --git a/modules/gdprEnforcement.js b/modules/gdprEnforcement.js index 4818bbf8ec9..adbccd8666d 100644 --- a/modules/gdprEnforcement.js +++ b/modules/gdprEnforcement.js @@ -11,39 +11,151 @@ 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'; +import events from '../src/events.js'; +import { EVENTS } from '../src/constants.json'; -const purpose1 = 'storage'; +const TCF2 = { + 'purpose1': { id: 1, name: 'storage' }, + 'purpose2': { id: 2, name: 'basicAds' }, + 'purpose7': { id: 7, name: 'measurement' } +} + +/* + These rules would be used if `consentManagement.gdpr.rules` is undefined by the publisher. +*/ +const DEFAULT_RULES = [{ + purpose: 'storage', + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: [] +}, { + purpose: 'basicAds', + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: [] +}]; + +export let purpose1Rule; +export let purpose2Rule; +export let purpose7Rule; + +export let enforcementRules; + +const storageBlocked = []; +const biddersBlocked = []; +const analyticsBlocked = []; let addedDeviceAccessHook = false; -let enforcementRules; -function getGvlid() { - let gvlid; - const bidderCode = config.getCurrentBidder(); +// Helps in stubbing these functions in unit tests. +export const internal = { + getGvlidForBidAdapter, + getGvlidForUserIdModule, + getGvlidForAnalyticsAdapter +}; + +/** + * Returns GVL ID for a Bid adapter / an USERID submodule / an Analytics adapter. + * If modules of different types have the same moduleCode: For example, 'appnexus' is the code for both Bid adapter and Analytics adapter, + * then, we assume that their GVL IDs are same. This function first checks if GVL ID is defined for a Bid adapter, if not found, tries to find User ID + * submodule's GVL ID, if not found, tries to find Analytics adapter's GVL ID. In this process, as soon as it finds a GVL ID, it returns it + * without going to the next check. + * @param {{string|Object}} - module + * @return {number} - GVL ID + */ +export function getGvlid(module) { + let gvlid = null; + if (module) { + // Check user defined GVL Mapping in pbjs.setConfig() + const gvlMapping = config.getConfig('gvlMapping'); + + // For USER ID Module, we pass the submodule object itself as the "module" parameter, this check is required to grab the module code + const moduleCode = typeof module === 'string' ? module : module.name; + + // Return GVL ID from user defined gvlMapping + if (gvlMapping && gvlMapping[moduleCode]) { + gvlid = gvlMapping[moduleCode]; + return gvlid; + } + + gvlid = internal.getGvlidForBidAdapter(moduleCode) || internal.getGvlidForUserIdModule(module) || internal.getGvlidForAnalyticsAdapter(moduleCode); + } + return gvlid; +} + +/** + * Returns GVL ID for a bid adapter. If the adapter does not have an associated GVL ID, it returns 'null'. + * @param {string=} bidderCode - The 'code' property of the Bidder spec. + * @return {number} GVL ID + */ +function getGvlidForBidAdapter(bidderCode) { + let gvlid = null; + bidderCode = bidderCode || config.getCurrentBidder(); if (bidderCode) { const bidder = adapterManager.getBidAdapter(bidderCode); - gvlid = bidder.getSpec().gvlid; - } else { - utils.logWarn('Current module not found'); + if (bidder && bidder.getSpec) { + gvlid = bidder.getSpec().gvlid; + } } 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 GVL ID for an userId submodule. If an userId submodules does not have an associated GVL ID, it returns 'null'. + * @param {Object} userIdModule + * @return {number} GVL ID + */ +function getGvlidForUserIdModule(userIdModule) { + return (typeof userIdModule === 'object' ? userIdModule.gvlid : null); +} + +/** + * Returns GVL ID for an analytics adapter. If an analytics adapter does not have an associated GVL ID, it returns 'null'. + * @param {string} code - 'provider' property on the analytics adapter config + * @return {number} GVL ID + */ +function getGvlidForAnalyticsAdapter(code) { + return adapterManager.getAnalyticsAdapter(code) && (adapterManager.getAnalyticsAdapter(code).gvlid || null); +} + +/** + * This function takes in a rule and consentData and validates against the consentData provided. Depending on what it returns, + * the caller may decide to suppress a TCF-sensitive activity. + * @param {Object} rule - enforcement rules set in config + * @param {Object} consentData - gdpr consent data + * @param {string=} currentModule - Bidder code of the current module + * @param {number=} gvlId - GVL ID for the module * @returns {boolean} */ -function validateRules(rule, consentData, currentModule, gvlid) { - // if vendor has exception => always true +export function validateRules(rule, consentData, currentModule, gvlId) { + const purposeId = TCF2[Object.keys(TCF2).filter(purposeName => TCF2[purposeName].name === rule.purpose)[0]].id; + + // return 'true' if vendor present in 'vendorExceptions' 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; + + // get data from the consent string + const purposeConsent = utils.deepAccess(consentData, `vendorData.purpose.consents.${purposeId}`); + const vendorConsent = utils.deepAccess(consentData, `vendorData.vendor.consents.${gvlId}`); + const liTransparency = utils.deepAccess(consentData, `vendorData.purpose.legitimateInterests.${purposeId}`); + + /* + Since vendor exceptions have already been handled, the purpose as a whole is allowed if it's not being enforced + or the user has consented. Similar with vendors. + */ + const purposeAllowed = rule.enforcePurpose === false || purposeConsent === true; + const vendorAllowed = rule.enforceVendor === false || vendorConsent === true; + + /* + Few if any vendors should be declaring Legitimate Interest for Device Access (Purpose 1), but some are claiming + LI for Basic Ads (Purpose 2). Prebid.js can't check to see who's declaring what legal basis, so if LI has been + established for Purpose 2, allow the auction to take place and let the server sort out the legal basis calculation. + */ + if (purposeId === 2) { + return (purposeAllowed && vendorAllowed) || (liTransparency === true); + } + return purposeAllowed && vendorAllowed; } @@ -65,22 +177,26 @@ export function deviceAccessHook(fn, gvlid, moduleName, result) { const consentData = gdprDataHandler.getConsentData(); if (consentData && consentData.gdprApplies) { if (consentData.apiVersion === 2) { - if (!gvlid) { - gvlid = getGvlid(); + const curBidder = config.getCurrentBidder(); + // Bidders have a copy of storage object with bidder code binded. Aliases will also pass the same bidder code when invoking storage functions and hence if alias tries to access device we will try to grab the gvl id for alias instead of original bidder + if (curBidder && (curBidder != moduleName) && adapterManager.aliasRegistry[curBidder] === moduleName) { + gvlid = getGvlid(curBidder); + } else { + gvlid = getGvlid(moduleName) || gvlid; } - const curModule = moduleName || config.getCurrentBidder(); - const purpose1Rule = find(enforcementRules, hasPurpose1); + const curModule = moduleName || curBidder; 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}`); + curModule && utils.logWarn(`TCF2 denied device access for ${curModule}`); result.valid = false; + storageBlocked.push(curModule); fn.call(this, gvlid, moduleName, result); } } else { - utils.logInfo('Enforcing TCF2 only'); + // The module doesn't enforce TCF1.1 strings result.valid = true; fn.call(this, gvlid, moduleName, result); } @@ -100,21 +216,17 @@ 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}`); - } + const gvlid = getGvlid(curBidder); + let isAllowed = validateRules(purpose1Rule, consentData, curBidder, gvlid); + if (isAllowed) { + fn.call(this, ...args); } else { utils.logWarn(`User sync not allowed for ${curBidder}`); + storageBlocked.push(curBidder); } } else { - utils.logInfo('Enforcing TCF2 only'); + // The module doesn't enforce TCF1.1 strings fn.call(this, ...args); } } else { @@ -132,24 +244,20 @@ 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 gvlid = getGvlid(submodule.submodule); 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`); - } + 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`); + storageBlocked.push(moduleName); } return undefined; }).filter(module => module) - fn.call(this, userIdModules, consentData); + fn.call(this, userIdModules, { ...consentData, hasValidated: true }); } else { - utils.logInfo('Enforcing TCF2 only'); + // The module doesn't enforce TCF1.1 strings fn.call(this, submodules, consentData); } } else { @@ -157,28 +265,137 @@ export function userIdHook(fn, submodules, consentData) { } } -const hasPurpose1 = (rule) => { return rule.purpose === purpose1 } +/** + * Checks if bidders are allowed in the auction. + * Enforces "purpose 2 (Basic Ads)" of TCF v2.0 spec + * @param {Function} fn - Function reference to the original function. + * @param {Array} adUnits + */ +export function makeBidRequestsHook(fn, adUnits, ...args) { + const consentData = gdprDataHandler.getConsentData(); + if (consentData && consentData.gdprApplies) { + if (consentData.apiVersion === 2) { + adUnits.forEach(adUnit => { + adUnit.bids = adUnit.bids.filter(bid => { + const currBidder = bid.bidder; + const gvlId = getGvlid(currBidder); + if (includes(biddersBlocked, currBidder)) return false; + const isAllowed = !!validateRules(purpose2Rule, consentData, currBidder, gvlId); + if (!isAllowed) { + utils.logWarn(`TCF2 blocked auction for ${currBidder}`); + biddersBlocked.push(currBidder); + } + return isAllowed; + }); + }); + fn.call(this, adUnits, ...args); + } else { + // The module doesn't enforce TCF1.1 strings + fn.call(this, adUnits, ...args); + } + } else { + fn.call(this, adUnits, ...args); + } +} + +/** + * Checks if Analytics adapters are allowed to send data to their servers for furhter processing. + * Enforces "purpose 7 (Measurement)" of TCF v2.0 spec + * @param {Function} fn - Function reference to the original function. + * @param {Array} config - Configuration object passed to pbjs.enableAnalytics() + */ +export function enableAnalyticsHook(fn, config) { + const consentData = gdprDataHandler.getConsentData(); + if (consentData && consentData.gdprApplies) { + if (consentData.apiVersion === 2) { + if (!utils.isArray(config)) { + config = [config] + } + config = config.filter(conf => { + const analyticsAdapterCode = conf.provider; + const gvlid = getGvlid(analyticsAdapterCode); + const isAllowed = !!validateRules(purpose7Rule, consentData, analyticsAdapterCode, gvlid); + if (!isAllowed) { + analyticsBlocked.push(analyticsAdapterCode); + utils.logWarn(`TCF2 blocked analytics adapter ${conf.provider}`); + } + return isAllowed; + }); + fn.call(this, config); + } else { + // This module doesn't enforce TCF1.1 strings + fn.call(this, config); + } + } else { + fn.call(this, config); + } +} + +/** + * Compiles the TCF2.0 enforcement results into an object, which is emitted as an event payload to "tcf2Enforcement" event. + */ +function emitTCF2FinalResults() { + // remove null and duplicate values + const formatArray = function (arr) { + return arr.filter((i, k) => i !== null && arr.indexOf(i) === k); + } + const tcf2FinalResults = { + storageBlocked: formatArray(storageBlocked), + biddersBlocked: formatArray(biddersBlocked), + analyticsBlocked: formatArray(analyticsBlocked) + }; + + events.emit(EVENTS.TCF2_ENFORCEMENT, tcf2FinalResults); +} + +events.on(EVENTS.AUCTION_END, emitTCF2FinalResults); + +/* + Set of callback functions used to detect presence of a TCF rule, passed as the second argument to find(). +*/ +const hasPurpose1 = (rule) => { return rule.purpose === TCF2.purpose1.name } +const hasPurpose2 = (rule) => { return rule.purpose === TCF2.purpose2.name } +const hasPurpose7 = (rule) => { return rule.purpose === TCF2.purpose7.name } /** - * A configuration function that initializes some module variables, as well as add hooks - * @param {Object} config GDPR enforcement config object + * A configuration function that initializes some module variables, as well as adds 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; + utils.logWarn('TCF2: enforcing P1 and P2 by default'); + enforcementRules = DEFAULT_RULES; + } else { + enforcementRules = rules; + } + + purpose1Rule = find(enforcementRules, hasPurpose1); + purpose2Rule = find(enforcementRules, hasPurpose2); + purpose7Rule = find(enforcementRules, hasPurpose7); + + if (!purpose1Rule) { + purpose1Rule = DEFAULT_RULES[0]; } - enforcementRules = rules; - const hasDefinedPurpose1 = find(enforcementRules, hasPurpose1); - if (hasDefinedPurpose1 && !addedDeviceAccessHook) { + if (!purpose2Rule) { + purpose2Rule = DEFAULT_RULES[1]; + } + + if (purpose1Rule && !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); } + if (purpose2Rule) { + getHook('makeBidRequests').before(makeBidRequestsHook); + } + + if (purpose7Rule) { + getHook('enableAnalyticsCb').before(enableAnalyticsHook); + } } config.getConfig('consentManagement', config => setEnforcementConfig(config.consentManagement)); diff --git a/modules/gjirafaBidAdapter.js b/modules/gjirafaBidAdapter.js new file mode 100644 index 00000000000..48496b52c05 --- /dev/null +++ b/modules/gjirafaBidAdapter.js @@ -0,0 +1,111 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'gjirafa'; +const ENDPOINT_URL = 'https://central.gjirafa.com/bid'; +const DIMENSION_SEPARATOR = 'x'; +const SIZE_SEPARATOR = ';'; + +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.propertyId && bid.params.placementId); + }, + /** + * 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) { + let propertyId = ''; + let pageViewGuid = ''; + let storageId = ''; + let bidderRequestId = ''; + let url = ''; + let contents = []; + + let placements = validBidRequests.map(bidRequest => { + if (!propertyId) { propertyId = bidRequest.params.propertyId; } + if (!pageViewGuid && bidRequest.params) { pageViewGuid = bidRequest.params.pageViewGuid || ''; } + if (!storageId && bidRequest.params) { storageId = bidRequest.params.storageId || ''; } + if (!bidderRequestId) { bidderRequestId = bidRequest.bidderRequestId; } + if (!url && bidderRequest) { url = bidderRequest.refererInfo.referer; } + if (!contents.length && bidRequest.params.contents && bidRequest.params.contents.length) { contents = bidRequest.params.contents } + + let adUnitId = bidRequest.adUnitCode; + let placementId = bidRequest.params.placementId; + let sizes = generateSizeParam(bidRequest.sizes); + + return { + sizes: sizes, + adUnitId: adUnitId, + placementId: placementId, + bidid: bidRequest.bidId, + }; + }); + + let body = { + propertyId: propertyId, + pageViewGuid: pageViewGuid, + storageId: storageId, + url: url, + requestid: bidderRequestId, + placements: placements, + contents: contents + } + + return [{ + method: 'POST', + url: ENDPOINT_URL, + data: body + }]; + }, + /** + * 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 responses = serverResponse.body; + const bidResponses = []; + for (var i = 0; i < responses.length; i++) { + const bidResponse = { + requestId: responses[i].BidId, + cpm: responses[i].CPM, + width: responses[i].Width, + height: responses[i].Height, + creativeId: responses[i].CreativeId, + currency: responses[i].Currency, + netRevenue: responses[i].NetRevenue, + ttl: responses[i].TTL, + referrer: responses[i].Referrer, + ad: responses[i].Ad, + vastUrl: responses[i].VastUrl, + mediaType: responses[i].MediaType + }; + bidResponses.push(bidResponse); + } + return bidResponses; + } +} + +/** +* Generate size param for bid request using sizes array +* +* @param {Array} sizes Possible sizes for the ad unit. +* @return {string} Processed sizes param to be used for the bid request. +*/ +function generateSizeParam(sizes) { + return sizes.map(size => size.join(DIMENSION_SEPARATOR)).join(SIZE_SEPARATOR); +} + +registerBidder(spec); diff --git a/modules/gjirafaBidAdapter.md b/modules/gjirafaBidAdapter.md index 1ec8222d8de..deb06e74a27 100644 --- a/modules/gjirafaBidAdapter.md +++ b/modules/gjirafaBidAdapter.md @@ -1,36 +1,45 @@ # Overview Module Name: Gjirafa Bidder Adapter Module Type: Bidder Adapter -Maintainer: agonq@gjirafa.com +Maintainer: drilon@gjirafa.com # Description Gjirafa Bidder Adapter for Prebid.js. # Test Parameters var adUnits = [ -{ - code: 'test-div', - sizes: [[728, 90]], // leaderboard - bids: [ - { - bidder: 'gjirafa', - params: { - placementId: '71-3' + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + bids: [ + { + bidder: 'gjirafa', + params: { + propertyId: '105227', + placementId: '846841' + } + } + ] + }, + { + code: 'test-div', + mediaTypes: { + video: { + context: 'instream' } - } - ] -},{ - code: 'test-div', - sizes: [[300, 250]], // mobile rectangle - bids: [ - { - bidder: 'gjirafa', - params: { - minCPM: 0.0001, - minCPC: 0.001, - explicit: true - } - } - ] -} -]; \ No newline at end of file + }, + bids: [ + { + bidder: 'gjirafa', + params: { + propertyId: '105227', + placementId: '846836' + } + } + ] + } +]; diff --git a/modules/glimpseBidAdapter.js b/modules/glimpseBidAdapter.js new file mode 100644 index 00000000000..969c04bb451 --- /dev/null +++ b/modules/glimpseBidAdapter.js @@ -0,0 +1,58 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'glimpse'; + +export const spec = { + code: BIDDER_CODE, + url: 'https://api.glimpseprotocol.io/cloud/v1/vault/prebid', + supportedMediaTypes: [BANNER], + + isBidRequestValid: (bid) => { + try { + const { placementId } = bid.params; + return typeof placementId === 'string' && placementId.length > 0; + } catch (error) { + return false; + } + }, + + buildRequests: (validBidRequests, bidderRequest) => { + const { url, code: bidderCode } = spec; + + const bids = validBidRequests.map((request) => { + delete request.mediaTypes; + return request; + }); + + const sdk = { + source: 'pbjs', + version: '$prebid.version$', + }; + + const payload = { + ...bidderRequest, + bidderCode, + bids, + sdk, + }; + + return { + method: 'POST', + url, + data: JSON.stringify(payload), + }; + }, + + interpretResponse: (serverResponse, _) => { + const bids = []; + try { + const { body } = serverResponse; + bids.push(...body); + } catch (error) {} + + return bids; + }, +}; + +registerBidder(spec); diff --git a/modules/glimpseBidAdapter.md b/modules/glimpseBidAdapter.md new file mode 100644 index 00000000000..024cc9ebfa7 --- /dev/null +++ b/modules/glimpseBidAdapter.md @@ -0,0 +1,101 @@ +# Overview + +``` +Module Name: Glimpse Protocol Bid Adapter +Module Type: Bidder Adapter +Maintainer: hello@glimpseprotocol.io +``` + +# Description + +This module connects publishers to Glimpse Protocol's demand sources via Prebid.js. Our innovative marketplace protects +consumer privacy while allowing precise targeting. It is compliant with GDPR, DPA and CCPA. + +This adapter supports Banner. + +# Test Parameters + +```javascript +var adUnits = [ + { + code: 'banner-div-a', + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + bids: [ + { + bidder: 'glimpse', + params: { + placementId: 'glimpse-demo-300x250', + }, + }, + ], + }, + { + code: 'banner-div-b', + mediaTypes: { + banner: { + sizes: [[320, 50]], + }, + }, + bids: [ + { + bidder: 'glimpse', + params: { + placementId: 'glimpse-demo-320x50', + }, + }, + ], + }, + { + code: 'banner-div-c', + mediaTypes: { + banner: { + sizes: [[970, 250]], + }, + }, + bids: [ + { + bidder: 'glimpse', + params: { + placementId: 'glimpse-demo-970x250', + }, + }, + ], + }, + { + code: 'banner-div-d', + mediaTypes: { + banner: { + sizes: [[728, 90]], + }, + }, + bids: [ + { + bidder: 'glimpse', + params: { + placementId: 'glimpse-demo-728x90', + }, + }, + ], + }, + { + code: 'banner-div-e', + mediaTypes: { + banner: { + sizes: [[300, 600]], + }, + }, + bids: [ + { + bidder: 'glimpse', + params: { + placementId: 'glimpse-demo-300x600', + }, + }, + ], + }, +]; +``` diff --git a/modules/gmosspBidAdapter.js b/modules/gmosspBidAdapter.js new file mode 100644 index 00000000000..d9dc8f7641a --- /dev/null +++ b/modules/gmosspBidAdapter.js @@ -0,0 +1,134 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { BANNER } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'gmossp'; +const ENDPOINT = 'https://sp.gmossp-sp.jp/hb/prebid/query.ad'; + +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: function (bid) { + return !!(bid.params.sid); + }, + + /** + * 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) { + const bidRequests = []; + + const url = bidderRequest.refererInfo.referer; + const cur = getCurrencyType(); + const dnt = utils.getDNT() ? '1' : '0'; + + for (let i = 0; i < validBidRequests.length; i++) { + let queryString = ''; + + const request = validBidRequests[i]; + const tid = request.transactionId; + const bid = request.bidId; + const ver = '$prebid.version$'; + const sid = utils.getBidIdParameter('sid', request.params); + + queryString = utils.tryAppendQueryString(queryString, 'tid', tid); + queryString = utils.tryAppendQueryString(queryString, 'bid', bid); + queryString = utils.tryAppendQueryString(queryString, 'ver', ver); + queryString = utils.tryAppendQueryString(queryString, 'sid', sid); + queryString = utils.tryAppendQueryString(queryString, 'url', url); + queryString = utils.tryAppendQueryString(queryString, 'cur', cur); + queryString = utils.tryAppendQueryString(queryString, 'dnt', dnt); + + bidRequests.push({ + method: 'GET', + url: ENDPOINT, + data: queryString + }); + } + return bidRequests; + }, + + /** + * 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 (bidderResponse, requests) { + const res = bidderResponse.body; + + if (utils.isEmpty(res)) { + return []; + } + + try { + res.imps.forEach(impTracker => { + const tracker = utils.createTrackPixelHtml(impTracker); + res.ad += tracker; + }); + } catch (error) { + utils.logError('Error appending tracking pixel', error); + } + + const bid = { + requestId: res.bid, + cpm: res.price, + currency: res.cur, + width: res.w, + height: res.h, + ad: res.ad, + creativeId: res.creativeId, + netRevenue: true, + ttl: res.ttl || 300 + }; + + return [bid]; + }, + + /** + * 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) { + const syncs = []; + if (!serverResponses.length) { + return syncs; + } + + serverResponses.forEach(res => { + if (syncOptions.pixelEnabled && res.body && res.body.syncs.length) { + res.body.syncs.forEach(sync => { + syncs.push({ + type: 'image', + url: sync + }) + }) + } + }) + return syncs; + }, + +}; + +function getCurrencyType() { + if (config.getConfig('currency.adServerCurrency')) { + return config.getConfig('currency.adServerCurrency'); + } + return 'JPY'; +} + +registerBidder(spec); diff --git a/modules/gmosspBidAdapter.md b/modules/gmosspBidAdapter.md new file mode 100644 index 00000000000..4f63582ef9a --- /dev/null +++ b/modules/gmosspBidAdapter.md @@ -0,0 +1,36 @@ +# Overview + +``` +Module Name: GMOSSP Bid Adapter +Module Type: Bidder Adapter +Maintainer: dev@ml.gmo-am.jp +``` + +# Description +Connects to GMOSSP exchange for bids. +GMOSSP bid adapter supports Banner. + +# Test Parameters +``` +var adUnits = [ + // Banner adUnit + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [320, 50], + [320, 100] + ] + } + }, + bids: [{ + bidder: 'gmossp', + params: { + sid: '61590' + } + }] + } +]; +``` \ No newline at end of file diff --git a/modules/gptPreAuction.js b/modules/gptPreAuction.js new file mode 100644 index 00000000000..48b72671d6a --- /dev/null +++ b/modules/gptPreAuction.js @@ -0,0 +1,101 @@ +import { config } from '../src/config.js'; +import * as utils from '../src/utils.js'; +import { getHook } from '../src/hook.js'; +import find from 'core-js-pure/features/array/find.js'; + +const MODULE_NAME = 'GPT Pre-Auction'; +export let _currentConfig = {}; +let hooksAdded = false; + +export const appendGptSlots = adUnits => { + const { customGptSlotMatching } = _currentConfig; + + if (!utils.isGptPubadsDefined()) { + return; + } + + const adUnitMap = adUnits.reduce((acc, adUnit) => { + acc[adUnit.code] = adUnit; + return acc; + }, {}); + + window.googletag.pubads().getSlots().forEach(slot => { + const matchingAdUnitCode = find(Object.keys(adUnitMap), customGptSlotMatching + ? customGptSlotMatching(slot) + : utils.isAdUnitCodeMatchingSlot(slot)); + + if (matchingAdUnitCode) { + const adUnit = adUnitMap[matchingAdUnitCode]; + adUnit.fpd = adUnit.fpd || {}; + adUnit.fpd.context = adUnit.fpd.context || {}; + + const context = adUnit.fpd.context; + context.adServer = context.adServer || {}; + context.adServer.name = 'gam'; + context.adServer.adSlot = slot.getAdUnitPath(); + } + }); +}; + +export const appendPbAdSlot = adUnit => { + adUnit.fpd = adUnit.fpd || {}; + adUnit.fpd.context = adUnit.fpd.context || {}; + const context = adUnit.fpd.context; + const { customPbAdSlot } = _currentConfig; + + if (customPbAdSlot) { + context.pbAdSlot = customPbAdSlot(adUnit.code, utils.deepAccess(context, 'adServer.adSlot')); + return; + } + + // use context.pbAdSlot if set + if (context.pbAdSlot) { + return; + } + // use data attribute 'data-adslotid' if set + try { + const adUnitCodeDiv = document.getElementById(adUnit.code); + if (adUnitCodeDiv.dataset.adslotid) { + context.pbAdSlot = adUnitCodeDiv.dataset.adslotid; + return; + } + } catch (e) {} + // banner adUnit, use GPT adunit if defined + if (context.adServer) { + context.pbAdSlot = context.adServer.adSlot; + return; + } + context.pbAdSlot = adUnit.code; +}; + +export const makeBidRequestsHook = (fn, adUnits, ...args) => { + appendGptSlots(adUnits); + adUnits.forEach(adUnit => { + appendPbAdSlot(adUnit); + }); + return fn.call(this, adUnits, ...args); +}; + +const handleSetGptConfig = moduleConfig => { + _currentConfig = utils.pick(moduleConfig, [ + 'enabled', enabled => enabled !== false, + 'customGptSlotMatching', customGptSlotMatching => + typeof customGptSlotMatching === 'function' && customGptSlotMatching, + 'customPbAdSlot', customPbAdSlot => typeof customPbAdSlot === 'function' && customPbAdSlot, + ]); + + if (_currentConfig.enabled) { + if (!hooksAdded) { + getHook('makeBidRequests').before(makeBidRequestsHook); + hooksAdded = true; + } + } else { + utils.logInfo(`${MODULE_NAME}: Turning off module`); + _currentConfig = {}; + getHook('makeBidRequests').getHooks({hook: makeBidRequestsHook}).remove(); + hooksAdded = false; + } +}; + +config.getConfig('gptPreAuction', config => handleSetGptConfig(config.gptPreAuction)); +handleSetGptConfig({}); diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index 4ca631b23e5..378fc5a7efe 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -2,10 +2,12 @@ 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'; +import {config} from '../src/config.js'; const BIDDER_CODE = 'grid'; const ENDPOINT_URL = 'https://grid.bidswitch.net/hb'; -const SYNC_URL = 'https://x.bidswitch.net/sync?ssp=iow_labs'; +const NEW_ENDPOINT_URL = 'https://grid.bidswitch.net/hbjson'; +const SYNC_URL = 'https://x.bidswitch.net/sync?ssp=themediagrid'; const TIME_TO_LIVE = 360; const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; @@ -39,95 +41,22 @@ export const spec = { * * @param {BidRequest[]} validBidRequests - an array of bids * @param {bidderRequest} bidderRequest bidder request object - * @return ServerRequest Info describing the request to the server. + * @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 reqId; - - bids.forEach(bid => { - reqId = bid.bidderRequestId; - const {params: {uid}, adUnitCode, mediaTypes} = bid; - auids.push(uid); - const sizesId = utils.parseSizesInput(bid.sizes); - - const addedSizes = {}; - sizesId.forEach((sizeId) => { - addedSizes[sizeId] = true; - }); - const bannerSizesId = utils.parseSizesInput(utils.deepAccess(mediaTypes, 'banner.sizes')); - const videoSizesId = utils.parseSizesInput(utils.deepAccess(mediaTypes, 'video.playerSize')); - bannerSizesId.concat(videoSizesId).forEach((sizeId) => { - if (!addedSizes[sizeId]) { - addedSizes[sizeId] = true; - sizesId.push(sizeId); - } - }); - - 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 oldFormatBids = []; + const newFormatBids = []; + validBidRequests.forEach((bid) => { + bid.params.useNewFormat ? newFormatBids.push(bid) : oldFormatBids.push(bid); }); - - const payload = { - auids: auids.join(','), - sizes: utils.getKeys(sizeMap).join(','), - r: reqId, - wrapperType: 'Prebid_js', - wrapperVersion: '$prebid.version$' - }; - - 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; - } + const requests = []; + if (newFormatBids.length) { + requests.push(buildNewRequest(newFormatBids, bidderRequest)); } - - return { - method: 'GET', - url: ENDPOINT_URL, - data: utils.parseQueryStringParameters(payload).replace(/\&$/, ''), - bidsMap: bidsMap, - }; + if (oldFormatBids.length) { + requests.push(buildOldRequest(oldFormatBids, bidderRequest)); + } + return requests; }, /** * Unpack the response from the server into a list of bids. @@ -139,7 +68,6 @@ export const spec = { interpretResponse: function(serverResponse, bidRequest) { serverResponse = serverResponse && serverResponse.body; const bidResponses = []; - const bidsMap = bidRequest.bidsMap; let errorMessage; @@ -150,7 +78,7 @@ export const spec = { if (!errorMessage && serverResponse.seatbid) { serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidsMap, bidResponses); + _addBidResponse(_getBidFromResponse(respItem), bidRequest, bidResponses); }); } if (errorMessage) utils.logError(errorMessage); @@ -180,6 +108,16 @@ export const spec = { } }; +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); @@ -191,68 +129,76 @@ function _getBidFromResponse(respItem) { return respItem && respItem.bid && respItem.bid[0]; } -function _addBidResponse(serverBid, bidsMap, bidResponses) { +function _addBidResponse(serverBid, bidRequest, 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) { - 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: 'USD', - netRevenue: false, - ttl: TIME_TO_LIVE, - dealId: serverBid.dealid - }; - - if (serverBid.content_type === '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 - }); - } - } else { - bidResponse.ad = serverBid.adm; - bidResponse.mediaType = BANNER; + let bid = null; + let slot = null; + const bidsMap = bidRequest.bidsMap; + if (bidRequest.newFormat) { + bid = bidsMap[serverBid.impid]; + } else { + const awaitingBids = bidsMap[serverBid.auid]; + if (awaitingBids) { + const sizeId = `${serverBid.w}x${serverBid.h}`; + if (awaitingBids[sizeId]) { + slot = awaitingBids[sizeId][0]; + bid = slot.bids.shift(); } - bidResponses.push(bidResponse); + } else { + errorMessage = LOG_ERROR_MESS.noPlacementCode + serverBid.auid; + } + } - 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]; - } - } + if (bid) { + 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: 'USD', + netRevenue: false, + ttl: TIME_TO_LIVE, + dealId: serverBid.dealid + }; + + if (serverBid.content_type === '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 }); } + } else { + bidResponse.ad = serverBid.adm; + bidResponse.mediaType = BANNER; + } + bidResponses.push(bidResponse); + + if (slot && !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) { @@ -260,6 +206,326 @@ function _addBidResponse(serverBid, bidsMap, bidResponses) { } } +function buildOldRequest(validBidRequests, bidderRequest) { + const auids = []; + const bidsMap = {}; + const slotsMapByUid = {}; + const sizeMap = {}; + const bids = validBidRequests || []; + let pageKeywords = null; + let reqId; + + bids.forEach(bid => { + reqId = bid.bidderRequestId; + const {params: {uid}, adUnitCode, mediaTypes} = bid; + auids.push(uid); + const sizesId = utils.parseSizesInput(bid.sizes); + + if (!pageKeywords && !utils.isEmpty(bid.params.keywords)) { + pageKeywords = utils.transformBidderParamKeywords(bid.params.keywords); + } + + const addedSizes = {}; + sizesId.forEach((sizeId) => { + addedSizes[sizeId] = true; + }); + const bannerSizesId = utils.parseSizesInput(utils.deepAccess(mediaTypes, 'banner.sizes')); + const videoSizesId = utils.parseSizesInput(utils.deepAccess(mediaTypes, 'video.playerSize')); + bannerSizesId.concat(videoSizesId).forEach((sizeId) => { + if (!addedSizes[sizeId]) { + addedSizes[sizeId] = true; + sizesId.push(sizeId); + } + }); + + 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 configKeywords = utils.transformBidderParamKeywords({ + 'user': utils.deepAccess(config.getConfig('fpd.user'), 'keywords') || null, + 'context': utils.deepAccess(config.getConfig('fpd.context'), 'keywords') || null + }); + + if (configKeywords.length) { + pageKeywords = (pageKeywords || []).concat(configKeywords); + } + + if (pageKeywords && pageKeywords.length > 0) { + pageKeywords.forEach(deleteValues); + } + + const payload = { + 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 + } +} + +function buildNewRequest(validBidRequests, bidderRequest) { + let pageKeywords = null; + let jwpseg = null; + let content = null; + let schain = null; + let userId = null; + let user = null; + let userExt = null; + let {bidderRequestId, auctionId, gdprConsent, uspConsent, timeout, refererInfo} = bidderRequest; + + const referer = refererInfo ? encodeURIComponent(refererInfo.referer) : ''; + const imp = []; + const bidsMap = {}; + + validBidRequests.forEach((bid) => { + if (!bidderRequestId) { + bidderRequestId = bid.bidderRequestId; + } + if (!auctionId) { + auctionId = bid.auctionId; + } + if (!schain) { + schain = bid.schain; + } + if (!userId) { + userId = bid.userId; + } + const {params: {uid, keywords}, mediaTypes, bidId, adUnitCode, realTimeData} = bid; + bidsMap[bidId] = bid; + if (!pageKeywords && !utils.isEmpty(keywords)) { + pageKeywords = utils.transformBidderParamKeywords(keywords); + } + if (realTimeData && realTimeData.jwTargeting) { + if (!jwpseg && realTimeData.jwTargeting.segments) { + jwpseg = realTimeData.jwTargeting.segments; + } + if (!content && realTimeData.jwTargeting.content) { + content = realTimeData.jwTargeting.content; + } + } + let impObj = { + id: bidId, + tagid: uid.toString(), + ext: { + divid: adUnitCode + } + }; + + if (!mediaTypes || mediaTypes[BANNER]) { + const banner = createBannerRequest(bid, mediaTypes ? mediaTypes[BANNER] : {}); + if (banner) { + impObj.banner = banner; + } + } + if (mediaTypes && mediaTypes[VIDEO]) { + const video = createVideoRequest(bid, mediaTypes[VIDEO]); + if (video) { + impObj.video = video; + } + } + + if (impObj.banner || impObj.video) { + imp.push(impObj); + } + }); + + const source = { + tid: auctionId, + ext: { + wrapper: 'Prebid_js', + wrapper_version: '$prebid.version$' + } + }; + + if (schain) { + source.ext.schain = schain; + } + + const tmax = config.getConfig('bidderTimeout') || timeout; + + let request = { + id: bidderRequestId, + site: { + page: referer + }, + tmax, + source, + imp + }; + + if (content) { + request.site.content = content; + } + + if (jwpseg && jwpseg.length) { + user = { + data: [{ + name: 'iow_labs_pub_data', + segment: jwpseg.map((seg) => { + return {name: 'jwpseg', value: seg}; + }) + }] + }; + } + + if (gdprConsent && gdprConsent.consentString) { + userExt = {consent: gdprConsent.consentString}; + } + + if (userId) { + userExt = userExt || {}; + if (userId.tdid) { + userExt.unifiedid = userId.tdid; + } + if (userId.id5id && userId.id5id.uid) { + userExt.id5id = userId.id5id.uid; + } + if (userId.digitrustid && userId.digitrustid.data && userId.digitrustid.data.id) { + userExt.digitrustid = userId.digitrustid.data.id; + } + if (userId.lipb && userId.lipb.lipbid) { + userExt.liveintentid = userId.lipb.lipbid; + } + } + + if (userExt && Object.keys(userExt).length) { + user = user || {}; + user.ext = userExt; + } + + if (user) { + request.user = user; + } + + const configKeywords = utils.transformBidderParamKeywords({ + 'user': utils.deepAccess(config.getConfig('fpd.user'), 'keywords') || null, + 'context': utils.deepAccess(config.getConfig('fpd.context'), 'keywords') || null + }); + + if (configKeywords.length) { + pageKeywords = (pageKeywords || []).concat(configKeywords); + } + + if (pageKeywords && pageKeywords.length > 0) { + pageKeywords.forEach(deleteValues); + } + + if (pageKeywords) { + request.ext = { + keywords: pageKeywords + }; + } + + if (gdprConsent && gdprConsent.gdprApplies) { + request.regs = { + ext: { + gdpr: gdprConsent.gdprApplies ? 1 : 0 + } + } + } + + if (uspConsent) { + if (!request.regs) { + request.regs = {ext: {}}; + } + request.regs.ext.us_privacy = uspConsent; + } + + return { + method: 'POST', + url: NEW_ENDPOINT_URL, + data: JSON.stringify(request), + newFormat: true, + bidsMap + }; +} + +function createVideoRequest(bid, mediaType) { + const {playerSize, mimes, durationRangeSec} = mediaType; + const size = (playerSize || bid.sizes || [])[0]; + if (!size) return; + + let result = utils.parseGPTSingleSizeArrayToRtbSize(size); + + if (mimes) { + result.mimes = mimes; + } + + if (durationRangeSec && durationRangeSec.length === 2) { + result.minduration = durationRangeSec[0]; + result.maxduration = durationRangeSec[1]; + } + + return result; +} + +function createBannerRequest(bid, mediaType) { + const sizes = mediaType.sizes || bid.sizes; + if (!sizes || !sizes.length) return; + + let format = sizes.map((size) => utils.parseGPTSingleSizeArrayToRtbSize(size)); + let result = utils.parseGPTSingleSizeArrayToRtbSize(sizes[0]); + + if (format.length) { + result.format = format + } + return result; +} + function outstreamRender (bid) { bid.renderer.push(() => { window.ANOutstreamVideo.renderAd({ diff --git a/modules/gridBidAdapter.md b/modules/gridBidAdapter.md index 4720ee3d808..77b9bbf0f36 100644 --- a/modules/gridBidAdapter.md +++ b/modules/gridBidAdapter.md @@ -32,7 +32,11 @@ Grid bid adapter supports Banner and Video (instream and outstream). bidder: "grid", params: { uid: 2, - priceType: 'gross' + priceType: 'gross', + keywords: { + brandsafety: ['disaster'], + topic: ['stress', 'fear'] + } } } ] @@ -51,4 +55,4 @@ Grid bid adapter supports Banner and Video (instream and outstream). ] } ]; -``` \ No newline at end of file +``` diff --git a/modules/gridNMBidAdapter.js b/modules/gridNMBidAdapter.js index 7e244f8293c..ffd6c1b250c 100644 --- a/modules/gridNMBidAdapter.js +++ b/modules/gridNMBidAdapter.js @@ -5,7 +5,7 @@ import { VIDEO } from '../src/mediaTypes.js'; const BIDDER_CODE = 'gridNM'; const ENDPOINT_URL = 'https://grid.bidswitch.net/hbnm'; -const SYNC_URL = 'https://x.bidswitch.net/sync?ssp=iponweblabs'; +const SYNC_URL = 'https://x.bidswitch.net/sync?ssp=themediagrid'; const TIME_TO_LIVE = 360; const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; diff --git a/modules/gumgumBidAdapter.js b/modules/gumgumBidAdapter.js index cb2401fd90a..3206b7e1727 100644 --- a/modules/gumgumBidAdapter.js +++ b/modules/gumgumBidAdapter.js @@ -1,20 +1,23 @@ import * as utils from '../src/utils.js' -import { config } from '../src/config.js' import { BANNER, VIDEO } from '../src/mediaTypes.js'; -import includes from 'core-js-pure/features/array/includes.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js' + +import { config } from '../src/config.js' import { getStorageManager } from '../src/storageManager.js'; +import includes from 'core-js-pure/features/array/includes'; +import { registerBidder } from '../src/adapters/bidderFactory.js' const storage = getStorageManager(); const BIDDER_CODE = 'gumgum' const ALIAS_BIDDER_CODE = ['gg'] const BID_ENDPOINT = `https://g2.gumgum.com/hbid/imp` -const DT_CREDENTIALS = { member: 'YcXr87z2lpbB' } +const JCSI = { t: 0, rq: 8, pbv: '$prebid.version$' } const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO] const TIME_TO_LIVE = 60 +const DELAY_REQUEST_TIME = 1800000; // setting to 30 mins +let invalidRequestIds = {}; let browserParams = {}; let pageViewId = null @@ -60,7 +63,7 @@ function _getBrowserParams(topWindowUrl) { pu: topUrl, ce: storage.cookiesAreEnabled(), dpr: topWindow.devicePixelRatio || 1, - jcsi: encodeURIComponent(JSON.stringify({ t: 0, rq: 8 })), + jcsi: JSON.stringify(JCSI), ogu: getOgURL() } @@ -90,10 +93,6 @@ function _getTradeDeskIDParam(userId) { function _getDigiTrustQueryParams(userId) { let digiTrustId = userId.digitrustid && userId.digitrustid.data; - if (!digiTrustId) { - const digiTrustUser = (window.DigiTrust && window.DigiTrust.getUser) ? window.DigiTrust.getUser(DT_CREDENTIALS) : {}; - digiTrustId = (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || ''; - } // Verify there is an ID and this user has not opted out if (!digiTrustId || (digiTrustId.privacy && digiTrustId.privacy.optout)) { return {}; @@ -136,12 +135,24 @@ function isBidRequestValid (bid) { params, adUnitCode } = bid; + const legacyParamID = params.inScreen || params.inScreenPubID || params.inSlot || params.ICV || params.video || params.inVideo; + const id = legacyParamID || params.slot || params.native || params.zone || params.pubID; + + if (invalidRequestIds[id]) { + utils.logWarn(`[GumGum] Please check the implementation for ${id} for the placement ${adUnitCode}`); + return false; + } switch (true) { + case !!(params.zone): break; + case !!(params.pubId): break; case !!(params.inScreen): break; + case !!(params.inScreenPubID): break; case !!(params.inSlot): break; case !!(params.ICV): break; case !!(params.video): break; + case !!(params.inVideo): break; + case !!(params.videoPubID): break; default: utils.logWarn(`[GumGum] No product selected for the placement ${adUnitCode}, please check your implementation.`); return false; @@ -190,6 +201,34 @@ function _getVidParams (attributes) { }; } +/** + * Gets bidfloor + * @param {Object} mediaTypes + * @param {Number} bidfloor + * @param {Object} bid + * @returns {Number} floor + */ +function _getFloor (mediaTypes, bidfloor, bid) { + const curMediaType = Object.keys(mediaTypes)[0] || 'banner'; + let floor = bidfloor || 0; + + if (typeof bid.getFloor === 'function') { + const floorInfo = bid.getFloor({ + currency: 'USD', + mediaType: curMediaType, + size: '*' + }); + + if (typeof floorInfo === 'object' && + floorInfo.currency === 'USD' && + !isNaN(parseFloat(floorInfo.floor))) { + floor = Math.max(floor, parseFloat(floorInfo.floor)); + } + } + + return floor; +} + /** * Make a server request from the list of BidRequests. * @@ -211,35 +250,48 @@ function buildRequests (validBidRequests, bidderRequest) { transactionId, userId = {} } = bidRequest; - const bannerSizes = mediaTypes.banner && mediaTypes.banner.sizes; + const bidFloor = _getFloor(mediaTypes, params.bidfloor, bidRequest); + let sizes = [1, 1]; let data = {}; + if (mediaTypes.banner) { + sizes = mediaTypes.banner.sizes; + } else if (mediaTypes.video) { + sizes = mediaTypes.video.playerSize; + data = _getVidParams(mediaTypes.video); + } + if (pageViewId) { data.pv = pageViewId; } - if (params.bidfloor) { - data.fp = params.bidfloor; - } - if (params.inScreenPubID) { - data.pubId = params.inScreenPubID; - data.pi = 2; - } - if (params.inScreen) { - data.t = params.inScreen; - data.pi = 2; - } - if (params.inSlot) { - data.si = parseInt(params.inSlot, 10); - data.pi = 3; + + if (bidFloor) { + data.fp = bidFloor; } - if (params.ICV) { - data.ni = parseInt(params.ICV, 10); - data.pi = 5; + + if (params.iriscat && typeof params.iriscat === 'string') { + data.iriscat = params.iriscat; } - if (params.video) { - data = Object.assign(data, _getVidParams(mediaTypes.video)); - data.t = params.video; - data.pi = 7; + + if (params.zone) { + data.t = params.zone; + data.pi = 2; // inscreen + // override pi if the following is found + if (params.slot) { + data.si = parseInt(params.slot, 10); + data.pi = 3; + data.bf = sizes.reduce((acc, curSlotDim) => `${acc}${acc && ','}${curSlotDim[0]}x${curSlotDim[1]}`, ''); + } else if (params.native) { + data.ni = parseInt(params.native, 10); + data.pi = 5; + } else if (mediaTypes.video) { + data.pi = mediaTypes.video.linearity === 1 ? 7 : 6; // video : invideo + } + } else if (params.pubId) { + data.pubId = params.pubId + data.pi = mediaTypes.video ? 7 : 2; // video : inscreen + } else { // legacy params + data = { ...data, ...handleLegacyParams(params, sizes) } } if (gdprConsent) { @@ -261,7 +313,7 @@ function buildRequests (validBidRequests, bidderRequest) { tId: transactionId, pi: data.pi, selector: params.selector, - sizes: bannerSizes || bidRequest.sizes, + sizes, url: BID_ENDPOINT, method: 'GET', data: Object.assign(data, _getBrowserParams(topWindowUrl), _getDigiTrustQueryParams(userId), _getTradeDeskIDParam(userId)) @@ -270,6 +322,40 @@ function buildRequests (validBidRequests, bidderRequest) { return bids; } +function handleLegacyParams (params, sizes) { + const data = {}; + if (params.inScreenPubID) { + data.pubId = params.inScreenPubID; + data.pi = 2; + } + if (params.inScreen) { + data.t = params.inScreen; + data.pi = 2; + } + if (params.inSlot) { + data.si = parseInt(params.inSlot, 10); + data.pi = 3; + data.bf = sizes.reduce((acc, curSlotDim) => `${acc}${acc && ','}${curSlotDim[0]}x${curSlotDim[1]}`, ''); + } + if (params.ICV) { + data.ni = parseInt(params.ICV, 10); + data.pi = 5; + } + if (params.videoPubID) { + data.pubId = params.videoPubID; + data.pi = 7; + } + if (params.video) { + data.t = params.video; + data.pi = 7; + } + if (params.inVideo) { + data.t = params.inVideo; + data.pi = 6; + } + return data; +} + /** * Unpack the response from the server into a list of bids. * @@ -279,6 +365,19 @@ function buildRequests (validBidRequests, bidderRequest) { function interpretResponse (serverResponse, bidRequest) { const bidResponses = [] const serverResponseBody = serverResponse.body + + if (!serverResponseBody || serverResponseBody.err) { + const data = bidRequest.data || {} + const id = data.si || data.ni || data.t || data.pubId; + const delayTime = serverResponseBody ? serverResponseBody.err.drt : DELAY_REQUEST_TIME; + invalidRequestIds[id] = { productId: data.pi, timestamp: new Date().getTime() }; + + setTimeout(() => { + !!invalidRequestIds[id] && delete invalidRequestIds[id]; + }, delayTime); + utils.logWarn(`[GumGum] Please check the implementation for ${id}`); + } + const defaultResponse = { ad: { price: 0, @@ -299,7 +398,8 @@ function interpretResponse (serverResponse, bidRequest) { cw: wrapper, pag: { pvid - } + }, + jcsi } = Object.assign(defaultResponse, serverResponseBody) let data = bidRequest.data || {} let product = data.pi @@ -313,6 +413,10 @@ function interpretResponse (serverResponse, bidRequest) { height = '1' } + if (jcsi) { + serverResponseBody.jcsi = JCSI + } + // update Page View ID from server response pageViewId = pvid @@ -320,8 +424,9 @@ function interpretResponse (serverResponse, bidRequest) { bidResponses.push({ // dealId: DEAL_ID, // referrer: REFERER, - ...(product === 7 && { vastXml: markup }), + ...(product === 7 && { vastXml: markup, mediaType: VIDEO }), ad: wrapper ? getWrapperCode(wrapper, Object.assign({}, serverResponseBody, { bidRequest })) : markup, + ...(product === 6 && {ad: markup}), cpm: isTestUnit ? 0.1 : cpm, creativeId, currency: cur || 'USD', diff --git a/modules/gumgumBidAdapter.md b/modules/gumgumBidAdapter.md index 3abc8a246c9..f47666e9628 100644 --- a/modules/gumgumBidAdapter.md +++ b/modules/gumgumBidAdapter.md @@ -37,6 +37,18 @@ var adUnits = [ } } ] + },{ + code: 'test-div', + sizes: [[300, 50]], + bids: [ + { + bidder: 'gumgum', + params: { + inVideo: 'ggumtest', // GumGum Zone ID given to the client + bidfloor: 0.03 // CPM bid floor + } + } + ] } ]; ``` diff --git a/modules/h12mediaBidAdapter.js b/modules/h12mediaBidAdapter.js new file mode 100644 index 00000000000..0d2c22a3f68 --- /dev/null +++ b/modules/h12mediaBidAdapter.js @@ -0,0 +1,209 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import find from 'core-js-pure/features/array/find.js'; +const BIDDER_CODE = 'h12media'; +const DEFAULT_URL = 'https://bidder.h12-media.com/prebid/'; +const DEFAULT_CURRENCY = 'USD'; +const DEFAULT_TTL = 360; +const DEFAULT_NET_REVENUE = false; + +export const spec = { + code: BIDDER_CODE, + aliases: ['h12'], + + isBidRequestValid: function(bid) { + return !!(bid.params && bid.params.pubid); + }, + + buildRequests: function(validBidRequests, bidderRequest) { + const requestUrl = validBidRequests[0].params.endpointdom || DEFAULT_URL; + const isiframe = !((window.self === window.top) || window.frameElement); + const screenSize = getClientDimensions(); + const docSize = getDocumentDimensions(); + + const bidrequests = validBidRequests.map((bidRequest) => { + const bidderParams = bidRequest.params; + const adUnitElement = document.getElementById(bidRequest.adUnitCode); + const ishidden = !isVisible(adUnitElement); + const coords = { + x: adUnitElement && adUnitElement.getBoundingClientRect().x, + y: adUnitElement && adUnitElement.getBoundingClientRect().y, + }; + + return { + bidId: bidRequest.bidId, + transactionId: bidRequest.transactionId, + adunitId: bidRequest.adUnitCode, + pubid: bidderParams.pubid, + placementid: bidderParams.placementid || '', + size: bidderParams.size || '', + adunitSize: bidRequest.mediaTypes.banner.sizes || [], + coords, + ishidden, + }; + }); + + return { + method: 'POST', + url: requestUrl, + options: {withCredentials: false}, + data: { + gdpr: utils.deepAccess(bidderRequest, 'gdprConsent.gdprApplies') ? Boolean(bidderRequest.gdprConsent.gdprApplies & 1) : false, + gdpr_cs: utils.deepAccess(bidderRequest, 'gdprConsent.gdprApplies') ? bidderRequest.gdprConsent.consentString : '', + topLevelUrl: window.top.location.href, + refererUrl: bidderRequest.refererInfo ? bidderRequest.refererInfo.referer : '', + isiframe, + version: '$prebid.version$', + visitorInfo: { + localTime: getLocalDateFormatted(), + dayOfWeek: new Date().getDay(), + screenWidth: screenSize[0], + screenHeight: screenSize[1], + docWidth: docSize[0], + docHeight: docSize[1], + scrollbarx: window.scrollX, + scrollbary: window.scrollY, + }, + bidrequests, + }, + }; + }, + + interpretResponse: function(serverResponse, bidRequests) { + let bidResponses = []; + try { + const serverBody = serverResponse.body; + if (serverBody) { + if (serverBody.bids) { + serverBody.bids.forEach(bidBody => { + const bidRequest = find(bidRequests.data.bidrequests, bid => bid.bidId === bidBody.bidId); + const bidResponse = { + currency: serverBody.currency || DEFAULT_CURRENCY, + netRevenue: serverBody.netRevenue || DEFAULT_NET_REVENUE, + ttl: serverBody.ttl || DEFAULT_TTL, + requestId: bidBody.bidId, + cpm: bidBody.cpm, + width: bidBody.width, + height: bidBody.height, + creativeId: bidBody.creativeId, + ad: bidBody.ad, + meta: bidBody.meta, + mediaType: 'banner', + }; + if (bidRequest) { + bidResponse.pubid = bidRequest.pubid; + bidResponse.placementid = bidRequest.placementid; + bidResponse.size = bidRequest.size; + } + bidResponses.push(bidResponse); + }); + } + } + return bidResponses; + } catch (err) { + utils.logError(err); + } + }, + + getUserSyncs: function(syncOptions, serverResponses, gdprConsent) { + const serverBody = serverResponses[0].body; + const syncs = []; + gdprConsent = gdprConsent || { + gdprApplies: false, consentString: '', + }; + + if (serverBody) { + if (serverBody.bids) { + serverBody.bids.forEach(bidBody => { + const userSyncUrls = bidBody.usersync || []; + const userSyncUrlProcess = url => { + return url + .replace('{gdpr}', gdprConsent.gdprApplies) + .replace('{gdpr_cs}', gdprConsent.consentString); + } + + userSyncUrls.forEach(sync => { + if (syncOptions.iframeEnabled && sync.type === 'iframe' && sync.url) { + syncs.push({ + type: 'iframe', + url: userSyncUrlProcess(sync.url), + }); + } + if (syncOptions.pixelEnabled && sync.type === 'image' && sync.url) { + syncs.push({ + type: 'image', + url: userSyncUrlProcess(sync.url), + }); + } + }); + }); + } + } + + return syncs; + }, +} + +function getContext(elem) { + return elem && window.document.body.contains(elem) ? window : (window.top.document.body.contains(elem) ? top : undefined); +} + +function isDefined(val) { + return (val !== null) && (typeof val !== 'undefined'); +} + +function getIsHidden(elem) { + let lastElem = elem; + let elemHidden = false; + let m; + m = 0; + + do { + m = m + 1; + try { + if ( + getContext(elem).getComputedStyle(lastElem).getPropertyValue('display') === 'none' || + getContext(elem).getComputedStyle(lastElem).getPropertyValue('visibility') === 'hidden' + ) { + return true; + } else { + elemHidden = false; + lastElem = lastElem.parentElement; + } + } catch (o) { + return false; + } + } while ((m < 250) && (lastElem != null) && (elemHidden === false)) + return elemHidden; +} + +function isVisible(element) { + return element && isDefined(getContext(element)) && !getIsHidden(element); +} + +function getClientDimensions() { + try { + const t = window.top.innerWidth || window.top.document.documentElement.clientWidth || window.top.document.body.clientWidth; + const e = window.top.innerHeight || window.top.document.documentElement.clientHeight || window.top.document.body.clientHeight; + return [Math.round(t), Math.round(e)]; + } catch (i) { + return [0, 0]; + } +} + +function getDocumentDimensions() { + try { + const D = window.top.document; + return [D.body.offsetWidth, Math.max(D.body.scrollHeight, D.documentElement.scrollHeight, D.body.offsetHeight, D.documentElement.offsetHeight, D.body.clientHeight, D.documentElement.clientHeight)] + } catch (t) { + return [-1, -1] + } +} + +function getLocalDateFormatted() { + const two = num => ('0' + num).slice(-2); + const d = new Date(); + return `${d.getFullYear()}-${two(d.getMonth() + 1)}-${two(d.getDate())} ${two(d.getHours())}:${two(d.getMinutes())}:${two(d.getSeconds())}`; +} + +registerBidder(spec); diff --git a/modules/h12mediaBidAdapter.md b/modules/h12mediaBidAdapter.md new file mode 100644 index 00000000000..7430bf11b90 --- /dev/null +++ b/modules/h12mediaBidAdapter.md @@ -0,0 +1,48 @@ +# Overview + +Module Name: H12 Media Bidder Adapter +Module Type: Bidder Adapter +Maintainer: contact@h12-media.com + +# Description + +Module that connects to H12 Media demand source to fetch bids. + +# Test Parameters +``` + var adUnits = [ + { + code: 'div-1', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [ + { + bidder: "h12media", + params: { + pubid: '123', + sizes: '300x250', + } + } + ] + },{ + code: 'div-2', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + bids: [ + { + bidder: "h12media", + params: { + pubid: '123', + placementid: '321' + } + } + ] + } + ]; +``` diff --git a/modules/haloIdSystem.js b/modules/haloIdSystem.js new file mode 100644 index 00000000000..237b502f6a7 --- /dev/null +++ b/modules/haloIdSystem.js @@ -0,0 +1,63 @@ +/** + * This module adds HaloID to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/haloIdSystem + * @requires module:modules/userId + */ + +import * as utils from '../src/utils.js'; +import {ajax} from '../src/ajax.js'; +import {submodule} from '../src/hook.js'; + +const MODULE_NAME = 'haloId'; + +/** @type {Submodule} */ +export const haloIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: MODULE_NAME, + /** + * decode the stored id value for passing to bid requests + * @function + * @param {{value:string}} value + * @returns {{haloId:Object}} + */ + decode(value) { + return (value && typeof value['haloId'] === 'string') ? { 'haloId': value['haloId'] } : undefined; + }, + /** + * performs action to obtain id and return a value in the callback's response argument + * @function + * @param {SubmoduleParams} [configParams] + * @returns {IdResponse|undefined} + */ + getId(configParams) { + const url = `https://id.halo.ad.gt/api/v1/pbhid`; + + const resp = function (callback) { + const callbacks = { + success: response => { + let responseObj; + if (response) { + try { + responseObj = JSON.parse(response); + } catch (error) { + utils.logError(error); + } + } + callback(responseObj); + }, + error: error => { + utils.logError(`${MODULE_NAME}: ID fetch encountered an error`, error); + callback(); + } + }; + ajax(url, callbacks, undefined, {method: 'GET'}); + }; + return {callback: resp}; + } +}; + +submodule('userId', haloIdSubmodule); diff --git a/modules/haloIdSystem.md b/modules/haloIdSystem.md new file mode 100644 index 00000000000..0be0be27f5d --- /dev/null +++ b/modules/haloIdSystem.md @@ -0,0 +1,32 @@ +## Audigent Halo User ID Submodule + +Audigent Halo ID Module. For assistance setting up your module please contact us at [prebid@audigent.com](prebid@audigent.com). + +### Prebid Params + +Individual params may be set for the Audigent Halo ID Submodule. At least one identifier must be set in the params. + +``` +pbjs.setConfig({ + usersync: { + userIds: [{ + name: 'haloId', + storage: { + name: 'haloId', + type: 'html5' + } + }] + } +}); +``` +## Parameter Descriptions for the `usersync` Configuration Section +The below parameters apply only to the HaloID User ID Module integration. + +| Param under usersync.userIds[] | Scope | Type | Description | Example | +| --- | --- | --- | --- | --- | +| name | Required | String | ID value for the HaloID module - `"haloId"` | `"haloId"` | +| 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. | `"haloid"` | +| 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 Halo 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 | `{"haloId": "eb33b0cb-8d35-4722-b9c0-1a31d4064888"}` | diff --git a/modules/id5IdSystem.js b/modules/id5IdSystem.js index 151782791af..47064e0a1a9 100644 --- a/modules/id5IdSystem.js +++ b/modules/id5IdSystem.js @@ -1,13 +1,22 @@ /** * This module adds ID5 to the User ID module * The {@link module:modules/userId} module is required - * @module modules/unifiedIdSystem + * @module modules/id5IdSystem * @requires module:modules/userId */ import * as utils from '../src/utils.js' -import {ajax} from '../src/ajax.js'; -import {submodule} from '../src/hook.js'; +import { ajax } from '../src/ajax.js'; +import { submodule } from '../src/hook.js'; +import { getRefererInfo } from '../src/refererDetection.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const MODULE_NAME = 'id5Id'; +const GVLID = 131; +const BASE_NB_COOKIE_NAME = 'id5id.1st'; +const NB_COOKIE_EXP_DAYS = (30 * 24 * 60 * 60 * 1000); // 30 days + +const storage = getStorageManager(GVLID, MODULE_NAME); /** @type {Submodule} */ export const id5IdSubmodule = { @@ -16,11 +25,13 @@ export const id5IdSubmodule = { * @type {string} */ name: 'id5Id', + /** * Vendor id of ID5 * @type {Number} */ - gvlid: 131, + gvlid: GVLID, + /** * decode the stored id value for passing to bid requests * @function decode @@ -28,25 +39,59 @@ export const id5IdSubmodule = { * @returns {(Object|undefined)} */ decode(value) { - return (value && typeof value['ID5ID'] === 'string') ? { 'id5id': value['ID5ID'] } : undefined; + let uid; + let linkType = 0; + + if (value && typeof value.ID5ID === 'string') { + // don't lose our legacy value from cache + uid = value.ID5ID; + } else if (value && typeof value.universal_uid === 'string') { + uid = value.universal_uid; + linkType = value.link_type || linkType; + } else { + return undefined; + } + + return { + 'id5id': { + 'uid': uid, + 'ext': { + 'linkType': linkType + } + } + }; }, + /** * performs action to obtain id and return a value in the callback's response argument - * @function + * @function getId * @param {SubmoduleParams} [configParams] * @param {ConsentData} [consentData] * @param {(Object|undefined)} cacheIdObj * @returns {IdResponse|undefined} */ getId(configParams, consentData, cacheIdObj) { - if (!configParams || typeof configParams.partner !== 'number') { - utils.logError(`User ID - ID5 submodule requires partner to be defined as a number`); + if (!hasRequiredParams(configParams)) { return undefined; } const hasGdpr = (consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies) ? 1 : 0; const gdprConsentString = hasGdpr ? consentData.consentString : ''; - const storedUserId = this.decode(cacheIdObj); - const url = `https://id5-sync.com/g/v1/${configParams.partner}.json?1puid=${storedUserId ? storedUserId.id5id : ''}&gdpr=${hasGdpr}&gdpr_consent=${gdprConsentString}`; + const url = `https://id5-sync.com/g/v2/${configParams.partner}.json?gdpr_consent=${gdprConsentString}&gdpr=${hasGdpr}`; + const referer = getRefererInfo(); + const signature = (cacheIdObj && cacheIdObj.signature) ? cacheIdObj.signature : ''; + const pubId = (cacheIdObj && cacheIdObj.ID5ID) ? cacheIdObj.ID5ID : ''; // TODO: remove when 1puid isn't needed + const data = { + 'partner': configParams.partner, + '1puid': pubId, // TODO: remove when 1puid isn't needed + 'nbPage': incrementNb(configParams), + 'o': 'pbjs', + 'pd': configParams.pd || '', + 'rf': referer.referer, + 's': signature, + 'top': referer.reachedTop ? 1 : 0, + 'u': referer.stack[0] || window.location.href, + 'v': '$prebid.version$' + }; const resp = function (callback) { const callbacks = { @@ -55,6 +100,7 @@ export const id5IdSubmodule = { if (response) { try { responseObj = JSON.parse(response); + resetNb(configParams); } catch (error) { utils.logError(error); } @@ -66,10 +112,54 @@ export const id5IdSubmodule = { callback(); } }; - ajax(url, callbacks, undefined, { method: 'GET', withCredentials: true }); + ajax(url, callbacks, JSON.stringify(data), { method: 'POST', withCredentials: true }); }; return {callback: resp}; + }, + + /** + * Similar to Submodule#getId, this optional method returns response to for id that exists already. + * If IdResponse#id is defined, then it will be written to the current active storage even if it exists already. + * If IdResponse#callback is defined, then it'll called at the end of auction. + * It's permissible to return neither, one, or both fields. + * @function extendId + * @param {SubmoduleParams} configParams + * @param {Object} cacheIdObj - existing id, if any + * @return {(IdResponse|function(callback:function))} A response object that contains id and/or callback. + */ + extendId(configParams, cacheIdObj) { + incrementNb(configParams); + return cacheIdObj; } }; +function hasRequiredParams(configParams) { + if (!configParams || typeof configParams.partner !== 'number') { + utils.logError(`User ID - ID5 submodule requires partner to be defined as a number`); + return false; + } + return true; +} +function nbCookieName(configParams) { + return hasRequiredParams(configParams) ? `${BASE_NB_COOKIE_NAME}_${configParams.partner}_nb` : undefined; +} +function nbCookieExpStr(expDays) { + return (new Date(Date.now() + expDays)).toUTCString(); +} +function storeNbInCookie(configParams, nb) { + storage.setCookie(nbCookieName(configParams), nb, nbCookieExpStr(NB_COOKIE_EXP_DAYS), 'Lax'); +} +function getNbFromCookie(configParams) { + const cacheNb = storage.getCookie(nbCookieName(configParams)); + return (cacheNb) ? parseInt(cacheNb) : 0; +} +function incrementNb(configParams) { + const nb = (getNbFromCookie(configParams) + 1); + storeNbInCookie(configParams, nb); + return nb; +} +function resetNb(configParams) { + storeNbInCookie(configParams, 0); +} + submodule('userId', id5IdSubmodule); diff --git a/modules/identityLinkIdSystem.js b/modules/identityLinkIdSystem.js index a7114c2a147..14c33329b2d 100644 --- a/modules/identityLinkIdSystem.js +++ b/modules/identityLinkIdSystem.js @@ -6,8 +6,8 @@ */ import * as utils from '../src/utils.js' -import {ajax} from '../src/ajax.js'; -import {submodule} from '../src/hook.js'; +import { ajax } from '../src/ajax.js'; +import { submodule } from '../src/hook.js'; /** @type {Submodule} */ export const identityLinkSubmodule = { @@ -16,6 +16,11 @@ export const identityLinkSubmodule = { * @type {string} */ name: 'identityLink', + /** + * used to specify vendor id + * @type {number} + */ + gvlid: 97, /** * decode the stored id value for passing to bid requests * @function @@ -39,15 +44,22 @@ export const identityLinkSubmodule = { } const hasGdpr = (consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies) ? 1 : 0; const gdprConsentString = hasGdpr ? consentData.consentString : ''; + const tcfPolicyV2 = utils.deepAccess(consentData, 'vendorData.tcfPolicyVersion') === 2; // use protocol relative urls for http or https - const url = `https://api.rlcdn.com/api/identity/envelope?pid=${configParams.pid}${hasGdpr ? '&ct=1&cv=' + gdprConsentString : ''}`; + if (hasGdpr && (!gdprConsentString || gdprConsentString === '')) { + utils.logInfo('Consent string is required to call envelope API.'); + return; + } + const url = `https://api.rlcdn.com/api/identity/envelope?pid=${configParams.pid}${hasGdpr ? (tcfPolicyV2 ? '&ct=4&cv=' : '&ct=1&cv=') + gdprConsentString : ''}`; let resp; - resp = function(callback) { + resp = function (callback) { // Check ats during callback so it has a chance to initialise. // If ats library is available, use it to retrieve envelope. If not use standard third party endpoint if (window.ats) { + utils.logInfo('ATS exists!'); window.ats.retrieveEnvelope(function (envelope) { if (envelope) { + utils.logInfo('An envelope can be retrieved from ATS!'); callback(JSON.parse(envelope).envelope); } else { getEnvelope(url, callback); @@ -58,11 +70,12 @@ export const identityLinkSubmodule = { } }; - return {callback: resp}; + return { callback: resp }; } }; // return envelope from third party endpoint function getEnvelope(url, callback) { + utils.logInfo('A 3P retrieval is attempted!'); const callbacks = { success: response => { let responseObj; @@ -70,17 +83,17 @@ function getEnvelope(url, callback) { try { responseObj = JSON.parse(response); } catch (error) { - utils.logError(error); + utils.logInfo(error); } } - callback(responseObj.envelope); + callback((responseObj && responseObj.envelope) ? responseObj.envelope : ''); }, error: error => { - utils.logError(`identityLink: ID fetch encountered an error`, error); + utils.logInfo(`identityLink: ID fetch encountered an error`, error); callback(); } }; - ajax(url, callbacks, undefined, {method: 'GET', withCredentials: true}); + ajax(url, callbacks, undefined, { method: 'GET', withCredentials: true }); } submodule('userId', identityLinkSubmodule); diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js index dfabf4eef55..3c000258ede 100644 --- a/modules/improvedigitalBidAdapter.js +++ b/modules/improvedigitalBidAdapter.js @@ -8,7 +8,7 @@ const BIDDER_CODE = 'improvedigital'; const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; export const spec = { - version: '7.0.0', + version: '7.1.0', code: BIDDER_CODE, gvlid: 253, aliases: ['id'], @@ -123,7 +123,7 @@ export const spec = { // Deal ID. Composite ads can have multiple line items and the ID of the first // dealID line item will be used. - if (utils.isNumber(bidObject.lid) && bidObject.buying_type === 'deal_id') { + if (utils.isNumber(bidObject.lid) && bidObject.buying_type && bidObject.buying_type !== 'rtb') { bid.dealId = bidObject.lid; } else if (Array.isArray(bidObject.lid) && Array.isArray(bidObject.buying_type) && @@ -131,7 +131,7 @@ export const spec = { let isDeal = false; bidObject.buying_type.forEach((bt, i) => { if (isDeal) return; - if (bt === 'deal_id') { + if (bt && bt !== 'rtb') { isDeal = true; bid.dealId = bidObject.lid[i]; } @@ -182,9 +182,10 @@ export const spec = { }; function isInstreamVideo(bid) { + const mediaTypes = Object.keys(utils.deepAccess(bid, 'mediaTypes', {})); const videoMediaType = utils.deepAccess(bid, 'mediaTypes.video'); const context = utils.deepAccess(bid, 'mediaTypes.video.context'); - return bid.mediaType === 'video' || (videoMediaType && context !== 'outstream'); + return bid.mediaType === 'video' || (mediaTypes.length === 1 && videoMediaType && context !== 'outstream'); } function isOutstreamVideo(bid) { @@ -197,30 +198,23 @@ function outstreamRender(bid) { bid.renderer.push(() => { window.ANOutstreamVideo.renderAd({ sizes: [bid.width, bid.height], - width: bid.width, - height: bid.height, targetId: bid.adUnitCode, adResponse: bid.adResponse, - rendererOptions: { - showBigPlayButton: false, - showProgressBar: 'bar', - showVolume: false, - allowFullscreen: true, - skippable: false, - } - }); + rendererOptions: bid.renderer.getConfig() + }, handleOutstreamRendererEvents.bind(null, bid)); }); } +function handleOutstreamRendererEvents(bid, id, eventName) { + bid.renderer.handleVideoEvent({ id, eventName }); +} + function createRenderer(bidRequest) { const renderer = Renderer.install({ id: bidRequest.adUnitCode, url: RENDERER_URL, loaded: false, - config: { - player_width: bidRequest.mediaTypes.video.playerSize[0][0], - player_height: bidRequest.mediaTypes.video.playerSize[0][1] - }, + config: utils.deepAccess(bidRequest, 'renderer.options'), adUnitCode: bidRequest.adUnitCode }); try { diff --git a/modules/inmarBidAdapter.js b/modules/inmarBidAdapter.js new file mode 100755 index 00000000000..b5ab72266fc --- /dev/null +++ b/modules/inmarBidAdapter.js @@ -0,0 +1,113 @@ +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 = 'inmar'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['inm'], + supportedMediaTypes: [BANNER, VIDEO], + + /** + * Determines whether or not the given bid request is valid + * + * @param {bidRequest} bid The bid params to validate. + * @returns {boolean} True if this is a valid bid, and false otherwise + */ + isBidRequestValid: function(bid) { + return !!(bid.params && bid.params.partnerId && bid.params.adnetId); + }, + + /** + * Build a server request from the list of valid BidRequests + * @param {validBidRequests} is an array of the valid bids + * @param {bidderRequest} bidder request object + * @returns {ServerRequest} Info describing the request to the server + */ + buildRequests: function(validBidRequests, bidderRequest) { + var payload = { + bidderCode: bidderRequest.bidderCode, + auctionId: bidderRequest.auctionId, + bidderRequestId: bidderRequest.bidderRequestId, + bidRequests: validBidRequests, + auctionStart: bidderRequest.auctionStart, + timeout: bidderRequest.timeout, + refererInfo: bidderRequest.refererInfo, + start: bidderRequest.start, + gdprConsent: bidderRequest.gdprConsent, + uspConsent: bidderRequest.uspConsent, + currencyCode: config.getConfig('currency.adServerCurrency'), + coppa: config.getConfig('coppa'), + firstPartyData: config.getConfig('fpd'), + prebidVersion: '$prebid.version$' + }; + + var payloadString = JSON.stringify(payload); + + return { + method: 'POST', + url: 'https://prebid.owneriq.net:8443/bidder/pb/bid', + options: { + withCredentials: false + }, + data: payloadString, + }; + }, + + /** + * Read the response from the server and build a list of bids + * @param {serverResponse} Response from the server. + * @param {bidRequest} Bid request object + * @returns {bidResponses} Array of bids which were nested inside the server + */ + interpretResponse: function(serverResponse, bidRequest) { + const bidResponses = []; + var response = serverResponse.body; + + try { + if (response) { + var 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, + vastUrl: response.vastUrl, + dealId: response.dealId, + meta: response.meta + }; + + bidResponses.push(bidResponse); + } + } catch (error) { + utils.logError('Error while parsing inmar response', error); + } + return bidResponses; + }, + + /** + * User Syncs + * + * @param {syncOptions} Publisher prebid configuration + * @param {serverResponses} Response from the server + * @returns {Array} + */ + getUserSyncs: function(syncOptions, serverResponses) { + const syncs = []; + if (syncOptions.pixelEnabled) { + syncs.push({ + type: 'image', + url: 'https://px.owneriq.net/eucm/p/pb' + }); + } + return syncs; + } +}; + +registerBidder(spec); diff --git a/modules/inmarBidAdapter.md b/modules/inmarBidAdapter.md new file mode 100644 index 00000000000..1bacb30f2dd --- /dev/null +++ b/modules/inmarBidAdapter.md @@ -0,0 +1,46 @@ +# Overview + +``` +Module Name: Inmar Bidder Adapter +Module Type: Bidder Adapter +Maintainer: oiq_rtb@inmar.com +``` + +# Description + +Connects to Inmar for bids. This adapter supports Display and Video. + +The Inmar adapter requires setup and approval from the Inmar team. +Please reach out to your account manager for more information. + +# Test Parameters + +## Web +``` + var adUnits = [ + { + code: 'test-div1', + sizes: [[300, 250],[300, 600]], + bids: [{ + bidder: 'inmar', + params: { + partnerId: 12345, + adnetId: 'ADb1f40rmi', + position: 1 + } + }] + }, + { + code: 'test-div2', + sizes: [[728, 90],[970, 250]], + bids: [{ + bidder: 'inmar', + params: { + partnerId: 12345, + adnetId: 'ADb1f40rmo', + position: 0 + } + }] + } + ]; +``` diff --git a/modules/inskinBidAdapter.js b/modules/inskinBidAdapter.js index a89a1b20219..2a55b5280db 100644 --- a/modules/inskinBidAdapter.js +++ b/modules/inskinBidAdapter.js @@ -57,6 +57,9 @@ export const spec = { parallel: true }, validBidRequests[0].params); + data.keywords = data.keywords || []; + const restrictions = []; + if (bidderRequest && bidderRequest.gdprConsent) { data.consent = { gdprVendorId: 150, @@ -64,6 +67,33 @@ export const spec = { // will check if the gdprApplies field was populated with a boolean value (ie from page config). If it's undefined, then default to true gdprConsentRequired: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true }; + + if (bidderRequest.gdprConsent.apiVersion === 2) { + const purposes = [ + {id: 1, kw: 'nocookies'}, + {id: 2, kw: 'nocontext'}, + {id: 3, kw: 'nodmp'}, + {id: 4, kw: 'nodata'}, + {id: 7, kw: 'noclicks'}, + {id: 9, kw: 'noresearch'} + ]; + + const d = bidderRequest.gdprConsent.vendorData; + + if (d) { + if (d.purposeOneTreatment) { + data.keywords.push('cst-nodisclosure'); + restrictions.push('nodisclosure'); + } + + purposes.map(p => { + if (!checkConsent(p.id, d)) { + data.keywords.push('cst-' + p.kw); + restrictions.push(p.kw); + } + }); + } + } } validBidRequests.map(bid => { @@ -78,6 +108,11 @@ export const spec = { placement.adTypes.push(5, 9, 163, 2163, 3006); + if (restrictions.length) { + placement.properties = placement.properties || {}; + placement.properties.restrictions = restrictions; + } + if (placement.networkId && placement.siteId) { data.placements.push(placement); } @@ -153,6 +188,7 @@ export const spec = { const id = 'ism_tag_' + Math.floor((Math.random() * 10e16)); window[id] = { + plr_AdSlot: e.source.frameElement, bidId: e.data.bidId, bidPrice: bidsMap[e.data.bidId].price, serverResponse @@ -242,4 +278,97 @@ function retrieveAd(bidId, decision) { return " ``` +# Ad Unit and Setup: For Testing (Video Instream) -# Ad Unit and Setup: For Testing (Native) +```html + + + +``` +# Ad Unit and Setup: For Testing (Video Outstream) ```html +``` + +# Ad Unit and Setup: For Testing (Native) + +```html + + + + diff --git a/modules/mediasquareBidAdapter.js b/modules/mediasquareBidAdapter.js new file mode 100644 index 00000000000..288526d3cc5 --- /dev/null +++ b/modules/mediasquareBidAdapter.js @@ -0,0 +1,153 @@ +import {ajax} from '../src/ajax.js'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'mediasquare'; +const BIDDER_URL_PROD = 'https://pbs-front.mediasquare.fr/' +const BIDDER_URL_TEST = 'https://bidder-test.mediasquare.fr/' +const BIDDER_ENDPOINT_AUCTION = 'msq_prebid'; +const BIDDER_ENDPOINT_SYNC = 'cookie_sync'; +const BIDDER_ENDPOINT_WINNING = 'winning'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['msq'], // short 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: function(bid) { + return !!(bid.params.owner && bid.params.code); + }, + /** + * 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) { + let codes = []; + let endpoint = document.location.search.match(/msq_test=true/) ? BIDDER_URL_TEST : BIDDER_URL_PROD; + const test = config.getConfig('debug') ? 1 : 0; + let adunitValue = null; + Object.keys(validBidRequests).forEach(key => { + adunitValue = validBidRequests[key]; + codes.push({ + owner: adunitValue.params.owner, + code: adunitValue.params.code, + adunit: adunitValue.adUnitCode, + bidId: adunitValue.bidId, + auctionId: adunitValue.auctionId, + transactionId: adunitValue.transactionId, + mediatypes: adunitValue.mediaTypes + }); + }); + const payload = { + codes: codes, + referer: encodeURIComponent(bidderRequest.refererInfo.referer) + }; + if (bidderRequest) { // modules informations (gdpr, ccpa, schain, userId) + if (bidderRequest.gdprConsent) { + payload.gdpr = { + consent_string: bidderRequest.gdprConsent.consentString, + consent_required: bidderRequest.gdprConsent.gdprApplies + }; + } + if (bidderRequest.uspConsent) { payload.uspConsent = bidderRequest.uspConsent; } + if (bidderRequest.schain) { payload.schain = bidderRequest.schain; } + if (bidderRequest.userId) { payload.userId = bidderRequest.userId; } + }; + if (test) { payload.debug = true; } + const payloadString = JSON.stringify(payload); + return { + method: 'POST', + url: endpoint + BIDDER_ENDPOINT_AUCTION, + data: payloadString, + }; + }, + /** + * 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, bidRequest) { + const serverBody = serverResponse.body; + // const headerValue = serverResponse.headers.get('some-response-header'); + const bidResponses = []; + let bidResponse = null; + let value = null; + if (serverBody.hasOwnProperty('responses')) { + Object.keys(serverBody['responses']).forEach(key => { + value = serverBody['responses'][key]; + bidResponse = { + requestId: value['bid_id'], + cpm: value['cpm'], + width: value['width'], + height: value['height'], + creativeId: value['creative_id'], + currency: value['currency'], + netRevenue: value['net_revenue'], + ttl: value['ttl'], + ad: value['ad'], + mediasquare: { + 'bidder': value['bidder'], + 'code': value['code'] + } + }; + if (value.hasOwnProperty('deal_id')) { bidResponse['dealId'] = value['deal_id']; } + bidResponses.push(bidResponse); + }); + } + 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, gdprConsent, uspConsent) { + let params = ''; + let endpoint = document.location.search.match(/msq_test=true/) ? BIDDER_URL_TEST : BIDDER_URL_PROD; + if (serverResponses[0].body.hasOwnProperty('cookies') && typeof serverResponses[0].body.cookies === 'object') { + return serverResponses[0].body.cookies; + } else { + if (gdprConsent && typeof gdprConsent.consentString === 'string') { params += typeof gdprConsent.gdprApplies === 'boolean' ? `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}` : `&gdpr_consent=${gdprConsent.consentString}`; } + if (uspConsent && typeof uspConsent === 'string') { params += '&uspConsent=' + uspConsent } + return { + type: 'iframe', + url: endpoint + BIDDER_ENDPOINT_SYNC + '?type=iframe' + params + }; + } + }, + + /** + * Register bidder specific code, which will execute if a bid from this bidder won the auction + * @param {Bid} The bid that won the auction + */ + onBidWon: function(bid) { + // fires a pixel to confirm a winning bid + let params = []; + let endpoint = document.location.search.match(/msq_test=true/) ? BIDDER_URL_TEST : BIDDER_URL_PROD; + let paramsToSearchFor = ['cpm', 'size', 'mediaType', 'currency', 'creativeId', 'adUnitCode', 'timeToRespond', 'auctionId', 'requestId'] + if (bid.hasOwnProperty('mediasquare')) { + if (bid['mediasquare'].hasOwnProperty('bidder')) { params.push('bidder=' + bid['mediasquare']['bidder']); } + if (bid['mediasquare'].hasOwnProperty('code')) { params.push('code=' + bid['mediasquare']['code']); } + }; + for (let i = 0; i < paramsToSearchFor.length; i++) { + if (bid.hasOwnProperty(paramsToSearchFor[i])) { params.push(paramsToSearchFor[i] + '=' + bid[paramsToSearchFor[i]]); } + } + if (params.length > 0) { params = '?' + params.join('&'); } + ajax(endpoint + BIDDER_ENDPOINT_WINNING + params, null); + return true; + } + +} +registerBidder(spec); diff --git a/modules/mediasquareBidAdapter.md b/modules/mediasquareBidAdapter.md new file mode 100644 index 00000000000..f9f8d4be908 --- /dev/null +++ b/modules/mediasquareBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +``` +Module Name: MediaSquare Bid Adapter +Module Type: Bidder Adapter +Maintainer: tech@mediasquare.fr +``` + +# Description + +Connects to Mediasquare network for bids. + +Mediasquare bid adapter supports Banner only for the time being. + +# Test Parameters +``` +var adUnits = [ + // Banner adUnit + { + code: 'banner-div', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]] + } + }, + bids: [{ + bidder: 'mediasquare', + params: { + owner: "test", + code: "publishername_atf_desktop_rg_pave" + } + }] + }, +]; +``` diff --git a/modules/merkleIdSystem.js b/modules/merkleIdSystem.js new file mode 100644 index 00000000000..d6bf96618df --- /dev/null +++ b/modules/merkleIdSystem.js @@ -0,0 +1,80 @@ +/** + * This module adds merkleId to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/merkleIdSystem + * @requires module:modules/userId + */ + +import * as utils from '../src/utils.js' +import {ajax} from '../src/ajax.js'; +import {submodule} from '../src/hook.js' + +const MODULE_NAME = 'merkleId'; + +/** @type {Submodule} */ +export const merkleIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: MODULE_NAME, + /** + * decode the stored id value for passing to bid requests + * @function + * @param {string} value + * @returns {{merkleId:string}} + */ + decode(value) { + const id = (value && value.ppid && typeof value.ppid.id === 'string') ? value.ppid.id : undefined; + return id ? { 'merkleId': id } : undefined; + }, + /** + * performs action to obtain id and return a value in the callback's response argument + * @function + * @param {SubmoduleParams} [configParams] + * @param {ConsentData} [consentData] + * @returns {IdResponse|undefined} + */ + getId(configParams, consentData) { + if (!configParams || typeof configParams.pubid !== 'string') { + utils.logError('User ID - merkleId submodule requires a valid pubid to be defined'); + return; + } + + if (typeof configParams.ptk !== 'string') { + utils.logError('User ID - merkleId submodule requires a valid ptk string to be defined'); + return; + } + + if (consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies) { + utils.logError('User ID - merkleId submodule does not currently handle consent strings'); + return; + } + + const url = `https://mid.rkdms.com/idsv2?ptk=${configParams.ptk}&pubid=${configParams.pubid}`; + + const resp = function (callback) { + const callbacks = { + success: response => { + let responseObj; + if (response) { + try { + responseObj = JSON.parse(response); + } catch (error) { + utils.logError(error); + } + } + callback(responseObj); + }, + error: error => { + utils.logError(`${MODULE_NAME}: merkleId fetch encountered an error`, error); + callback(); + } + }; + ajax(url, callbacks, undefined, {method: 'GET', withCredentials: true}); + }; + return {callback: resp}; + } +}; + +submodule('userId', merkleIdSubmodule); diff --git a/modules/nextrollBidAdapter.js b/modules/nextrollBidAdapter.js index 0f273792154..02ebcd3f87a 100644 --- a/modules/nextrollBidAdapter.js +++ b/modules/nextrollBidAdapter.js @@ -1,16 +1,16 @@ import * as utils from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER } from '../src/mediaTypes.js'; +import { BANNER, NATIVE } from '../src/mediaTypes.js'; import find from 'core-js-pure/features/array/find.js'; const BIDDER_CODE = 'nextroll'; const BIDDER_ENDPOINT = 'https://d.adroll.com/bid/prebid/'; -const ADAPTER_VERSION = 4; +const ADAPTER_VERSION = 5; export const spec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER], + supportedMediaTypes: [BANNER, NATIVE], /** * Determines whether or not the given bid request is valid. @@ -30,12 +30,12 @@ export const spec = { */ buildRequests: function (validBidRequests, bidderRequest) { let topLocation = utils.parseUrl(utils.deepAccess(bidderRequest, 'refererInfo.referer')); - let consent = hasCCPAConsent(bidderRequest); - return validBidRequests.map((bidRequest, index) => { + + return validBidRequests.map((bidRequest) => { return { method: 'POST', options: { - withCredentials: consent, + withCredentials: true, }, url: BIDDER_ENDPOINT, data: { @@ -43,9 +43,8 @@ export const spec = { imp: { id: bidRequest.bidId, bidfloor: utils.getBidIdParameter('bidfloor', bidRequest.params), - banner: { - format: _getSizes(bidRequest) - }, + banner: _getBanner(bidRequest), + native: _getNative(utils.deepAccess(bidRequest, 'mediaTypes.native')), ext: { zone: { id: utils.getBidIdParameter('zoneId', bidRequest.params) @@ -60,9 +59,10 @@ export const spec = { site: _getSite(bidRequest, topLocation), seller: _getSeller(bidRequest), device: _getDevice(bidRequest), + regs: _getRegs(bidderRequest) } - } - }) + }; + }); }, /** @@ -82,10 +82,104 @@ export const spec = { } } +function _getBanner(bidRequest) { + let sizes = _getSizes(bidRequest); + if (sizes === undefined) return undefined; + return {format: sizes}; +} + +function _getNative(mediaTypeNative) { + if (mediaTypeNative === undefined) return undefined; + let assets = _getNativeAssets(mediaTypeNative); + if (assets === undefined || assets.length == 0) return undefined; + return { + request: { + native: { + assets: assets + } + } + }; +} + +/* + id: Unique numeric id for the asset + kind: OpenRTB kind of asset. Supported: title, img and data. + key: Name of property that comes in the mediaType.native object. + type: OpenRTB type for that spefic kind of asset. + required: Overrides the asset required field configured, only overrides when is true. +*/ +const NATIVE_ASSET_MAP = [ + {id: 1, kind: 'title', key: 'title', required: true}, + {id: 2, kind: 'img', key: 'image', type: 3, required: true}, + {id: 3, kind: 'img', key: 'icon', type: 1}, + {id: 4, kind: 'img', key: 'logo', type: 2}, + {id: 5, kind: 'data', key: 'sponsoredBy', type: 1}, + {id: 6, kind: 'data', key: 'body', type: 2} +]; + +const ASSET_KIND_MAP = { + title: _getTitleAsset, + img: _getImageAsset, + data: _getDataAsset, +}; + +function _getAsset(mediaTypeNative, assetMap) { + const asset = mediaTypeNative[assetMap.key]; + if (asset === undefined) return undefined; + const assetFunc = ASSET_KIND_MAP[assetMap.kind]; + return { + id: assetMap.id, + required: (assetMap.required || !!asset.required) ? 1 : 0, + [assetMap.kind]: assetFunc(asset, assetMap) + }; +} + +function _getTitleAsset(title, _assetMap) { + return {len: title.len || 0}; +} + +function _getMinAspectRatio(aspectRatio, property) { + if (!utils.isPlainObject(aspectRatio)) return 1; + + const ratio = aspectRatio['ratio_' + property]; + const min = aspectRatio['min_' + property]; + + if (utils.isNumber(ratio)) return ratio; + if (utils.isNumber(min)) return min; + + return 1; +} + +function _getImageAsset(image, assetMap) { + const sizes = image.sizes; + const aspectRatio = image.aspect_ratios ? image.aspect_ratios[0] : undefined; + + return { + type: assetMap.type, + w: (sizes ? sizes[0] : undefined), + h: (sizes ? sizes[1] : undefined), + wmin: _getMinAspectRatio(aspectRatio, 'width'), + hmin: _getMinAspectRatio(aspectRatio, 'height'), + }; +} + +function _getDataAsset(data, assetMap) { + return { + type: assetMap.type, + len: data.len || 0 + }; +} + +function _getNativeAssets(mediaTypeNative) { + return NATIVE_ASSET_MAP + .map(assetMap => _getAsset(mediaTypeNative, assetMap)) + .filter(asset => asset !== undefined); +} + function _getUser(requests) { - let id = utils.deepAccess(requests, '0.userId.nextroll'); + const id = utils.deepAccess(requests, '0.userId.nextroll'); if (id === undefined) { - return + return; } return { @@ -95,12 +189,11 @@ function _getUser(requests) { id }] } - } + }; } function _buildResponse(bidResponse, bid) { - const adm = utils.replaceAuctionPrice(bid.adm, bid.price); - return { + let response = { requestId: bidResponse.id, cpm: bid.price, width: bid.w, @@ -109,8 +202,53 @@ function _buildResponse(bidResponse, bid) { dealId: bidResponse.dealId, currency: 'USD', netRevenue: true, - ttl: 300, - ad: adm + ttl: 300 + }; + if (utils.isStr(bid.adm)) { + response.mediaType = BANNER; + response.ad = utils.replaceAuctionPrice(bid.adm, bid.price); + } else { + response.mediaType = NATIVE; + response.native = _getNativeResponse(bid.adm, bid.price); + } + return response; +} + +const privacyLink = 'https://info.evidon.com/pub_info/573'; +const privacyIcon = 'https://c.betrad.com/pub/icon1.png'; + +function _getNativeResponse(adm, price) { + let baseResponse = { + clickTrackers: (adm.link && adm.link.clicktrackers) || [], + jstracker: adm.jstracker || [], + clickUrl: utils.replaceAuctionPrice(adm.link.url, price), + impressionTrackers: adm.imptrackers.map(impTracker => utils.replaceAuctionPrice(impTracker, price)), + privacyLink: privacyLink, + privacyIcon: privacyIcon + }; + return adm.assets.reduce((accResponse, asset) => { + const assetMaps = NATIVE_ASSET_MAP.filter(assetMap => assetMap.id === asset.id && asset[assetMap.kind] !== undefined); + if (assetMaps.length === 0) return accResponse; + const assetMap = assetMaps[0]; + accResponse[assetMap.key] = _getAssetResponse(asset, assetMap); + return accResponse; + }, baseResponse); +} + +function _getAssetResponse(asset, assetMap) { + switch (assetMap.kind) { + case 'title': + return asset.title.text; + + case 'img': + return { + url: asset.img.url, + width: asset.img.w, + height: asset.img.h + }; + + case 'data': + return asset.data.value; } } @@ -121,22 +259,25 @@ function _getSite(bidRequest, topLocation) { publisher: { id: utils.getBidIdParameter('publisherId', bidRequest.params) } - } + }; } function _getSeller(bidRequest) { return { id: utils.getBidIdParameter('sellerId', bidRequest.params) - } + }; } function _getSizes(bidRequest) { + if (!utils.isArray(bidRequest.sizes)) { + return undefined; + } return bidRequest.sizes.filter(_isValidSize).map(size => { return { w: size[0], h: size[1] } - }) + }); } function _isValidSize(size) { @@ -150,7 +291,18 @@ function _getDevice(_bidRequest) { language: navigator['language'], os: _getOs(navigator.userAgent.toLowerCase()), osv: _getOsVersion(navigator.userAgent) + }; +} + +function _getRegs(bidderRequest) { + if (!bidderRequest || !bidderRequest.uspConsent) { + return undefined; } + return { + ext: { + us_privacy: bidderRequest.uspConsent + } + }; } function _getOs(userAgent) { @@ -170,7 +322,7 @@ function _getOs(userAgent) { } function _getOsVersion(userAgent) { - let clientStrings = [ + const clientStrings = [ { s: 'Android', r: /Android/ }, { s: 'iOS', r: /(iPhone|iPad|iPod)/ }, { s: 'Mac OS X', r: /Mac OS X/ }, @@ -190,25 +342,4 @@ function _getOsVersion(userAgent) { return cs ? cs.s : 'unknown'; } -export function hasCCPAConsent(bidderRequest) { - if (typeof bidderRequest.uspConsent !== 'string') { - return true; - } - const usps = bidderRequest.uspConsent; - const version = usps[0]; - - // If we don't support the consent string, assume no-consent. - if (version !== '1' || usps.length < 3) { - return false; - } - - const notice = usps[1]; - const optOut = usps[2]; - - if (notice === 'N' || optOut === 'Y') { - return false; - } - return true; -} - registerBidder(spec); diff --git a/modules/nextrollBidAdapter.md b/modules/nextrollBidAdapter.md index 2f57987f985..c706839c453 100644 --- a/modules/nextrollBidAdapter.md +++ b/modules/nextrollBidAdapter.md @@ -9,9 +9,11 @@ Maintainer: prebid@nextroll.com # Description Module that connects to NextRoll's bidders. -The NextRoll bid adapter supports Banner format only. +The NextRoll bid adapter supports banner and native format. # Test Parameters + +## Banner Example ``` javascript var adUnits = [ { @@ -47,4 +49,29 @@ var adUnits = [ }] } ] +``` + +## Native Example +```javascript +var adUnits = [ + { + code: 'div-1', + mediaTypes: { + native: { + title: { required: true, len: 80 }, + image: { required: true, sizes: [728, 90] }, + sponsoredBy: { required: false, len: 20 } + } + }, + bids: [{ + bidder: 'nextroll', + params: { + bidfloor: 1, + zoneId: "13144370", + publisherId: "publisherId", + sellerId: "sellerId", + } + }] + } +]; ``` \ No newline at end of file diff --git a/modules/nobidBidAdapter.js b/modules/nobidBidAdapter.js index dacb76a9a98..00cb14dc01d 100644 --- a/modules/nobidBidAdapter.js +++ b/modules/nobidBidAdapter.js @@ -6,7 +6,7 @@ import { getStorageManager } from '../src/storageManager.js'; const storage = getStorageManager(); const BIDDER_CODE = 'nobid'; -window.nobidVersion = '1.2.5'; +window.nobidVersion = '1.2.8'; window.nobid = window.nobid || {}; window.nobid.bidResponses = window.nobid.bidResponses || {}; window.nobid.timeoutTotal = 0; @@ -24,6 +24,15 @@ function nobidSetCookie(cname, cvalue, hours) { function nobidGetCookie(cname) { return storage.getCookie(cname); } +function nobidHasPurpose1Consent(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 nobidBuildRequests(bids, bidderRequest) { var serializeState = function(divIds, siteId, adunits) { var filterAdUnitsByIds = function(divIds, adUnits) { @@ -200,7 +209,7 @@ function nobidBuildRequests(bids, bidderRequest) { var adType = 'banner'; const videoMediaType = utils.deepAccess(bid, 'mediaTypes.video'); const context = utils.deepAccess(bid, 'mediaTypes.video.context'); - if (bid.mediaType === VIDEO || (videoMediaType && context === 'instream')) { + if (bid.mediaType === VIDEO || (videoMediaType && (context === 'instream' || context === 'outstream'))) { adType = 'video'; } @@ -287,6 +296,23 @@ window.nobid.renderTag = function(doc, id, win) { } log('nobid.renderTag() tag NOT FOUND *ERROR*', id); } +window.addEventListener('message', function (event) { + let key = event.message ? 'message' : 'data'; + var msg = '' + event[key]; + if (msg.substring(0, 'nbTagRenderer.requestAdMarkup|'.length) === 'nbTagRenderer.requestAdMarkup|') { + log('Prebid received nbTagRenderer.requestAdMarkup event'); + var adId = msg.substring(msg.indexOf('|') + 1); + if (window.nobid && window.nobid.bidResponses) { + var bid = window.nobid.bidResponses['' + adId]; + if (bid && bid.adm2) { + var markup = bid.adm2; + if (markup) { + event.source.postMessage('nbTagRenderer.renderAdInSafeFrame|' + markup, '*'); + } + } + } + } +}, false); export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO], @@ -329,11 +355,18 @@ export const spec = { window.nobid.refreshCount++; const payloadString = JSON.stringify(payload).replace(/'|&|#/g, '') const endpoint = buildEndpoint(); + + let options = {}; + if (!nobidHasPurpose1Consent(bidderRequest)) { + options = { withCredentials: false }; + } + return { method: 'POST', url: endpoint, data: payloadString, - bidderRequest + bidderRequest, + options }; }, /** diff --git a/modules/oneVideoBidAdapter.js b/modules/oneVideoBidAdapter.js index e43e7eff0f8..c5bc054ac04 100644 --- a/modules/oneVideoBidAdapter.js +++ b/modules/oneVideoBidAdapter.js @@ -1,13 +1,14 @@ import * as utils from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; + const BIDDER_CODE = 'oneVideo'; export const spec = { code: 'oneVideo', - VERSION: '3.0.2', + VERSION: '3.0.4', ENDPOINT: 'https://ads.adaptv.advertising.com/rtb/openrtb?ext_id=', - SYNC_ENDPOINT1: 'https://cm.g.doubleclick.net/pixel?google_nid=adaptv_dbm&google_cm&google_sc', - SYNC_ENDPOINT2: 'https://pr-bh.ybp.yahoo.com/sync/adaptv_ortb/{combo_uid}', - SYNC_ENDPOINT3: 'https://match.adsrvr.org/track/cmf/generic?ttd_pid=adaptv&ttd_tpi=1', + E2ETESTENDPOINT: 'https://ads-wc.v.ssp.yahoo.com/rtb/openrtb?ext_id=', + SYNC_ENDPOINT1: 'https://pixel.advertising.com/ups/57304/sync?gdpr=&gdpr_consent=&_origin=0&redir=true', + SYNC_ENDPOINT2: 'https://match.adsrvr.org/track/cmf/generic?ttd_pid=adaptv&ttd_tpi=1', supportedMediaTypes: ['video', 'banner'], /** * Determines whether or not the given bid request is valid. @@ -25,14 +26,12 @@ export const spec = { return false; } - // Prevend DAP Outstream validation + // Prevend DAP Outstream validation, Banner DAP validation & Multi-Format adUnit support if (bid.mediaTypes.video) { if (bid.mediaTypes.video.context === 'outstream' && bid.params.video.display === 1) { return false; } - } - // Banner DAP validation - if (bid.mediaTypes.banner && (!bid.params.video.display)) { + } else if (bid.mediaTypes.banner && !bid.params.video.display) { return false; } @@ -54,11 +53,17 @@ export const spec = { let consentData = bidRequest ? bidRequest.gdprConsent : null; return bids.map(bid => { + let url = spec.ENDPOINT + let pubId = bid.params.pubId; + if (bid.params.video.e2etest) { + url = spec.E2ETESTENDPOINT; + pubId = 'HBExchange'; + } return { method: 'POST', /** removing adding local protocal since we * can get cookie data only if we call with https. */ - url: spec.ENDPOINT + bid.params.pubId, + url: url + pubId, data: getRequestData(bid, consentData, bidRequest), bidRequest: bid } @@ -130,17 +135,13 @@ export const spec = { type: 'image', url: spec.SYNC_ENDPOINT1 }, - { - type: 'image', - url: spec.SYNC_ENDPOINT2 - }, { type: 'image', url: `https://sync-tm.everesttech.net/upi/pid/m7y5t93k?gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${consentString}&redir=https%3A%2F%2Fpixel.advertising.com%2Fups%2F55986%2Fsync%3Fuid%3D%24%7BUSER_ID%7D%26_origin%3D0` + encodeURI(`&gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${consentString}`) }, { type: 'image', - url: spec.SYNC_ENDPOINT3 + url: spec.SYNC_ENDPOINT2 }]; } } @@ -257,6 +258,16 @@ function getRequestData(bid, consentData, bidRequest) { } } } + if (bid.params.video.hp == 1) { + bidData.source.ext.schain.nodes[0].hp = bid.params.video.hp; + } + } else if (bid.schain) { + bidData.source = { + ext: { + schain: bid.schain + } + } + bidData.source.ext.schain.nodes[0].rid = bidData.id; } if (bid.params.site && bid.params.site.id) { bidData.site.id = bid.params.site.id @@ -281,7 +292,16 @@ function getRequestData(bid, consentData, bidRequest) { bidData.regs.ext.us_privacy = bidRequest.uspConsent } } - + if (bid.params.video.e2etest) { + bidData.imp[0].bidfloor = null; + bidData.imp[0].video.w = 300; + bidData.imp[0].video.h = 250; + bidData.imp[0].video.mimes = ['video/mp4', 'application/javascript']; + bidData.imp[0].video.api = [2]; + bidData.site.page = 'https://verizonmedia.com'; + bidData.site.ref = 'https://verizonmedia.com'; + bidData.tmax = 1000; + } return bidData; } diff --git a/modules/oneVideoBidAdapter.md b/modules/oneVideoBidAdapter.md index 1805a6869d3..72f251aac04 100644 --- a/modules/oneVideoBidAdapter.md +++ b/modules/oneVideoBidAdapter.md @@ -5,11 +5,10 @@ **Maintainer**: deepthi.neeladri.sravana@verizonmedia.com # Description - Connects to Verizon Media's Video SSP (AKA ONE Video / Adap.tv) demand source to fetch bids. - -# Instream Video adUnit example & parameters +# Integration Examples: +## Instream Video adUnit example & parameters *Note:* The Video SSP ad server will respond with an VAST XML to load into your defined player. ``` var adUnits = [ @@ -34,7 +33,8 @@ Connects to Verizon Media's Video SSP (AKA ONE Video / Adap.tv) demand source to position: 1, delivery: [2], playbackmethod: [1,5], - sid: , + sid: YOUR_VSSP_ORG_ID, + hp: 1, rewarded: 1, placement: 1, inventoryid: 123, @@ -53,7 +53,7 @@ Connects to Verizon Media's Video SSP (AKA ONE Video / Adap.tv) demand source to } ] ``` -# Outstream Video adUnit example & parameters +## Outstream Video adUnit example & parameters *Note:* The Video SSP ad server will load it's own Outstream Renderer (player) as a fallback if no player is defined on the publisher page. The Outstream player will inject into the div id that has an identical adUnit code. ``` var adUnits = [ @@ -78,7 +78,8 @@ Connects to Verizon Media's Video SSP (AKA ONE Video / Adap.tv) demand source to position: 1, delivery: [2], playbackmethod: [1,5], - sid: , + sid: YOUR_VSSP_ORG_ID, + hp: 1, rewarded: 1, placement: 1, inventoryid: 123, @@ -98,7 +99,7 @@ Connects to Verizon Media's Video SSP (AKA ONE Video / Adap.tv) demand source to ] ``` -# S2S / Video: Dynamic Ad Placement (DAP) adUnit example & parameters +## S2S / Video: Dynamic Ad Placement (DAP) adUnit example & parameters *Note:* The Video SSP ad server will respond with HTML embed tag to be injected into an iFrame you create. ``` var adUnits = [ @@ -133,7 +134,7 @@ Connects to Verizon Media's Video SSP (AKA ONE Video / Adap.tv) demand source to } ] ``` -# Prebid.js / Banner: Dynamic Ad Placement (DAP) adUnit example & parameters +## Prebid.js / Banner: Dynamic Ad Placement (DAP) adUnit example & parameters *Note:* The Video SSP ad server will respond with HTML embed tag to be injected into an iFrame created by Google Ad Manager (GAM). ``` var adUnits = [ @@ -166,3 +167,130 @@ Connects to Verizon Media's Video SSP (AKA ONE Video / Adap.tv) demand source to } ] ``` + +# End 2 End Testing Mode +By passing bid.params.video.e2etest = true you will be able to receive a test creative when connecting via VPN location U.S West Coast. This will allow you to trubleshoot how your player/ad-server parses and uses the VAST XML response. +This automatically sets default values for the outbound bid-request to respond from our test exchange. +No need to override the site/ref urls or change your pubId +``` +var adUnits = [ + { + code: 'video-1', + mediaTypes: { + video: { + context: "instream", + playerSize: [480, 640] + } + }, + bids: [ + { + bidder: 'oneVideo', + params: { + video: { + playerWidth: 300, + playerHeight: 250, + mimes: ['video/mp4', 'application/javascript'], + e2etest: true + } + pubId: 'YOUR_PUBLISHER_ID' + } + } + ] + } +] +``` + +# Supply Chain Object Support +The oneVideoBidAdapter supports 2 methods for passing/creating an schain object. +1. By passing your Video SSP Org ID in the bid.video.params.sid - The adapter will create a new schain object and our ad-server will fill in the data for you. +2. Using the Prebid Supply Chain Object Module - The adapter will capture the schain object +*Note:* You cannot pass both schain object and bid.video.params.sid together. Option 1 will always be the default. + +## Create new schain using bid.video.params.sid +sid = your Video SSP Organization ID. +This is for direct publishers only. +``` +var adUnits = [ + { + code: 'video1', + mediaTypes: { + video: { + context: 'instream', + playerSize: [480, 640] + } + }, + bids: [ + { + bidder: 'oneVideo', + params: { + video: { + playerWidth: 480, + playerHeight: 640, + mimes: ['video/mp4', 'application/javascript'], + protocols: [2,5], + api: [2], + sid: + }, + site: { + id: 1, + page: 'https://verizonmedia.com', + referrer: 'https://verizonmedia.com' + }, + pubId: 'HBExchange' + } + } + ] + } + ] +``` + +## Pass global schain using pbjs.setConfig(SCHAIN_OBJECT) +For both Authorized resellers and direct publishers. +``` +pbjs.setConfig({ + "schain": { + "validation": "strict", + "config": { + "ver": "1.0", + "complete": 1, + "nodes": [{ + "asi": "some-platform.com", + "sid": "111111", + "hp": 1 + }] + } + } +}); + +var adUnits = [ + { + code: 'video1', + mediaTypes: { + video: { + context: 'instream', + playerSize: [480, 640] + } + }, + bids: [ + { + bidder: 'oneVideo', + params: { + video: { + playerWidth: 480, + playerHeight: 640, + mimes: ['video/mp4', 'application/javascript'], + protocols: [2,5], + api: [2], + }, + site: { + id: 1, + page: 'https://verizonmedia.com', + referrer: 'https://verizonmedia.com' + }, + pubId: 'HBExchange' + } + } + ] + } + ] +``` diff --git a/modules/onetagBidAdapter.js b/modules/onetagBidAdapter.js index f2cea34bb1a..fd66c8ce69f 100644 --- a/modules/onetagBidAdapter.js +++ b/modules/onetagBidAdapter.js @@ -1,7 +1,13 @@ 'use strict'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; -const { registerBidder } = require('../src/adapters/bidderFactory.js'); +import { INSTREAM, OUTSTREAM } from '../src/video.js'; +import { Renderer } from '../src/Renderer.js'; +import find from 'core-js-pure/features/array/find.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; + +const storage = getStorageManager(); const ENDPOINT = 'https://onetag-sys.com/prebid-request'; const USER_SYNC_ENDPOINT = 'https://onetag-sys.com/usync/'; @@ -29,9 +35,7 @@ export function isValid(type, bid) { return parseSizes(bid).length > 0; } else if (type === VIDEO && hasTypeVideo(bid)) { const context = bid.mediaTypes.video.context; - if (context === 'outstream') { - return parseVideoSize(bid).length > 0 && typeof bid.renderer !== 'undefined' && typeof bid.renderer.render !== 'undefined' && typeof bid.renderer.url !== 'undefined'; - } else if (context === 'instream') { + if (context === 'outstream' || context === 'instream') { return parseVideoSize(bid).length > 0; } } @@ -44,140 +48,191 @@ export function isValid(type, bid) { * @param {validBidRequests[]} - an array of bids * @return ServerRequest Info describing the request to the server. */ - function buildRequests(validBidRequests, bidderRequest) { - const bids = requestsToBids(validBidRequests); - const bidObject = {'bids': bids}; - const pageInfo = getPageInfo(); - - const payload = Object.assign(bidObject, pageInfo); - + const payload = { + bids: requestsToBids(validBidRequests), + ...getPageInfo() + }; if (bidderRequest && bidderRequest.gdprConsent) { payload.gdprConsent = { consentString: bidderRequest.gdprConsent.consentString, consentRequired: bidderRequest.gdprConsent.gdprApplies }; } - if (bidderRequest && bidderRequest.uspConsent) { payload.usPrivacy = bidderRequest.uspConsent; } - if (bidderRequest && bidderRequest.userId) { payload.userId = bidderRequest.userId; } - - const payloadString = JSON.stringify(payload); - + try { + if (storage.hasLocalStorage()) { + payload.onetagSid = storage.getDataFromLocalStorage('onetag_sid'); + } + } catch (e) {} return { method: 'POST', url: ENDPOINT, - data: payloadString + data: JSON.stringify(payload) } } -function interpretResponse(serverResponse, request) { - let body = serverResponse.body; +function interpretResponse(serverResponse, bidderRequest) { + const body = serverResponse.body; const bids = []; - - if (typeof serverResponse === 'string') { - try { - body = JSON.parse(serverResponse); - } catch (e) { - return bids; - } - } - + const requestData = JSON.parse(bidderRequest.data); if (!body || (body.nobid && body.nobid === true)) { return bids; } if (!body.bids || !Array.isArray(body.bids) || body.bids.length === 0) { return bids; } - - body.bids.forEach(function(bid) { - let responseBid = { - requestId: bid.requestId, - cpm: bid.cpm, - width: bid.width, - height: bid.height, - creativeId: bid.creativeId, - dealId: bid.dealId ? bid.dealId : '', - currency: bid.currency, + body.bids.forEach(({ + requestId, + cpm, + width, + height, + creativeId, + dealId, + currency, + mediaType, + ttl, + rendererUrl, + ad, + vastUrl, + videoCacheKey + }) => { + const responseBid = { + requestId, + cpm, + width, + height, + creativeId, + dealId: dealId == null ? dealId : '', + currency, netRevenue: false, - mediaType: bid.mediaType, - ttl: bid.ttl || 300 + meta: { + mediaType + }, + ttl: ttl || 300 }; - - if (bid.mediaType === BANNER) { - responseBid.ad = bid.ad; - } else if (bid.mediaType === VIDEO) { - responseBid.vastXml = bid.ad; + if (mediaType === BANNER) { + responseBid.ad = ad; + } else if (mediaType === VIDEO) { + const {context, adUnitCode} = find(requestData.bids, (item) => item.bidId === requestId); + if (context === INSTREAM) { + responseBid.vastUrl = vastUrl; + responseBid.videoCacheKey = videoCacheKey; + } else if (context === OUTSTREAM) { + responseBid.vastXml = ad; + responseBid.vastUrl = vastUrl; + if (rendererUrl) { + responseBid.renderer = createRenderer({requestId, rendererUrl, adUnitCode}); + } + } } - bids.push(responseBid); }); - return bids; } -/** - * Returns information about the page needed by the server in an object to be converted in JSON - * @returns {{location: *, referrer: (*|string), masked: *, wWidth: (*|Number), wHeight: (*|Number), sWidth, sHeight, date: string, timeOffset: number}} - */ -function getPageInfo() { - let w, d, l, r, m, p, e, t, s; - for (w = window, d = w.document, l = d.location.href, r = d.referrer, m = 0, e = encodeURIComponent, t = new Date(), s = screen; w !== w.parent;) { - try { - p = w.parent; l = p.location.href; r = p.document.referrer; w = p; - } catch (e) { - m = top !== w.parent ? 2 : 1; - break - } +function createRenderer(bid, rendererOptions = {}) { + const renderer = Renderer.install({ + id: bid.requestId, + url: bid.rendererUrl, + config: rendererOptions, + adUnitCode: bid.adUnitCode, + loaded: false + }); + try { + renderer.setRender(onetagRenderer); + } catch (e) { + } - let isDocHidden; - let xOffset; - let yOffset; + return renderer; +} + +function onetagRenderer({renderer, width, height, vastXml, adUnitCode}) { + renderer.push(() => { + window.onetag.Player.init({ + width, + height, + vastXml, + nodeId: adUnitCode, + config: renderer.getConfig() + }); + }); +} + +function getFrameNesting() { + let topmostFrame = window; + let parent = window.parent; + let currentFrameNesting = 0; try { - if (typeof w.document.hidden !== 'undefined') { - isDocHidden = w.document.hidden; - } else if (typeof w.document['msHidden'] !== 'undefined') { - isDocHidden = w.document['msHidden']; - } else if (typeof w.document['webkitHidden'] !== 'undefined') { - isDocHidden = w.document['webkitHidden']; - } else { - isDocHidden = null; + while (topmostFrame !== topmostFrame.parent) { + parent = topmostFrame.parent; + // eslint-disable-next-line no-unused-expressions + parent.location.href; + topmostFrame = topmostFrame.parent; } } catch (e) { - isDocHidden = null; + currentFrameNesting = parent === topmostFrame.top ? 1 : 2; + } + return { + topmostFrame, + currentFrameNesting } +} + +function getDocumentVisibility(window) { try { - xOffset = w.pageXOffset; - yOffset = w.pageYOffset; + if (typeof window.document.hidden !== 'undefined') { + return window.document.hidden; + } else if (typeof window.document['msHidden'] !== 'undefined') { + return window.document['msHidden']; + } else if (typeof window.document['webkitHidden'] !== 'undefined') { + return window.document['webkitHidden']; + } else { + return null; + } } catch (e) { - xOffset = null; - yOffset = null; + return null; } +} + +/** + * Returns information about the page needed by the server in an object to be converted in JSON + * @returns {{location: *, referrer: (*|string), masked: *, wWidth: (*|Number), wHeight: (*|Number), sWidth, sHeight, date: string, timeOffset: number}} + */ +function getPageInfo() { + const { topmostFrame, currentFrameNesting } = getFrameNesting(); return { - location: e(l), - referrer: e(r) || '0', - masked: m, - wWidth: w.innerWidth, - wHeight: w.innerHeight, - oWidth: w.outerWidth, - oHeight: w.outerHeight, - sWidth: s.width, - sHeight: s.height, - aWidth: s.availWidth, - aHeight: s.availHeight, - sLeft: 'screenLeft' in w ? w.screenLeft : w.screenX, - sTop: 'screenTop' in w ? w.screenTop : w.screenY, - xOffset: xOffset, - yOffset: yOffset, - docHidden: isDocHidden, + location: topmostFrame.location.href, + referrer: + topmostFrame.document.referrer !== '' + ? topmostFrame.document.referrer + : null, + masked: currentFrameNesting, + wWidth: topmostFrame.innerWidth, + wHeight: topmostFrame.innerHeight, + oWidth: topmostFrame.outerWidth, + oHeight: topmostFrame.outerHeight, + sWidth: topmostFrame.screen.width, + sHeight: topmostFrame.screen.height, + aWidth: topmostFrame.screen.availWidth, + aHeight: topmostFrame.screen.availHeight, + sLeft: 'screenLeft' in topmostFrame ? topmostFrame.screenLeft : topmostFrame.screenX, + sTop: 'screenTop' in topmostFrame ? topmostFrame.screenTop : topmostFrame.screenY, + xOffset: topmostFrame.pageXOffset, + yOffset: topmostFrame.pageYOffset, + docHidden: getDocumentVisibility(topmostFrame), + docHeight: topmostFrame.document.body ? topmostFrame.document.body.scrollHeight : null, hLength: history.length, - date: t.toUTCString(), - timeOffset: t.getTimezoneOffset() + timing: getTiming(), + version: { + prebid: '$prebid.version$', + adapter: '1.0.0' + } }; } @@ -217,12 +272,53 @@ function setGeneralInfo(bidRequest) { this['auctionId'] = bidRequest.auctionId; this['transactionId'] = bidRequest.transactionId; this['pubId'] = params.pubId; + this['ext'] = params.ext; if (params.pubClick) { this['click'] = params.pubClick; } if (params.dealId) { this['dealId'] = params.dealId; } + const coords = getSpaceCoords(bidRequest.adUnitCode); + if (coords) { + this['coords'] = coords; + } +} + +function getSpaceCoords(id) { + const space = document.getElementById(id); + try { + const { top, left, width, height } = space.getBoundingClientRect(); + let window = space.ownerDocument.defaultView; + const coords = { top: top + window.pageYOffset, left: left + window.pageXOffset, width, height }; + let frame = window.frameElement; + while (frame != null) { + const { top, left } = frame.getBoundingClientRect(); + coords.top += top + window.pageYOffset; + coords.left += left + window.pageXOffset; + window = window.parent; + frame = window.frameElement; + } + return coords; + } catch (e) { + return null; + } +} + +function getTiming() { + try { + if (window.performance != null && window.performance.timing != null) { + const timing = {}; + const perf = window.performance.timing; + timing.pageLoadTime = perf.loadEventEnd - perf.navigationStart; + timing.connectTime = perf.responseEnd - perf.requestStart; + timing.renderTime = perf.domComplete - perf.domLoading; + return timing; + } + } catch (e) { + return null; + } + return null; } function parseVideoSize(bid) { @@ -247,7 +343,7 @@ function parseSizes(bid) { function getSizes(sizes) { const ret = []; - for (let i = 0, lenght = sizes.length; i < lenght; i++) { + for (let i = 0; i < sizes.length; i++) { const size = sizes[i]; ret.push({width: size[0], height: size[1]}) } @@ -255,35 +351,35 @@ function getSizes(sizes) { } function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { - const syncs = []; - if (syncOptions.iframeEnabled) { - const rnd = new Date().getTime(); - let params = '?cb=' + rnd; - - if (gdprConsent && typeof gdprConsent.consentString === 'string') { - params += '&gdpr_consent=' + gdprConsent.consentString; - if (typeof gdprConsent.gdprApplies === 'boolean') { - params += '&gdpr=' + (gdprConsent.gdprApplies ? 1 : 0); - } - } - - if (uspConsent && typeof uspConsent === 'string') { - params += '&us_privacy=' + uspConsent; + let syncs = []; + let params = ''; + if (gdprConsent && typeof gdprConsent.consentString === 'string') { + params += '&gdpr_consent=' + gdprConsent.consentString; + if (typeof gdprConsent.gdprApplies === 'boolean') { + params += '&gdpr=' + (gdprConsent.gdprApplies ? 1 : 0); } - + } + if (uspConsent && typeof uspConsent === 'string') { + params += '&us_privacy=' + uspConsent; + } + if (syncOptions.iframeEnabled) { syncs.push({ type: 'iframe', - url: USER_SYNC_ENDPOINT + params + url: USER_SYNC_ENDPOINT + '?cb=' + new Date().getTime() + params + }); + } + if (syncOptions.pixelEnabled) { + syncs.push({ + type: 'image', + url: USER_SYNC_ENDPOINT + '?tag=img' + params }); } return syncs; } export const spec = { - code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO], - isBidRequestValid: isBidRequestValid, buildRequests: buildRequests, interpretResponse: interpretResponse, @@ -291,5 +387,4 @@ export const spec = { }; -// Starting point registerBidder(spec); diff --git a/modules/onetagBidAdapter.md b/modules/onetagBidAdapter.md index 9757be4d440..7814403afbe 100644 --- a/modules/onetagBidAdapter.md +++ b/modules/onetagBidAdapter.md @@ -27,7 +27,7 @@ OneTag Bid Adapter supports banner and video at present. } }] }, { - code: 'video-space', + code: 'video-instream-space', mediaTypes: { video: { context: "instream", @@ -41,6 +41,20 @@ OneTag Bid Adapter supports banner and video at present. pubId: "your_publisher_id" // required, testing pubId: "386276e072" } }] + }, { + code: 'video-outstream-space', + mediaTypes: { + video: { + context: "outstream", + playerSize: [640,480] + } + }, + bids: [{ + bidder: "onetag", + params: { + pubId: "your_publisher_id" // required, testing pubId: "386276e072" + } + }] }]; ``` diff --git a/modules/onomagicBidAdapter.js b/modules/onomagicBidAdapter.js new file mode 100644 index 00000000000..55fca29fbf3 --- /dev/null +++ b/modules/onomagicBidAdapter.js @@ -0,0 +1,246 @@ +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 = 'onomagic'; +const URL = 'https://bidder.onomagic.com/hb'; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs +}; + +function buildRequests(bidReqs, bidderRequest) { + try { + let referrer = ''; + if (bidderRequest && bidderRequest.refererInfo) { + referrer = bidderRequest.refererInfo.referer; + } + const onomagicImps = []; + const publisherId = utils.getBidIdParameter('publisherId', bidReqs[0].params); + utils._each(bidReqs, function (bid) { + 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); + const viewabilityAmount = _isViewabilityMeasurable(element) + ? _getViewability(element, utils.getWindowTop(), minSize) + : 'na'; + const viewabilityAmountRounded = isNaN(viewabilityAmount) ? viewabilityAmount : Math.round(viewabilityAmount); + + const imp = { + id: bid.bidId, + banner: { + format: processedSizes, + ext: { + viewability: viewabilityAmountRounded + } + }, + tagid: String(bid.adUnitCode) + }; + const bidFloor = utils.getBidIdParameter('bidFloor', bid.params); + if (bidFloor) { + imp.bidfloor = bidFloor; + } + onomagicImps.push(imp); + }); + const onomagicBidReq = { + id: utils.getUniqueIdentifierStr(), + imp: onomagicImps, + site: { + domain: utils.parseUrl(referrer).host, + page: referrer, + publisher: { + id: publisherId + } + }, + device: { + devicetype: _getDeviceType(), + w: screen.width, + h: screen.height + }, + tmax: config.getConfig('bidderTimeout') + }; + + return { + method: 'POST', + url: URL, + data: JSON.stringify(onomagicBidReq), + options: {contentType: 'text/plain', withCredentials: false} + }; + } catch (e) { + utils.logError(e, {bidReqs, bidderRequest}); + } +} + +function isBidRequestValid(bid) { + if (bid.bidder !== BIDDER_CODE || typeof bid.params === 'undefined') { + return false; + } + + if (typeof bid.params.publisherId === 'undefined') { + return false; + } + + return true; +} + +function interpretResponse(serverResponse) { + if (!serverResponse.body || typeof serverResponse.body != 'object') { + utils.logWarn('Onomagic server returned empty/non-json response: ' + JSON.stringify(serverResponse.body)); + return []; + } + const { body: {id, seatbid} } = serverResponse; + try { + const onomagicBidResponses = []; + if (id && + seatbid && + seatbid.length > 0 && + seatbid[0].bid && + seatbid[0].bid.length > 0) { + seatbid[0].bid.map(onomagicBid => { + onomagicBidResponses.push({ + requestId: onomagicBid.impid, + cpm: parseFloat(onomagicBid.price), + width: parseInt(onomagicBid.w), + height: parseInt(onomagicBid.h), + creativeId: onomagicBid.crid || onomagicBid.id, + currency: 'USD', + netRevenue: true, + mediaType: BANNER, + ad: _getAdMarkup(onomagicBid), + ttl: 60 + }); + }); + } + return onomagicBidResponses; + } catch (e) { + utils.logError(e, {id, seatbid}); + } +} + +// Don't do user sync for now +function getUserSyncs(syncOptions, responses, gdprConsent) { + return []; +} + +function _isMobile() { + return (/(ios|ipod|ipad|iphone|android)/i).test(navigator.userAgent); +} + +function _isConnectedTV() { + return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(navigator.userAgent); +} + +function _getDeviceType() { + return _isMobile() ? 1 : _isConnectedTV() ? 3 : 2; +} + +function _getAdMarkup(bid) { + let adm = bid.adm; + if ('nurl' in bid) { + adm += utils.createTrackPixelHtml(bid.nurl); + } + return adm; +} + +function _isViewabilityMeasurable(element) { + return !_isIframe() && element !== null; +} + +function _getViewability(element, topWin, { w, h } = {}) { + return utils.getWindowTop().document.visibilityState === 'visible' + ? _getPercentInView(element, topWin, { w, h }) + : 0; +} + +function _isIframe() { + try { + return utils.getWindowSelf() !== utils.getWindowTop(); + } catch (e) { + return true; + } +} + +function _getMinSize(sizes) { + return sizes.reduce((min, size) => size.h * size.w < min.h * min.w ? size : min); +} + +function _getBoundingBox(element, { w, h } = {}) { + let { width, height, left, top, right, bottom } = element.getBoundingClientRect(); + + if ((width === 0 || height === 0) && w && h) { + width = w; + height = h; + right = left + w; + bottom = top + h; + } + + return { width, height, left, top, right, bottom }; +} + +function _getIntersectionOfRects(rects) { + const bbox = { + left: rects[0].left, + right: rects[0].right, + top: rects[0].top, + bottom: rects[0].bottom + }; + + for (let i = 1; i < rects.length; ++i) { + bbox.left = Math.max(bbox.left, rects[i].left); + bbox.right = Math.min(bbox.right, rects[i].right); + + if (bbox.left >= bbox.right) { + return null; + } + + bbox.top = Math.max(bbox.top, rects[i].top); + bbox.bottom = Math.min(bbox.bottom, rects[i].bottom); + + if (bbox.top >= bbox.bottom) { + return null; + } + } + + bbox.width = bbox.right - bbox.left; + bbox.height = bbox.bottom - bbox.top; + + return bbox; +} + +function _getPercentInView(element, topWin, { w, h } = {}) { + const elementBoundingBox = _getBoundingBox(element, { w, h }); + + // Obtain the intersection of the element and the viewport + const elementInViewBoundingBox = _getIntersectionOfRects([ { + left: 0, + top: 0, + right: topWin.innerWidth, + bottom: topWin.innerHeight + }, elementBoundingBox ]); + + let elementInViewArea, elementTotalArea; + + if (elementInViewBoundingBox !== null) { + // Some or all of the element is in view + elementInViewArea = elementInViewBoundingBox.width * elementInViewBoundingBox.height; + elementTotalArea = elementBoundingBox.width * elementBoundingBox.height; + + return ((elementInViewArea / elementTotalArea) * 100); + } + + // No overlap between element and the viewport; therefore, the element + // lies completely out of view + return 0; +} + +registerBidder(spec); diff --git a/modules/onomagicBidAdapter.md b/modules/onomagicBidAdapter.md new file mode 100644 index 00000000000..7222a506b2c --- /dev/null +++ b/modules/onomagicBidAdapter.md @@ -0,0 +1,46 @@ +# Overview + +``` +Module Name: Onomagic Bid Adapter +Module Type: Bidder Adapter +Maintainer: vyatsun@gmail.com +``` + +# Description + +Onomagic's adapter integration to the Prebid library. + +# Test Parameters + +``` +var adUnits = [ + { + code: 'test-leaderboard', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + bids: [{ + bidder: 'onomagic', + params: { + publisherId: 20167, + bidFloor: 0.01 + } + }] + }, { + code: 'test-banner', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [{ + bidder: 'onomagic', + params: { + publisherId: 20167 + } + }] + } +] +``` diff --git a/modules/openxAnalyticsAdapter.js b/modules/openxAnalyticsAdapter.js index 7addfe68bc6..07966e9e401 100644 --- a/modules/openxAnalyticsAdapter.js +++ b/modules/openxAnalyticsAdapter.js @@ -1,260 +1,733 @@ import adapter from '../src/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; import adapterManager from '../src/adapterManager.js'; -import { config } from '../src/config.js'; import { ajax } from '../src/ajax.js'; -import * as utils from '../src/utils.js'; +import find from 'core-js-pure/features/array/find.js'; +import includes from 'core-js-pure/features/array/includes.js'; +const utils = require('../src/utils.js'); + +export const AUCTION_STATES = { + INIT: 'initialized', // auction has initialized + ENDED: 'ended', // all auction requests have been accounted for + COMPLETED: 'completed' // all slots have rendered +}; + +const ADAPTER_VERSION = '0.1'; +const SCHEMA_VERSION = '0.1'; + +const AUCTION_END_WAIT_TIME = 1000; +const URL_PARAM = ''; +const ANALYTICS_TYPE = 'endpoint'; +const ENDPOINT = 'https://prebid.openx.net/ox/analytics/'; +// Event Types const { - EVENTS: { AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, BID_TIMEOUT, BID_WON } + EVENTS: { AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, BID_TIMEOUT, AUCTION_END, BID_WON } } = CONSTANTS; - const SLOT_LOADED = 'slotOnload'; -const ENDPOINT = 'https://ads.openx.net/w/1.0/pban'; +const UTM_TAGS = [ + 'utm_campaign', + 'utm_source', + 'utm_medium', + 'utm_term', + 'utm_content' +]; +const UTM_TO_CAMPAIGN_PROPERTIES = { + 'utm_campaign': 'name', + 'utm_source': 'source', + 'utm_medium': 'medium', + 'utm_term': 'term', + 'utm_content': 'content' +}; -let initOptions; +/** + * @typedef {Object} OxAnalyticsConfig + * @property {string} orgId + * @property {string} publisherPlatformId + * @property {number} publisherAccountId + * @property {number} sampling + * @property {boolean} enableV2 + * @property {boolean} testPipeline + * @property {Object} campaign + * @property {number} payloadWaitTime + * @property {number} payloadWaitTimePadding + * @property {Array} adUnits + */ + +/** + * @type {OxAnalyticsConfig} + */ +const DEFAULT_ANALYTICS_CONFIG = { + orgId: void (0), + publisherPlatformId: void (0), + publisherAccountId: void (0), + sampling: 0.05, // default sampling rate of 5% + testCode: 'default', + campaign: {}, + adUnits: [], + payloadWaitTime: AUCTION_END_WAIT_TIME, + payloadWaitTimePadding: 2000 +}; +// Initialization +/** + * @type {OxAnalyticsConfig} + */ +let analyticsConfig; let auctionMap = {}; +let auctionOrder = 1; // tracks the number of auctions ran on the page -function onAuctionInit({ auctionId }) { - auctionMap[auctionId] = { - adUnitMap: {} - }; +let googletag = window.googletag || {}; +googletag.cmd = googletag.cmd || []; + +let openxAdapter = Object.assign(adapter({ urlParam: URL_PARAM, analyticsType: ANALYTICS_TYPE })); + +openxAdapter.originEnableAnalytics = openxAdapter.enableAnalytics; + +openxAdapter.enableAnalytics = function(adapterConfig = {options: {}}) { + if (isValidConfig(adapterConfig)) { + analyticsConfig = {...DEFAULT_ANALYTICS_CONFIG, ...adapterConfig.options}; + + // campaign properties defined by config will override utm query parameters + analyticsConfig.campaign = {...buildCampaignFromUtmCodes(), ...analyticsConfig.campaign}; + + utils.logInfo('OpenX Analytics enabled with config', analyticsConfig); + + // override track method with v2 handlers + openxAdapter.track = prebidAnalyticsEventHandler; + + googletag.cmd.push(function () { + let pubads = googletag.pubads(); + + if (pubads.addEventListener) { + pubads.addEventListener(SLOT_LOADED, args => { + openxAdapter.track({eventType: SLOT_LOADED, args}); + utils.logInfo('OX: SlotOnLoad event triggered'); + }); + } + }); + + openxAdapter.originEnableAnalytics(adapterConfig); + } +}; + +adapterManager.registerAnalyticsAdapter({ + adapter: openxAdapter, + code: 'openx' +}); + +export default openxAdapter; + +/** + * Test Helper Functions + */ + +// reset the cache for unit tests +openxAdapter.reset = function() { + auctionMap = {}; + auctionOrder = 1; +}; + +/** + * Private Functions + */ + +function isValidConfig({options: analyticsOptions}) { + let hasOrgId = analyticsOptions && analyticsOptions.orgId !== void (0); + + const fieldValidations = [ + // tuple of property, type, required + ['orgId', 'string', hasOrgId], + ['publisherPlatformId', 'string', !hasOrgId], + ['publisherAccountId', 'number', !hasOrgId], + ['sampling', 'number', false], + ['enableV2', 'boolean', false], + ['testPipeline', 'boolean', false], + ['adIdKey', 'string', false], + ['payloadWaitTime', 'number', false], + ['payloadWaitTimePadding', 'number', false], + ]; + + let failedValidation = find(fieldValidations, ([property, type, required]) => { + // if required, the property has to exist + // if property exists, type check value + return (required && !analyticsOptions.hasOwnProperty(property)) || + /* eslint-disable valid-typeof */ + (analyticsOptions.hasOwnProperty(property) && typeof analyticsOptions[property] !== type); + }); + if (failedValidation) { + let [property, type, required] = failedValidation; + + if (required) { + utils.logError(`OpenXAnalyticsAdapter: Expected '${property}' to exist and of type '${type}'`); + } else { + utils.logError(`OpenXAnalyticsAdapter: Expected '${property}' to be type '${type}'`); + } + } + + return !failedValidation; } -function onBidRequested({ auctionId, auctionStart, bids, start }) { - const adUnitMap = auctionMap[auctionId]['adUnitMap']; +function buildCampaignFromUtmCodes() { + const location = utils.getWindowLocation(); + const queryParams = utils.parseQS(location && location.search); + let campaign = {}; - bids.forEach(bid => { - const { adUnitCode, bidId, bidder, params, transactionId } = bid; + UTM_TAGS.forEach(function(utmKey) { + let utmValue = queryParams[utmKey]; + if (utmValue) { + let key = UTM_TO_CAMPAIGN_PROPERTIES[utmKey]; + campaign[key] = decodeURIComponent(utmValue); + } + }); + return campaign; +} + +function detectMob() { + if ( + navigator.userAgent.match(/Android/i) || + navigator.userAgent.match(/webOS/i) || + navigator.userAgent.match(/iPhone/i) || + navigator.userAgent.match(/iPad/i) || + navigator.userAgent.match(/iPod/i) || + navigator.userAgent.match(/BlackBerry/i) || + navigator.userAgent.match(/Windows Phone/i) + ) { + return true; + } else { + return false; + } +} + +function detectOS() { + if (navigator.userAgent.indexOf('Android') != -1) return 'Android'; + if (navigator.userAgent.indexOf('like Mac') != -1) return 'iOS'; + if (navigator.userAgent.indexOf('Win') != -1) return 'Windows'; + if (navigator.userAgent.indexOf('Mac') != -1) return 'Macintosh'; + if (navigator.userAgent.indexOf('Linux') != -1) return 'Linux'; + if (navigator.appVersion.indexOf('X11') != -1) return 'Unix'; + return 'Others'; +} - adUnitMap[adUnitCode] = adUnitMap[adUnitCode] || { - auctionId, - auctionStart, - transactionId, - bidMap: {} +function detectBrowser() { + var isChrome = + /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor); + var isCriOS = navigator.userAgent.match('CriOS'); + var isSafari = + /Safari/.test(navigator.userAgent) && + /Apple Computer/.test(navigator.vendor); + var isFirefox = /Firefox/.test(navigator.userAgent); + var isIE = + /Trident/.test(navigator.userAgent) || /MSIE/.test(navigator.userAgent); + var isEdge = /Edge/.test(navigator.userAgent); + if (isIE) return 'Internet Explorer'; + if (isEdge) return 'Microsoft Edge'; + if (isCriOS) return 'Chrome'; + if (isSafari) return 'Safari'; + if (isFirefox) return 'Firefox'; + if (isChrome) return 'Chrome'; + return 'Others'; +} + +function prebidAnalyticsEventHandler({eventType, args}) { + utils.logMessage(eventType, Object.assign({}, args)); + switch (eventType) { + case AUCTION_INIT: + onAuctionInit(args); + break; + case BID_REQUESTED: + onBidRequested(args); + break; + case BID_RESPONSE: + onBidResponse(args); + break; + case BID_TIMEOUT: + onBidTimeout(args); + break; + case AUCTION_END: + onAuctionEnd(args); + break; + case BID_WON: + onBidWon(args); + break; + case SLOT_LOADED: + onSlotLoadedV2(args); + break; + } +} + +/** + * @typedef {Object} PbAuction + * @property {string} auctionId - Auction ID of the request this bid responded to + * @property {number} timestamp //: 1586675964364 + * @property {number} auctionEnd - timestamp of when auction ended //: 1586675964364 + * @property {string} auctionStatus //: "inProgress" + * @property {Array} adUnits //: [{…}] + * @property {string} adUnitCodes //: ["video1"] + * @property {string} labels //: undefined + * @property {Array} bidderRequests //: (2) [{…}, {…}] + * @property {Array} noBids //: [] + * @property {Array} bidsReceived //: [] + * @property {Array} winningBids //: [] + * @property {number} timeout //: 3000 + * @property {Object} config //: {publisherPlatformId: "a3aece0c-9e80-4316-8deb-faf804779bd1", publisherAccountId: 537143056, sampling: 1, enableV2: true}/* + */ + +function onAuctionInit({auctionId, timestamp: startTime, timeout, adUnitCodes}) { + auctionMap[auctionId] = { + id: auctionId, + startTime, + endTime: void (0), + timeout, + auctionOrder, + userIds: [], + adUnitCodesCount: adUnitCodes.length, + adunitCodesRenderedCount: 0, + state: AUCTION_STATES.INIT, + auctionSendDelayTimer: void (0), + }; + + // setup adunit properties in map + auctionMap[auctionId].adUnitCodeToAdUnitMap = adUnitCodes.reduce((obj, adunitCode) => { + obj[adunitCode] = { + code: adunitCode, + adPosition: void (0), + bidRequestsMap: {} }; + return obj; + }, {}); + + auctionOrder++; +} - adUnitMap[adUnitCode]['bidMap'][bidId] = { +/** + * @typedef {Object} PbBidRequest + * @property {string} auctionId - Auction ID of the request this bid responded to + * @property {number} auctionStart //: 1586675964364 + * @property {Object} refererInfo + * @property {PbBidderRequest} bids + * @property {number} start - Start timestamp of the bidder request + * + */ + +/** + * @typedef {Object} PbBidderRequest + * @property {string} adUnitCode - Name of div or google adunit path + * @property {string} bidder - Bame of bidder + * @property {string} bidId - Identifies the bid request + * @property {Object} mediaTypes + * @property {Object} params + * @property {string} src + * @property {Object} userId - Map of userId module to module object + */ + +/** + * Tracks the bid request + * @param {PbBidRequest} bidRequest + */ +function onBidRequested(bidRequest) { + const {auctionId, bids: bidderRequests, start, timeout} = bidRequest; + const auction = auctionMap[auctionId]; + const adUnitCodeToAdUnitMap = auction.adUnitCodeToAdUnitMap; + + bidderRequests.forEach(bidderRequest => { + const { adUnitCode, bidder, bidId: requestId, mediaTypes, params, src, userId } = bidderRequest; + + auction.userIds.push(userId); + adUnitCodeToAdUnitMap[adUnitCode].bidRequestsMap[requestId] = { bidder, params, - requestTimestamp: start + mediaTypes, + source: src, + startTime: start, + timedOut: false, + timeLimit: timeout, + bids: {} }; }); } -function onBidResponse({ - auctionId, - adUnitCode, - requestId: bidId, - cpm, - creativeId, - responseTimestamp, - ts, - adId -}) { - const adUnit = auctionMap[auctionId]['adUnitMap'][adUnitCode]; - const bid = adUnit['bidMap'][bidId]; - bid.cpm = cpm; - bid.creativeId = creativeId; - bid.responseTimestamp = responseTimestamp; - bid.ts = ts; - bid.adId = adId; +/** + * + * @param {BidResponse} bidResponse + */ +function onBidResponse(bidResponse) { + let { + auctionId, + adUnitCode, + requestId, + cpm, + creativeId, + requestTimestamp, + responseTimestamp, + ts, + mediaType, + dealId, + ttl, + netRevenue, + currency, + originalCpm, + originalCurrency, + width, + height, + timeToRespond: latency, + adId, + meta + } = bidResponse; + + auctionMap[auctionId].adUnitCodeToAdUnitMap[adUnitCode].bidRequestsMap[requestId].bids[adId] = { + cpm, + creativeId, + requestTimestamp, + responseTimestamp, + ts, + adId, + meta, + mediaType, + dealId, + ttl, + netRevenue, + currency, + originalCpm, + originalCurrency, + width, + height, + latency, + winner: false, + rendered: false, + renderTime: 0, + }; } function onBidTimeout(args) { - utils - ._map(args, value => value) - .forEach(({ auctionId, adUnitCode, bidId }) => { - const bid = - auctionMap[auctionId]['adUnitMap'][adUnitCode]['bidMap'][bidId]; - bid.timedOut = true; - }); + utils._each(args, ({auctionId, adUnitCode, bidId: requestId}) => { + let timedOutRequest = utils.deepAccess(auctionMap, + `${auctionId}.adUnitCodeToAdUnitMap.${adUnitCode}.bidRequestsMap.${requestId}`); + + if (timedOutRequest) { + timedOutRequest.timedOut = true; + } + }); } +/** + * + * @param {PbAuction} endedAuction + */ +function onAuctionEnd(endedAuction) { + let auction = auctionMap[endedAuction.auctionId]; + + if (!auction) { + return; + } -function onBidWon({ auctionId, adUnitCode, requestId: bidId }) { - const adUnit = auctionMap[auctionId]['adUnitMap'][adUnitCode]; - const bid = adUnit['bidMap'][bidId]; - bid.won = true; + clearAuctionTimer(auction); + auction.endTime = endedAuction.auctionEnd; + auction.state = AUCTION_STATES.ENDED; + delayedSend(auction); } -function onSlotLoaded({ slot }) { - const targeting = slot.getTargetingKeys().reduce((targeting, key) => { - targeting[key] = slot.getTargeting(key); - return targeting; - }, {}); - utils.logMessage( - 'GPT slot is loaded. Current targeting set on slot:', - targeting - ); +/** + * + * @param {BidResponse} bidResponse + */ +function onBidWon(bidResponse) { + const { auctionId, adUnitCode, requestId, adId } = bidResponse; + let winningBid = utils.deepAccess(auctionMap, + `${auctionId}.adUnitCodeToAdUnitMap.${adUnitCode}.bidRequestsMap.${requestId}.bids.${adId}`); + + if (winningBid) { + winningBid.winner = true + } +} - const adId = slot.getTargeting('hb_adid')[0]; - if (!adId) { - return; +/** + * + * @param {GoogleTagSlot} slot + * @param {string} serviceName + */ +function onSlotLoadedV2({ slot }) { + const renderTime = Date.now(); + const elementId = slot.getSlotElementId(); + const bidId = slot.getTargeting('hb_adid')[0]; + + let [auction, adUnit, bid] = getPathToBidResponseByBidId(bidId); + + if (!auction) { + // attempt to get auction by adUnitCode + auction = getAuctionByGoogleTagSLot(slot); + + if (!auction) { + return; // slot is not participating in an active prebid auction + } } - const adUnit = getAdUnitByAdId(adId); - if (!adUnit) { - return; + clearAuctionTimer(auction); + + // track that an adunit code has completed within an auction + auction.adunitCodesRenderedCount++; + + // mark adunit as rendered + if (bid) { + let {x, y} = getPageOffset(); + bid.rendered = true; + bid.renderTime = renderTime; + adUnit.adPosition = isAtf(elementId, x, y) ? 'ATF' : 'BTF'; } - const adUnitData = getAdUnitData(adUnit); - const performanceData = getPerformanceData(adUnit.auctionStart); - const commonFields = { - 'hb.asiid': slot.getAdUnitPath(), - 'hb.cur': config.getConfig('currency.adServerCurrency'), - 'hb.pubid': initOptions.publisherId - }; + if (auction.adunitCodesRenderedCount === auction.adUnitCodesCount) { + auction.state = AUCTION_STATES.COMPLETED; + } - const data = Object.assign({}, adUnitData, performanceData, commonFields); - sendEvent(data); + // prepare to send regardless if auction is complete or not as a failsafe in case not all events are tracked + // add additional padding when not all slots are rendered + delayedSend(auction); } -function getAdUnitByAdId(adId) { - let result; +function isAtf(elementId, scrollLeft = 0, scrollTop = 0) { + let elem = document.querySelector('#' + elementId); + let isAtf = false; + if (elem) { + let bounding = elem.getBoundingClientRect(); + if (bounding) { + let windowWidth = (window.innerWidth || document.documentElement.clientWidth); + let windowHeight = (window.innerHeight || document.documentElement.clientHeight); + + // intersection coordinates + let left = Math.max(0, bounding.left + scrollLeft); + let right = Math.min(windowWidth, bounding.right + scrollLeft); + let top = Math.max(0, bounding.top + scrollTop); + let bottom = Math.min(windowHeight, bounding.bottom + scrollTop); + + let intersectionWidth = right - left; + let intersectionHeight = bottom - top; + + let intersectionArea = (intersectionHeight > 0 && intersectionWidth > 0) ? (intersectionHeight * intersectionWidth) : 0; + let adSlotArea = (bounding.right - bounding.left) * (bounding.bottom - bounding.top); + + if (adSlotArea > 0) { + // Atleast 50% of intersection in window + isAtf = intersectionArea * 2 >= adSlotArea; + } + } + } else { + utils.logWarn('OX: DOM element not for id ' + elementId); + } + return isAtf; +} - utils._map(auctionMap, value => value).forEach(auction => { - utils._map(auction.adUnitMap, value => value).forEach(adUnit => { - utils._map(adUnit.bidMap, value => value).forEach(bid => { - if (adId === bid.adId) { - result = adUnit; - } - }) - }); - }); +// backwards compatible pageOffset from https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollX +function getPageOffset() { + var x = (window.pageXOffset !== undefined) + ? window.pageXOffset + : (document.documentElement || document.body.parentNode || document.body).scrollLeft; - return result; + var y = (window.pageYOffset !== undefined) + ? window.pageYOffset + : (document.documentElement || document.body.parentNode || document.body).scrollTop; + return {x, y}; } -function getAdUnitData(adUnit) { - const bids = utils._map(adUnit.bidMap, value => value); - const bidders = bids.map(bid => bid.bidder); - const requestTimes = bids.map( - bid => bid.requestTimestamp && bid.requestTimestamp - adUnit.auctionStart - ); - const responseTimes = bids.map( - bid => bid.responseTimestamp && bid.responseTimestamp - adUnit.auctionStart - ); - const bidValues = bids.map(bid => bid.cpm || 0); - const timeouts = bids.map(bid => !!bid.timedOut); - const creativeIds = bids.map(bid => bid.creativeId); - const winningBid = bids.filter(bid => bid.won)[0]; - const winningExchangeIndex = bids.indexOf(winningBid); - const openxBid = bids.filter(bid => bid.bidder === 'openx')[0]; +function delayedSend(auction) { + const delayTime = auction.adunitCodesRenderedCount === auction.adUnitCodesCount + ? analyticsConfig.payloadWaitTime + : analyticsConfig.payloadWaitTime + analyticsConfig.payloadWaitTimePadding; - return { - 'hb.ct': adUnit.auctionStart, - 'hb.rid': adUnit.auctionId, - 'hb.exn': bidders.join(','), - 'hb.sts': requestTimes.join(','), - 'hb.ets': responseTimes.join(','), - 'hb.bv': bidValues.join(','), - 'hb.to': timeouts.join(','), - 'hb.crid': creativeIds.join(','), - 'hb.we': winningExchangeIndex, - 'hb.g1': winningExchangeIndex === -1, - dddid: adUnit.transactionId, - ts: openxBid && openxBid.ts, - auid: openxBid && openxBid.params && openxBid.params.unit - }; + auction.auctionSendDelayTimer = setTimeout(() => { + let payload = JSON.stringify([buildAuctionPayload(auction)]); + ajax(ENDPOINT, deleteAuctionMap, payload, { contentType: 'application/json' }); + + function deleteAuctionMap() { + delete auctionMap[auction.id]; + } + }, delayTime); } -function getPerformanceData(auctionStart) { - let timing; - try { - timing = window.top.performance.timing; - } catch (e) {} +function clearAuctionTimer(auction) { + // reset the delay timer to send the auction data + if (auction.auctionSendDelayTimer) { + clearTimeout(auction.auctionSendDelayTimer); + auction.auctionSendDelayTimer = void (0); + } +} - if (!timing) { - return; +/** + * Returns the path to a bid (auction, adunit, bidRequest, and bid) based on a bidId + * @param {string} bidId + * @returns {Array<*>} + */ +function getPathToBidResponseByBidId(bidId) { + let auction; + let adUnit; + let bidResponse; + + if (!bidId) { + return []; } - const { fetchStart, domContentLoadedEventEnd, loadEventEnd } = timing; - const domContentLoadTime = domContentLoadedEventEnd - fetchStart; - const pageLoadTime = loadEventEnd - fetchStart; - const timeToAuction = auctionStart - fetchStart; - const timeToRender = Date.now() - fetchStart; + utils._each(auctionMap, currentAuction => { + // skip completed auctions + if (currentAuction.state === AUCTION_STATES.COMPLETED) { + return; + } - return { - 'hb.dcl': domContentLoadTime, - 'hb.dl': pageLoadTime, - 'hb.tta': timeToAuction, - 'hb.ttr': timeToRender - }; + utils._each(currentAuction.adUnitCodeToAdUnitMap, (currentAdunit) => { + utils._each(currentAdunit.bidRequestsMap, currentBiddRequest => { + utils._each(currentBiddRequest.bids, (currentBidResponse, bidResponseId) => { + if (bidId === bidResponseId) { + auction = currentAuction; + adUnit = currentAdunit; + bidResponse = currentBidResponse; + } + }); + }); + }); + }); + return [auction, adUnit, bidResponse]; } -function sendEvent(data) { - utils._map(data, (value, key) => [key, value]).forEach(([key, value]) => { - if ( - value === undefined || - value === null || - (typeof value === 'number' && isNaN(value)) - ) { - delete data[key]; +function getAuctionByGoogleTagSLot(slot) { + let slotAdunitCodes = [slot.getSlotElementId(), slot.getAdUnitPath()]; + let slotAuction; + + utils._each(auctionMap, auction => { + if (auction.state === AUCTION_STATES.COMPLETED) { + return; } + + utils._each(auction.adUnitCodeToAdUnitMap, (bidderRequestIdMap, adUnitCode) => { + if (includes(slotAdunitCodes, adUnitCode)) { + slotAuction = auction; + } + }); }); - ajax(ENDPOINT, null, data, { method: 'GET' }); + + return slotAuction; } -let googletag = window.googletag || {}; -googletag.cmd = googletag.cmd || []; -googletag.cmd.push(function() { - googletag.pubads().addEventListener(SLOT_LOADED, args => { - openxAdapter.track({ eventType: SLOT_LOADED, args }); - }); -}); +function buildAuctionPayload(auction) { + let {startTime, endTime, state, timeout, auctionOrder, userIds, adUnitCodeToAdUnitMap} = auction; + let {orgId, publisherPlatformId, publisherAccountId, campaign} = analyticsConfig; -const openxAdapter = Object.assign( - adapter({ url: ENDPOINT, analyticsType: 'endpoint' }), - { - track({ eventType, args }) { - utils.logMessage(eventType, Object.assign({}, args)); - switch (eventType) { - case AUCTION_INIT: - onAuctionInit(args); - break; - case BID_REQUESTED: - onBidRequested(args); - break; - case BID_RESPONSE: - onBidResponse(args); - break; - case BID_TIMEOUT: - onBidTimeout(args); - break; - case BID_WON: - onBidWon(args); - break; - case SLOT_LOADED: - onSlotLoaded(args); - break; + return { + adapterVersion: ADAPTER_VERSION, + schemaVersion: SCHEMA_VERSION, + orgId, + publisherPlatformId, + publisherAccountId, + campaign, + state, + startTime, + endTime, + timeLimit: timeout, + auctionOrder, + deviceType: detectMob() ? 'Mobile' : 'Desktop', + deviceOSType: detectOS(), + browser: detectBrowser(), + testCode: analyticsConfig.testCode, + // return an array of module name that have user data + userIdProviders: buildUserIdProviders(userIds), + adUnits: buildAdUnitsPayload(adUnitCodeToAdUnitMap), + }; + + function buildAdUnitsPayload(adUnitCodeToAdUnitMap) { + return utils._map(adUnitCodeToAdUnitMap, (adUnit) => { + let {code, adPosition} = adUnit; + + return { + code, + adPosition, + bidRequests: buildBidRequestPayload(adUnit.bidRequestsMap) + }; + + function buildBidRequestPayload(bidRequestsMap) { + return utils._map(bidRequestsMap, (bidRequest) => { + let {bidder, source, bids, mediaTypes, timeLimit, timedOut} = bidRequest; + return { + bidder, + source, + hasBidderResponded: Object.keys(bids).length > 0, + availableAdSizes: getMediaTypeSizes(mediaTypes), + availableMediaTypes: getMediaTypes(mediaTypes), + timeLimit, + timedOut, + bidResponses: utils._map(bidRequest.bids, (bidderBidResponse) => { + let { + cpm, + creativeId, + ts, + meta, + mediaType, + dealId, + ttl, + netRevenue, + currency, + width, + height, + latency, + winner, + rendered, + renderTime + } = bidderBidResponse; + + return { + microCpm: cpm * 1000000, + netRevenue, + currency, + mediaType, + height, + width, + size: `${width}x${height}`, + dealId, + latency, + ttl, + winner, + creativeId, + ts, + rendered, + renderTime, + meta + } + }) + } + }); } - } + }); } -); - -// save the base class function -openxAdapter.originEnableAnalytics = openxAdapter.enableAnalytics; -// override enableAnalytics so we can get access to the config passed in from the page -openxAdapter.enableAnalytics = function(config) { - if (!config || !config.options || !config.options.publisherId) { - utils.logError('OpenX analytics adapter: publisherId is required.'); - return; + function buildUserIdProviders(userIds) { + return utils._map(userIds, (userId) => { + return utils._map(userId, (id, module) => { + return hasUserData(module, id) ? module : false + }).filter(module => module); + }).reduce(utils.flatten, []).filter(utils.uniques).sort(); } - initOptions = config.options; - openxAdapter.originEnableAnalytics(config); // call the base class function -}; -// reset the cache for unit tests -openxAdapter.reset = function() { - auctionMap = {}; -}; + function hasUserData(module, idOrIdObject) { + let normalizedId; + + switch (module) { + case 'digitrustid': + normalizedId = utils.deepAccess(idOrIdObject, 'data.id'); + break; + case 'lipb': + normalizedId = idOrIdObject.lipbid; + break; + default: + normalizedId = idOrIdObject; + } -adapterManager.registerAnalyticsAdapter({ - adapter: openxAdapter, - code: 'openx' -}); + return !utils.isEmpty(normalizedId); + } -export default openxAdapter; + function getMediaTypeSizes(mediaTypes) { + return utils._map(mediaTypes, (mediaTypeConfig, mediaType) => { + return utils.parseSizesInput(mediaTypeConfig.sizes) + .map(size => `${mediaType}_${size}`); + }).reduce(utils.flatten, []); + } + + function getMediaTypes(mediaTypes) { + return utils._map(mediaTypes, (mediaTypeConfig, mediaType) => mediaType); + } +} diff --git a/modules/openxAnalyticsAdapter.md b/modules/openxAnalyticsAdapter.md index ac739f36c76..af40486f2a4 100644 --- a/modules/openxAnalyticsAdapter.md +++ b/modules/openxAnalyticsAdapter.md @@ -102,11 +102,13 @@ Configuration options are a follows: | Property | Type | Required? | Description | Example | |:---|:---|:---|:---|:---| -| `publisherPlatformId` | `string` | Yes | Used to determine ownership of data. | `a3aece0c-9e80-4316-8deb-faf804779bd1` | -| `publisherAccountId` | `number` | Yes | Used to determine ownership of data. | `1537143056` | +| `orgId` | `string` | Yes | Used to determine ownership of data. | `aa1bb2cc-3dd4-4316-8deb-faf804779bd1` | +| `publisherPlatformId` | `string` | No
**__Deprecated. Please use orgId__** | Used to determine ownership of data. | `a3aece0c-9e80-4316-8deb-faf804779bd1` | +| `publisherAccountId` | `number` | No
**__Deprecated. Please use orgId__** | Used to determine ownership of data. | `1537143056` | | `sampling` | `number` | Yes | Sampling rate | Undefined or `1.00` - No sampling. Analytics is sent all the time.
0.5 - 50% of users will send analytics data. | | `testCode` | `string` | No | Used to label analytics data for the purposes of tests.
This label is treated as a dimension and can be compared against other labels. | `timeout_config_1`
`timeout_config_2`
`timeout_default` | - +| `campaign` | `Object` | No | Object with 5 parameters:
  • content
  • medium
  • name
  • source
  • term
Each parameter is a free-form string. Refer to metrics doc on when to use these fields. By setting a value to one of these properties, you override the associated url utm query parameter. | | +| `payloadWaitTime` | `number` | No | Delay after all slots of an auction renders before the payload is sent.
Defaults to 100ms | 1000 | --- # Viewing Data @@ -114,7 +116,7 @@ The Prebid Report available in the Reporting in the Cloud tool, allows you to vi **To view your data:** -1. Log in to Reporting in the Cloud. +1. Log in to [OpenX Reporting](https://openx.sigmoid.io/app). 2. In the top right, click on the **View** list and then select **Prebidreport**. diff --git a/modules/openxBidAdapter.js b/modules/openxBidAdapter.js index c4a90fb0930..bbf3d6fdea1 100644 --- a/modules/openxBidAdapter.js +++ b/modules/openxBidAdapter.js @@ -6,7 +6,9 @@ import {BANNER, VIDEO} from '../src/mediaTypes.js'; const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; const BIDDER_CODE = 'openx'; const BIDDER_CONFIG = 'hb_pb'; -const BIDDER_VERSION = '3.0.2'; +const BIDDER_VERSION = '3.0.3'; + +const DEFAULT_CURRENCY = 'USD'; export const USER_ID_CODE_TO_QUERY_ARG = { britepoolid: 'britepoolid', // BritePool ID @@ -16,7 +18,7 @@ export const USER_ID_CODE_TO_QUERY_ARG = { idl_env: 'lre', // LiveRamp IdentityLink lipb: 'lipbid', // LiveIntent ID netId: 'netid', // netID - parrableid: 'parrableid', // Parrable ID + parrableId: 'parrableid', // Parrable ID pubcid: 'pubcid', // PubCommon ID tdid: 'ttduuid', // The Trade Desk Unified ID }; @@ -276,6 +278,12 @@ function appendUserIdsToQueryParams(queryParams, userIds) { case 'lipb': queryParams[key] = userIdObjectOrValue.lipbid; break; + case 'parrableId': + queryParams[key] = userIdObjectOrValue.eid; + break; + case 'id5id': + queryParams[key] = userIdObjectOrValue.uid; + break; default: queryParams[key] = userIdObjectOrValue; } @@ -336,8 +344,10 @@ function buildOXBannerRequest(bids, bidderRequest) { let customFloorsForAllBids = []; let hasCustomFloor = false; bids.forEach(function (bid) { - if (bid.params.customFloor) { - customFloorsForAllBids.push((Math.round(bid.params.customFloor * 100) / 100) * 1000); + let floor = getBidFloor(bid, BANNER); + + if (floor) { + customFloorsForAllBids.push(floor); hasCustomFloor = true; } else { customFloorsForAllBids.push(0); @@ -416,13 +426,17 @@ function generateVideoParameters(bid, bidderRequest) { queryParams.vmimes = oxVideoConfig.mimes; } + if (bid.params.test) { + queryParams.vtest = 1; + } + return queryParams; } function createVideoBidResponses(response, {bid, startTime}) { let bidResponses = []; - if (response !== undefined && response.vastUrl !== '' && response.pub_rev !== '') { + if (response !== undefined && response.vastUrl !== '' && response.pub_rev > 0) { let vastQueryParams = utils.parseUrl(response.vastUrl).search || {}; let bidResponse = {}; bidResponse.requestId = bid.bidId; @@ -431,9 +445,9 @@ function createVideoBidResponses(response, {bid, startTime}) { // true is net, false is gross bidResponse.netRevenue = true; bidResponse.currency = response.currency; - bidResponse.cpm = Number(response.pub_rev) / 1000; - bidResponse.width = response.width; - bidResponse.height = response.height; + bidResponse.cpm = parseInt(response.pub_rev, 10) / 1000; + bidResponse.width = parseInt(response.width, 10); + bidResponse.height = parseInt(response.height, 10); bidResponse.creativeId = response.adid; bidResponse.vastUrl = response.vastUrl; bidResponse.mediaType = VIDEO; @@ -449,4 +463,20 @@ function createVideoBidResponses(response, {bid, startTime}) { return bidResponses; } +function getBidFloor(bidRequest, mediaType) { + let floorInfo = {}; + const currency = config.getConfig('currency.adServerCurrency') || DEFAULT_CURRENCY; + + if (typeof bidRequest.getFloor === 'function') { + floorInfo = bidRequest.getFloor({ + currency: currency, + mediaType: mediaType, + size: '*' + }); + } + let floor = floorInfo.floor || bidRequest.params.customFloor || 0; + + return Math.round(floor * 1000); // normalize to microCpm +} + registerBidder(spec); diff --git a/modules/orbidderBidAdapter.js b/modules/orbidderBidAdapter.js index d7ce5aa859a..e01746af487 100644 --- a/modules/orbidderBidAdapter.js +++ b/modules/orbidderBidAdapter.js @@ -1,21 +1,20 @@ -import {detectReferer} from '../src/refererDetection.js'; -import {ajax} from '../src/ajax.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import { getStorageManager } from '../src/storageManager.js'; -const storage = getStorageManager(); +const storageManager = getStorageManager(); export const spec = { code: 'orbidder', - bidParams: {}, - orbidderHost: (() => { - let ret = 'https://orbidder.otto.de'; + hostname: 'https://orbidder.otto.de', + + getHostname() { + let ret = this.hostname; try { - ret = storage.getDataFromLocalStorage('ov_orbidder_host') || ret; + ret = storageManager.getDataFromLocalStorage('ov_orbidder_host') || ret; } catch (e) { } return ret; - })(), + }, isBidRequestValid(bid) { return !!(bid.sizes && bid.bidId && bid.params && @@ -26,6 +25,7 @@ export const spec = { }, buildRequests(validBidRequests, bidderRequest) { + const hostname = this.getHostname(); return validBidRequests.map((bidRequest) => { let referer = ''; if (bidderRequest && bidderRequest.refererInfo) { @@ -33,7 +33,7 @@ export const spec = { } const ret = { - url: `${spec.orbidderHost}/bid`, + url: `${hostname}/bid`, method: 'POST', options: { withCredentials: true }, data: { @@ -48,7 +48,6 @@ export const spec = { params: bidRequest.params } }; - spec.bidParams[bidRequest.bidId] = bidRequest.params; if (bidderRequest && bidderRequest.gdprConsent) { ret.data.gdprConsent = { consentString: bidderRequest.gdprConsent.consentString, @@ -76,21 +75,6 @@ export const spec = { } return bidResponses; }, - - onBidWon(bid) { - const getRefererInfo = detectReferer(window); - - bid.v = $$PREBID_GLOBAL$$.version; - bid.pageUrl = getRefererInfo().referer; - if (spec.bidParams[bid.requestId] && (typeof bid.params === 'undefined')) { - bid.params = [spec.bidParams[bid.requestId]]; - } - spec.ajaxCall(`${spec.orbidderHost}/win`, JSON.stringify(bid)); - }, - - ajaxCall(endpoint, data) { - ajax(endpoint, null, data, { withCredentials: true }); - } }; registerBidder(spec); diff --git a/modules/ozoneBidAdapter.js b/modules/ozoneBidAdapter.js index 32ae1ced2f3..4246a39bc69 100644 --- a/modules/ozoneBidAdapter.js +++ b/modules/ozoneBidAdapter.js @@ -4,19 +4,21 @@ import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import {config} from '../src/config.js'; import {getPriceBucketString} from '../src/cpmBucketManager.js'; import { Renderer } from '../src/Renderer.js'; - const BIDDER_CODE = 'ozone'; const ALLOWED_LOTAME_PARAMS = ['oz_lotameid', 'oz_lotamepid', 'oz_lotametpid']; + +// *** PROD *** const OZONEURI = 'https://elb.the-ozone-project.com/openrtb2/auction'; const OZONECOOKIESYNC = 'https://elb.the-ozone-project.com/static/load-cookie.html'; const OZONE_RENDERER_URL = 'https://prebid.the-ozone-project.com/ozone-renderer.js'; -const OZONEVERSION = '2.3.0'; - +const OZONEVERSION = '2.4.0'; export const spec = { code: BIDDER_CODE, supportedMediaTypes: [VIDEO, BANNER], cookieSyncBag: {'publisherId': null, 'siteId': null, 'userIdObject': {}}, // variables we want to make available to cookie sync + propertyBag: {'lotameWasOverridden': 0, 'pageId': null, 'buildRequestsStart': 0, 'buildRequestsEnd': 0}, /* allow us to store vars in instance scope - needs to be an object to be mutable */ + /** * Basic check to see whether required parameters are in the request. * @param bid @@ -80,13 +82,11 @@ export const spec = { } if (bid.hasOwnProperty('mediaTypes') && bid.mediaTypes.hasOwnProperty(VIDEO)) { if (!bid.mediaTypes[VIDEO].hasOwnProperty('context')) { - utils.logError('OZONE: No context key/value in bid. Rejecting bid: ', bid); + utils.logError('OZONE: No video context key/value in bid. Rejecting bid: ', bid); return false; } - if (bid.mediaTypes[VIDEO].context === 'instream') { - utils.logWarn('OZONE: video.context instream is not supported. Only outstream video is supported. Video will not be used for Bid: ', bid); - } else if (bid.mediaTypes.video.context !== 'outstream') { - utils.logError('OZONE: video.context is invalid. Only outstream video is supported. Rejecting bid: ', bid); + if (bid.mediaTypes[VIDEO].context !== 'instream' && bid.mediaTypes[VIDEO].context !== 'outstream') { + utils.logError('OZONE: video.context is invalid. Only instream/outstream video is supported. Rejecting bid: ', bid); return false; } } @@ -119,9 +119,10 @@ export const spec = { }, buildRequests(validBidRequests, bidderRequest) { - utils.logInfo('OZONE: ozone v' + OZONEVERSION + ' validBidRequests', validBidRequests, 'bidderRequest', bidderRequest); + this.propertyBag.buildRequestsStart = new Date().getTime(); + utils.logInfo(`OZONE: buildRequests time: ${this.propertyBag.buildRequestsStart} ozone v ${OZONEVERSION} validBidRequests`, validBidRequests, 'bidderRequest', bidderRequest); // First check - is there any config to block this request? - if (this.blockTheRequest(bidderRequest)) { + if (this.blockTheRequest()) { return []; } let htmlParams = {'publisherId': '', 'siteId': ''}; @@ -140,14 +141,13 @@ export const spec = { if (bidderRequest && bidderRequest.gdprConsent) { utils.logInfo('OZONE: ADDING GDPR info'); - ozoneRequest.regs = {}; - ozoneRequest.regs.ext = {}; // setting default values in case there is no additional information, like for the Mirror - ozoneRequest.regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; + let apiVersion = utils.deepAccess(bidderRequest.gdprConsent, 'apiVersion', '1'); + ozoneRequest.regs = {ext: {gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0, apiVersion: apiVersion}}; if (ozoneRequest.regs.ext.gdpr) { ozoneRequest.user = ozoneRequest.user || {}; ozoneRequest.user.ext = {'consent': bidderRequest.gdprConsent.consentString}; } else { - utils.logInfo('OZONE: **** Failed to find required info for GDPR for request object, even though bidderRequest.gdprConsent is TRUE ****'); + utils.logInfo('OZONE: **** Strange CMP info: bidderRequest.gdprConsent exists BUT bidderRequest.gdprConsent.gdprApplies is false. See bidderRequest logged above. ****'); } } else { utils.logInfo('OZONE: WILL NOT ADD GDPR info; no bidderRequest.gdprConsent object was present.'); @@ -156,8 +156,8 @@ export const spec = { const ozTestMode = getParams.hasOwnProperty('oztestmode') ? getParams.oztestmode : null; // this can be any string, it's used for testing ads ozoneRequest.device = {'w': window.innerWidth, 'h': window.innerHeight}; let placementIdOverrideFromGetParam = this.getPlacementIdOverrideFromGetParam(); // null or string - let arrLotameOverride = this.getLotameOverrideParams(); - let lotameIdsOverride = 0; + let lotameDataSingle = {}; // we will capture lotame data once & send it to the server as ext.ozone.lotameData + // build the array of params to attach to `imp` let tosendtags = validBidRequests.map(ozoneBidRequest => { var obj = {}; let placementId = placementIdOverrideFromGetParam || this.getPlacementId(ozoneBidRequest); // prefer to use a valid override param, else the bidRequest placement Id @@ -178,8 +178,14 @@ export const spec = { arrBannerSizes = ozoneBidRequest.mediaTypes[BANNER].sizes; /* Note - if there is a sizes element in the config root it will be pushed into here */ utils.logInfo('OZONE: setting banner size from the mediaTypes.banner element for bidId ' + obj.id + ': ', arrBannerSizes); } - if (ozoneBidRequest.mediaTypes.hasOwnProperty(VIDEO) && ozoneBidRequest.mediaTypes[VIDEO].context === 'outstream') { - obj.video = ozoneBidRequest.mediaTypes[VIDEO]; + if (ozoneBidRequest.mediaTypes.hasOwnProperty(VIDEO)) { + utils.logInfo('OZONE: openrtb 2.5 compliant video'); + // examine all the video attributes in the config, and either put them into obj.video if allowed by IAB2.5 or else in to obj.video.ext + if (typeof ozoneBidRequest.mediaTypes[VIDEO] == 'object') { + let childConfig = utils.deepAccess(ozoneBidRequest, 'params.video', {}); + obj.video = this.unpackVideoConfigIntoIABformat(ozoneBidRequest.mediaTypes[VIDEO], childConfig); + obj.video = this.addVideoDefaults(obj.video, ozoneBidRequest.mediaTypes[VIDEO], childConfig); + } // we need to duplicate some of the video values let wh = getWidthAndHeightFromVideoObject(obj.video); utils.logInfo('OZONE: setting video object from the mediaTypes.video element: ' + obj.id + ':', obj.video, 'wh=', wh); @@ -188,13 +194,13 @@ export const spec = { obj.video.h = wh['h']; if (playerSizeIsNestedArray(obj.video)) { // this should never happen; it was in the original spec for this change though. utils.logInfo('OZONE: setting obj.video.format to be an array of objects'); - obj.video.format = [wh]; + obj.video.ext.format = [wh]; } else { utils.logInfo('OZONE: setting obj.video.format to be an object'); - obj.video.format = wh; + obj.video.ext.format = wh; } } else { - utils.logInfo('OZONE: cannot set w, h & format values for video; the config is not right'); + utils.logWarn('OZONE: cannot set w, h & format values for video; the config is not right'); } } // Native integration is not complete yet @@ -223,9 +229,9 @@ export const spec = { if (ozoneBidRequest.params.hasOwnProperty('customData')) { obj.ext.ozone.customData = ozoneBidRequest.params.customData; } - utils.logInfo('obj.ext.ozone is ', obj.ext.ozone); + utils.logInfo('OZONE: obj.ext.ozone is ', obj.ext.ozone); if (ozTestMode != null) { - utils.logInfo('setting ozTestMode to ', ozTestMode); + utils.logInfo('OZONE: setting ozTestMode to ', ozTestMode); if (obj.ext.ozone.hasOwnProperty('customData')) { for (let i = 0; i < obj.ext.ozone.customData.length; i++) { obj.ext.ozone.customData[i]['targeting']['oztestmode'] = ozTestMode; @@ -234,38 +240,35 @@ export const spec = { obj.ext.ozone.customData = [{'settings': {}, 'targeting': {'oztestmode': ozTestMode}}]; } } else { - utils.logInfo('no ozTestMode '); + utils.logInfo('OZONE: no ozTestMode '); } // now deal with lotame, including the optional override parameters - if (Object.keys(arrLotameOverride).length === ALLOWED_LOTAME_PARAMS.length) { - // all override params are present, override lotame object: - if (ozoneBidRequest.params.hasOwnProperty('lotameData')) { - obj.ext.ozone.lotameData = this.makeLotameObjectFromOverride(arrLotameOverride, ozoneBidRequest.params.lotameData); - } else { - obj.ext.ozone.lotameData = this.makeLotameObjectFromOverride(arrLotameOverride, {}); - } - lotameIdsOverride = 1; - } else if (ozoneBidRequest.params.hasOwnProperty('lotameData')) { - // no lotame override, use it as-is - if (this.isLotameDataValid(ozoneBidRequest.params.lotameData)) { - obj.ext.ozone.lotameData = ozoneBidRequest.params.lotameData; - } else { - utils.logError('INVALID LOTAME DATA FOUND - WILL NOT USE THIS AT ALL ELSE IT MIGHT BREAK THE AUCTION CALL!', ozoneBidRequest.params.lotameData); - obj.ext.ozone.lotameData = {}; - } + if (Object.keys(lotameDataSingle).length === 0) { // we've not yet found lotameData, see if we can get it from this bid request object + lotameDataSingle = this.tryGetLotameData(ozoneBidRequest); } - // otherwise don't set obj.ext.ozone.lotameData return obj; }); // in v 2.0.0 we moved these outside of the individual ad slots - let extObj = {'ozone': {'oz_pb_v': OZONEVERSION, 'oz_rw': placementIdOverrideFromGetParam ? 1 : 0, 'oz_lot_rw': lotameIdsOverride}}; + let extObj = {'ozone': {'oz_pb_v': OZONEVERSION, 'oz_rw': placementIdOverrideFromGetParam ? 1 : 0, 'oz_lot_rw': this.propertyBag.lotameWasOverridden}}; if (validBidRequests.length > 0) { let userIds = this.findAllUserIds(validBidRequests[0]); if (userIds.hasOwnProperty('pubcid')) { extObj.ozone.pubcid = userIds.pubcid; } } + extObj.ozone.pv = this.getPageId(); // attach the page ID that will be common to all auciton calls for this page if refresh() is called + extObj.ozone.lotameData = lotameDataSingle; // 2.4.0 moved lotameData out of bid objects into the single ext.ozone area to remove duplication + let ozOmpFloorDollars = config.getConfig('ozone.oz_omp_floor'); // valid only if a dollar value (typeof == 'number') + utils.logInfo('OZONE: oz_omp_floor dollar value = ', ozOmpFloorDollars); + if (typeof ozOmpFloorDollars === 'number') { + extObj.ozone.oz_omp_floor = ozOmpFloorDollars; + } else if (typeof ozOmpFloorDollars !== 'undefined') { + utils.logError('OZONE: oz_omp_floor is invalid - IF SET then this must be a number, representing dollar value eg. oz_omp_floor: 1.55. You have it set as a ' + (typeof ozOmpFloorDollars)); + } + let ozWhitelistAdserverKeys = config.getConfig('ozone.oz_whitelist_adserver_keys'); + let useOzWhitelistAdserverKeys = utils.isArray(ozWhitelistAdserverKeys) && ozWhitelistAdserverKeys.length > 0; + extObj.ozone.oz_kvp_rw = useOzWhitelistAdserverKeys ? 1 : 0; var userExtEids = this.generateEids(validBidRequests); // generate the UserIDs in the correct format for UserId module @@ -298,7 +301,8 @@ export const spec = { bidderRequest: bidderRequest }; utils.logInfo('OZONE: buildRequests ozoneRequest for single = ', ozoneRequest); - utils.logInfo('OZONE: buildRequests going to return for single: ', ret); + this.propertyBag.buildRequestsEnd = new Date().getTime(); + utils.logInfo(`OZONE: buildRequests going to return for single at time ${this.propertyBag.buildRequestsEnd} (took ${this.propertyBag.buildRequestsEnd - this.propertyBag.buildRequestsStart}ms): `, ret); return ret; } // not single request - pull apart the tosendtags array & return an array of objects each containing one element in the imp array. @@ -320,7 +324,8 @@ export const spec = { bidderRequest: bidderRequest }; }); - utils.logInfo('OZONE: buildRequests going to return for non-single: ', arrRet); + this.propertyBag.buildRequestsEnd = new Date().getTime(); + utils.logInfo(`OZONE: buildRequests going to return for non-single at time ${this.propertyBag.buildRequestsEnd} (took ${this.propertyBag.buildRequestsEnd - this.propertyBag.buildRequestsStart}ms): `, arrRet); return arrRet; }, /** @@ -334,7 +339,9 @@ export const spec = { * @returns {*} */ interpretResponse(serverResponse, request) { - utils.logInfo('OZONE: interpretResponse: serverResponse, request', serverResponse, request); + let startTime = new Date().getTime(); + utils.logInfo(`OZONE: interpretResponse time: ${startTime} . Time between buildRequests done and interpretResponse start was ${startTime - this.propertyBag.buildRequestsEnd}ms`); + utils.logInfo(`OZONE: serverResponse, request`, serverResponse, request); serverResponse = serverResponse.body || {}; // note that serverResponse.id value is the auction_id we might want to use for reporting reasons. if (!serverResponse.hasOwnProperty('seatbid')) { @@ -351,57 +358,121 @@ export const spec = { } utils.logInfo('OZONE: enhancedAdserverTargeting', enhancedAdserverTargeting); serverResponse.seatbid = injectAdIdsIntoAllBidResponses(serverResponse.seatbid); // we now make sure that each bid in the bidresponse has a unique (within page) adId attribute. + serverResponse.seatbid = this.removeSingleBidderMultipleBids(serverResponse.seatbid); + let ozOmpFloorDollars = config.getConfig('ozone.oz_omp_floor'); // valid only if a dollar value (typeof == 'number') + let addOzOmpFloorDollars = typeof ozOmpFloorDollars === 'number'; + let ozWhitelistAdserverKeys = config.getConfig('ozone.oz_whitelist_adserver_keys'); + let useOzWhitelistAdserverKeys = utils.isArray(ozWhitelistAdserverKeys) && ozWhitelistAdserverKeys.length > 0; + for (let i = 0; i < serverResponse.seatbid.length; i++) { let sb = serverResponse.seatbid[i]; for (let j = 0; j < sb.bid.length; j++) { - const {defaultWidth, defaultHeight} = defaultSize(request.bidderRequest.bids[j]); + let thisRequestBid = this.getBidRequestForBidId(sb.bid[j].impid, request.bidderRequest.bids); + utils.logInfo(`OZONE seatbid:${i}, bid:${j} Going to set default w h for seatbid/bidRequest`, sb.bid[j], thisRequestBid); + const {defaultWidth, defaultHeight} = defaultSize(thisRequestBid); let thisBid = ozoneAddStandardProperties(sb.bid[j], defaultWidth, defaultHeight); - - // from https://github.com/prebid/Prebid.js/pull/1082 - if (utils.deepAccess(thisBid, 'ext.prebid.type') === VIDEO) { - utils.logInfo('OZONE: going to attach a renderer to:', j); - let renderConf = createObjectForInternalVideoRender(thisBid); - thisBid.renderer = Renderer.install(renderConf); - } else { - utils.logInfo('OZONE: bid is not a video, will not attach a renderer: ', j); + let videoContext = null; + let isVideo = false; + let bidType = utils.deepAccess(thisBid, 'ext.prebid.type'); + utils.logInfo(`OZONE: this bid type is : ${bidType}`, j); + if (bidType === VIDEO) { + isVideo = true; + videoContext = this.getVideoContextForBidId(thisBid.bidId, request.bidderRequest.bids); // should be instream or outstream (or null if error) + if (videoContext === 'outstream') { + utils.logInfo('OZONE: going to attach a renderer to OUTSTREAM video : ', j); + thisBid.renderer = newRenderer(thisBid.bidId); + } else { + utils.logInfo('OZONE: bid is not an outstream video, will not attach a renderer: ', j); + } } - - let ozoneInternalKey = thisBid.bidId; let adserverTargeting = {}; if (enhancedAdserverTargeting) { - let allBidsForThisBidid = ozoneGetAllBidsForBidId(ozoneInternalKey, serverResponse.seatbid); + let allBidsForThisBidid = ozoneGetAllBidsForBidId(thisBid.bidId, serverResponse.seatbid); // add all the winning & non-winning bids for this bidId: utils.logInfo('OZONE: Going to iterate allBidsForThisBidId', allBidsForThisBidid); Object.keys(allBidsForThisBidid).forEach(function (bidderName, index, ar2) { + utils.logInfo(`OZONE: adding adserverTargeting for ${bidderName} for bidId ${thisBid.bidId}`); + // let bidderName = bidderNameWH.split('_')[0]; adserverTargeting['oz_' + bidderName] = bidderName; - adserverTargeting['oz_' + bidderName + '_pb'] = String(allBidsForThisBidid[bidderName].price); adserverTargeting['oz_' + bidderName + '_crid'] = String(allBidsForThisBidid[bidderName].crid); adserverTargeting['oz_' + bidderName + '_adv'] = String(allBidsForThisBidid[bidderName].adomain); - adserverTargeting['oz_' + bidderName + '_imp_id'] = String(allBidsForThisBidid[bidderName].impid); adserverTargeting['oz_' + bidderName + '_adId'] = String(allBidsForThisBidid[bidderName].adId); adserverTargeting['oz_' + bidderName + '_pb_r'] = getRoundedBid(allBidsForThisBidid[bidderName].price, allBidsForThisBidid[bidderName].ext.prebid.type); if (allBidsForThisBidid[bidderName].hasOwnProperty('dealid')) { adserverTargeting['oz_' + bidderName + '_dealid'] = String(allBidsForThisBidid[bidderName].dealid); } + if (addOzOmpFloorDollars) { + adserverTargeting['oz_' + bidderName + '_omp'] = allBidsForThisBidid[bidderName].price >= ozOmpFloorDollars ? '1' : '0'; + } + if (isVideo) { + adserverTargeting['oz_' + bidderName + '_vid'] = videoContext; // outstream or instream + } + let flr = utils.deepAccess(allBidsForThisBidid[bidderName], 'ext.bidder.ozone.floor', null); + if (flr != null) { + adserverTargeting['oz_' + bidderName + '_flr'] = flr; + } + let rid = utils.deepAccess(allBidsForThisBidid[bidderName], 'ext.bidder.ozone.ruleId', null); + if (rid != null) { + adserverTargeting['oz_' + bidderName + '_rid'] = rid; + } + if (bidderName.match(/^ozappnexus/)) { + adserverTargeting['oz_' + bidderName + '_sid'] = String(allBidsForThisBidid[bidderName].cid); + } }); + } else { + if (useOzWhitelistAdserverKeys) { + utils.logWarn('OZONE: You have set a whitelist of adserver keys but this will be ignored because ozone.enhancedAdserverTargeting is set to false. No per-bid keys will be sent to adserver.'); + } else { + utils.logInfo('OZONE: ozone.enhancedAdserverTargeting is set to false, so no per-bid keys will be sent to adserver.'); + } } // also add in the winning bid, to be sent to dfp - let {seat: winningSeat, bid: winningBid} = ozoneGetWinnerForRequestBid(ozoneInternalKey, serverResponse.seatbid); + let {seat: winningSeat, bid: winningBid} = ozoneGetWinnerForRequestBid(thisBid.bidId, serverResponse.seatbid); adserverTargeting['oz_auc_id'] = String(request.bidderRequest.auctionId); adserverTargeting['oz_winner'] = String(winningSeat); - adserverTargeting['oz_response_id'] = String(serverResponse.id); if (enhancedAdserverTargeting) { - adserverTargeting['oz_winner_auc_id'] = String(winningBid.id); - adserverTargeting['oz_winner_imp_id'] = String(winningBid.impid); + adserverTargeting['oz_imp_id'] = String(winningBid.impid); adserverTargeting['oz_pb_v'] = OZONEVERSION; } + if (useOzWhitelistAdserverKeys) { // delete any un-whitelisted keys + utils.logInfo('OZONE: Going to filter out adserver targeting keys not in the whitelist: ', ozWhitelistAdserverKeys); + Object.keys(adserverTargeting).forEach(function(key) { if (ozWhitelistAdserverKeys.indexOf(key) === -1) { delete adserverTargeting[key]; } }); + } thisBid.adserverTargeting = adserverTargeting; arrAllBids.push(thisBid); } } - utils.logInfo('OZONE: interpretResponse going to return', arrAllBids); + let endTime = new Date().getTime(); + utils.logInfo(`OZONE: interpretResponse going to return at time ${endTime} (took ${endTime - startTime}ms) Time from buildRequests Start -> interpretRequests End = ${endTime - this.propertyBag.buildRequestsStart}ms`, arrAllBids); return arrAllBids; }, + /** + * If a bidder bids for > 1 size for an adslot, allow only the highest bid + * @param seatbid object (serverResponse.seatbid) + */ + removeSingleBidderMultipleBids(seatbid) { + var ret = []; + for (let i = 0; i < seatbid.length; i++) { + let sb = seatbid[i]; + var retSeatbid = {'seat': sb.seat, 'bid': []}; + var bidIds = []; + for (let j = 0; j < sb.bid.length; j++) { + var candidate = sb.bid[j]; + if (utils.contains(bidIds, candidate.impid)) { + continue; // we've already fully assessed this impid, found the highest bid from this seat for it + } + bidIds.push(candidate.impid); + for (let k = j + 1; k < sb.bid.length; k++) { + if (sb.bid[k].impid === candidate.impid && sb.bid[k].price > candidate.price) { + candidate = sb.bid[k]; + } + } + retSeatbid.bid.push(candidate); + } + ret.push(retSeatbid); + } + return ret; + }, // see http://prebid.org/dev-docs/bidder-adaptor.html#registering-user-syncs getUserSyncs(optionsType, serverResponse, gdprConsent) { utils.logInfo('OZONE: getUserSyncs optionsType, serverResponse, gdprConsent, cookieSyncBag', optionsType, serverResponse, gdprConsent, this.cookieSyncBag); @@ -435,23 +506,44 @@ export const spec = { }]; } }, - + /** + * Find the bid matching the bidId in the request object + * get instream or outstream if this was a video request else null + * @return object|null + */ + getBidRequestForBidId(bidId, arrBids) { + for (let i = 0; i < arrBids.length; i++) { + if (arrBids[i].bidId === bidId) { // bidId in the request comes back as impid in the seatbid bids + return arrBids[i]; + } + } + return null; + }, + /** + * Locate the bid inside the arrBids for this bidId, then discover the video context, and return it. + * IF the bid cannot be found return null, else return a string. + * @param bidId + * @param arrBids + * @return string|null + */ + getVideoContextForBidId(bidId, arrBids) { + let requestBid = this.getBidRequestForBidId(bidId, arrBids); + if (requestBid != null) { + return utils.deepAccess(requestBid, 'mediaTypes.video.context', 'unknown') + } + return null; + }, /** * Look for pubcid & all the other IDs according to http://prebid.org/dev-docs/modules/userId.html * @return map */ findAllUserIds(bidRequest) { var ret = {}; - let searchKeysSingle = ['pubcid', 'tdid', 'id5id', 'parrableid', 'idl_env', 'digitrustid', 'criteortus']; - utils.logInfo('OZONE: debug iterating keys'); - utils.logInfo('OZONE: debug bidRequest=', bidRequest); + let searchKeysSingle = ['pubcid', 'tdid', 'parrableId', 'idl_env', 'digitrustid', 'criteortus']; if (bidRequest.hasOwnProperty('userId')) { - utils.logInfo('OZONE: debug Looking inside userId element'); for (let arrayId in searchKeysSingle) { let key = searchKeysSingle[arrayId]; - utils.logInfo('OZONE: debug key=', key); if (bidRequest.userId.hasOwnProperty(key)) { - utils.logInfo('OZONE: debug found value : ', key); ret[key] = bidRequest.userId[key]; } } @@ -459,6 +551,10 @@ export const spec = { if (lipbid) { ret['lipb'] = {'lipbid': lipbid}; } + var id5id = utils.deepAccess(bidRequest.userId, 'id5id.uid'); + if (id5id) { + ret['id5id'] = id5id; + } } if (!ret.hasOwnProperty('pubcid')) { var pubcid = utils.deepAccess(bidRequest, 'crumbs.pubcid'); @@ -466,7 +562,6 @@ export const spec = { ret['pubcid'] = pubcid; // if built with old pubCommonId module } } - utils.logInfo('OZONE: debug going to return: ', ret); return ret; }, /** @@ -475,7 +570,7 @@ export const spec = { */ getLotameOverrideParams() { const arrGet = this.getGetParametersAsObject(); - utils.logInfo('getLotameOverrideParams - arrGet', arrGet); + utils.logInfo('OZONE: getLotameOverrideParams - arrGet=', arrGet); let arrRet = {}; for (let i in ALLOWED_LOTAME_PARAMS) { if (arrGet.hasOwnProperty(ALLOWED_LOTAME_PARAMS[i])) { @@ -506,13 +601,16 @@ export const spec = { }, /** * Use the arrOverride keys/vals to update the arrExisting lotame object. + * Ideally we will only be using the oz_lotameid value to update the audiences id, but in the event of bad/missing + * pid & tpid we will also have to use substitute values for those too. + * * @param objOverride object will contain all the ALLOWED_LOTAME_PARAMS parameters * @param lotameData object might be {} or contain the lotame data */ makeLotameObjectFromOverride(objOverride, lotameData) { if ((lotameData.hasOwnProperty('Profile') && Object.keys(lotameData.Profile).length < 3) || (!lotameData.hasOwnProperty('Profile'))) { // bad or empty lotame object (should contain pid, tpid & Audiences object) - build a total replacement - utils.logInfo('makeLotameObjectFromOverride', 'will return a full default lotame object'); + utils.logInfo('OZONE: makeLotameObjectFromOverride will return a full default lotame object'); return { 'Profile': { 'tpid': objOverride['oz_lotametpid'], @@ -522,11 +620,11 @@ export const spec = { }; } if (utils.deepAccess(lotameData, 'Profile.Audiences.Audience')) { - utils.logInfo('makeLotameObjectFromOverride', 'will return the existing lotame object with updated Audience by oz_lotameid'); + utils.logInfo('OZONE: makeLotameObjectFromOverride will return the existing lotame object with updated Audience by oz_lotameid'); lotameData.Profile.Audiences.Audience = [{'id': objOverride['oz_lotameid'], 'abbr': objOverride['oz_lotameid']}]; return lotameData; } - utils.logInfo('makeLotameObjectFromOverride', 'Weird error - failed to find Profile.Audiences.Audience in lotame object. Will return the object as-is'); + utils.logInfo('OZONE: makeLotameObjectFromOverride Weird error - failed to find Profile.Audiences.Audience in lotame object. Will return the object as-is'); return lotameData; }, /** @@ -581,11 +679,11 @@ export const spec = { if (bidRequest && bidRequest.userId) { this.addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.pubcid`), 'pubcid', 1); this.addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.pubcid`), 'pubcommon', 1); - this.addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.id5id`), 'id5-sync.com', 1); + this.addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.id5id.uid`), 'id5-sync.com', 1); this.addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.criteortus.${BIDDER_CODE}.userid`), 'criteortus', 1); this.addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.idl_env`), 'liveramp.com', 1); this.addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.lipb.lipbid`), 'liveintent.com', 1); - this.addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.parrableid`), 'parrable.com', 1); + this.addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.parrableId.eid`), 'parrable.com', 1); } return eids; }, @@ -622,98 +720,146 @@ export const spec = { return ret; }, /** - * This will be called IF we want to enforce gdpr on the client - * Do we have to block this request? Could be due to config values & gdpr permissions etc + * Do we have to block this request? Could be due to config values (no longer checking gdpr) * @return {boolean|*[]} true = block the request, else false */ - blockTheRequest(bidderRequest) { + blockTheRequest() { // if there is an ozone.oz_request = false then quit now. let ozRequest = config.getConfig('ozone.oz_request'); if (typeof ozRequest == 'boolean' && !ozRequest) { - utils.logError('OZONE: Will not allow auction : ozone.oz_request is set to false'); - return true; - } - // is there ozone.oz_enforceGdpr == true (ANYTHING else means don't enforce GDPR)) - let ozEnforce = config.getConfig('ozone.oz_enforceGdpr'); - if (typeof ozEnforce != 'boolean' || !ozEnforce) { // ozEnforce is false by default - utils.logError('OZONE: Will not validate GDPR on the client : oz_enforceGdpr is not set to true'); - return false; - } - // maybe the module was built without consentManagement module so we won't find any gdpr information - if (!bidderRequest.hasOwnProperty('gdprConsent')) { - return false; - } - // - // FROM HERE ON : WE ARE DOING GDPR CHECKS - // - // If there is indeterminate GDPR (gdprConsent.consentString == undefined or not a string), we will DITCH this: - if (typeof bidderRequest.gdprConsent.consentString !== 'string') { - utils.logError('OZONE: Will block the request - bidderRequest.gdprConsent.consentString is not a string'); - return true; - } - // IF the consentManagement module sends through the CMP information and user has refused all permissions: - if (this.failsGdprCheck(bidderRequest)) { + utils.logWarn('OZONE: Will not allow auction : ozone.oz_request is set to false'); return true; } return false; }, /** - * Examine the gdpr information inside the bidderRequest and return the boolean answer to the question - * @param bidderRequest - * @return {boolean} + * This returns a random ID for this page. It starts off with the current ms timestamp then appends a random component + * @return {string} */ - failsGdprCheck(bidderRequest) { - let consentRequired = (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true; - if (consentRequired) { - let vendorConsentsObject = utils.deepAccess(bidderRequest.gdprConsent, 'vendorData'); - if (!vendorConsentsObject || typeof vendorConsentsObject !== 'object') { - utils.logError('OZONE: gdpr test failed - bidderRequest.gdprConsent.vendorData is not an array'); - return true; + getPageId: function() { + if (this.propertyBag.pageId == null) { + let randPart = ''; + let allowable = '0123456789abcdefghijklmnopqrstuvwxyz'; + for (let i = 20; i > 0; i--) { + randPart += allowable[Math.floor(Math.random() * 36)]; } - if (!vendorConsentsObject.hasOwnProperty('purposeConsents')) { - return true; + this.propertyBag.pageId = new Date().getTime() + '_' + randPart; + } + return this.propertyBag.pageId; + }, + /** + * handle the complexity of there possibly being lotameData override (may be valid/invalid) & there may or may not be lotameData present in the bidRequest + * NOTE THAT this will also set this.propertyBag.lotameWasOverridden=1 if we use lotame override + * @param ozoneBidRequest + * @return object representing the absolute lotameData we need to use. + */ + tryGetLotameData: function(ozoneBidRequest) { + const arrLotameOverride = this.getLotameOverrideParams(); + let ret = {}; + if (Object.keys(arrLotameOverride).length === ALLOWED_LOTAME_PARAMS.length) { + // all override params are present, override lotame object: + if (ozoneBidRequest.params.hasOwnProperty('lotameData')) { + ret = this.makeLotameObjectFromOverride(arrLotameOverride, ozoneBidRequest.params.lotameData); + } else { + ret = this.makeLotameObjectFromOverride(arrLotameOverride, {}); } - if (typeof vendorConsentsObject.purposeConsents != 'object') { - return true; + this.propertyBag.lotameWasOverridden = 1; + } else if (ozoneBidRequest.params.hasOwnProperty('lotameData')) { + // no lotame override, use it as-is + if (this.isLotameDataValid(ozoneBidRequest.params.lotameData)) { + ret = ozoneBidRequest.params.lotameData; + } else { + utils.logError('OZONE: INVALID LOTAME DATA FOUND - WILL NOT USE THIS AT ALL ELSE IT MIGHT BREAK THE AUCTION CALL!', ozoneBidRequest.params.lotameData); + ret = {}; } - if (!this.purposeConsentsAreOk((vendorConsentsObject.purposeConsents))) { - utils.logError('OZONE: gdpr test failed - missing Purposes consent'); - return true; + } + return ret; + }, + unpackVideoConfigIntoIABformat(videoConfig, childConfig) { + let ret = {'ext': {}}; + ret = this._unpackVideoConfigIntoIABformat(ret, videoConfig); + ret = this._unpackVideoConfigIntoIABformat(ret, childConfig); + return ret; + }, + /** + * + * look in ONE object to get video config (we need to call this multiple times, so child settings override parent) + * @param ret + * @param objConfig + * @return {*} + * @private + */ + _unpackVideoConfigIntoIABformat(ret, objConfig) { + let arrVideoKeysAllowed = ['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']; + for (const key in objConfig) { + var found = false; + arrVideoKeysAllowed.forEach(function(arg) { + if (arg === key) { + ret[key] = objConfig[key]; + found = true; + } + }); + if (!found) { + ret.ext[key] = objConfig[key]; } - if (!vendorConsentsObject.vendorConsents[524]) { - utils.logError('OZONE: gdpr test failed - missing Vendor ID consent'); - return true; + } + // handle ext separately, if it exists; we have probably built up an ext object already + if (objConfig.hasOwnProperty('ext') && typeof objConfig.ext === 'object') { + if (objConfig.hasOwnProperty('ext')) { + ret.ext = utils.mergeDeep(ret.ext, objConfig.ext); + } else { + ret.ext = objConfig.ext; } } - return false; + return ret; + }, + addVideoDefaults(objRet, videoConfig, childConfig) { + objRet = this._addVideoDefaults(objRet, videoConfig, false); + objRet = this._addVideoDefaults(objRet, childConfig, true); // child config will override parent config + return objRet; }, /** - * Test that vendor purpose consents 1,2,3,4 and 5 are true - * This is because we can't use Object.values(vendorConsentsObject.purposeConsents).slice(0, 5) - * @param obj - * @return {boolean} + * modify objRet, adding in default values + * @param objRet + * @param objConfig + * @param addIfMissing + * @return {*} + * @private */ - purposeConsentsAreOk(obj) { - for (let i = 1; i <= 5; i++) { - if (!obj.hasOwnProperty(i) || !obj[i]) return false; + _addVideoDefaults(objRet, objConfig, addIfMissing) { + // add inferred values & any default values we want. + let context = utils.deepAccess(objConfig, 'context'); + if (context === 'outstream') { + objRet.placement = 3; + } else if (context === 'instream') { + objRet.placement = 1; } - return true; + let skippable = utils.deepAccess(objConfig, 'skippable', null); + if (skippable == null) { + if (addIfMissing && !objRet.hasOwnProperty('skip')) { + objRet.skip = skippable ? 1 : 0; + } + } else { + objRet.skip = skippable ? 1 : 0; + } + return objRet; } -} +}; /** * add a page-level-unique adId element to all server response bids. - * NOTE that this is distructive - it mutates the serverResponse object sent in as a parameter + * NOTE that this is destructive - it mutates the serverResponse object sent in as a parameter * @param seatbid object (serverResponse.seatbid) * @returns seatbid object */ export function injectAdIdsIntoAllBidResponses(seatbid) { - utils.logInfo('injectAdIdsIntoAllBidResponses', seatbid); + utils.logInfo('OZONE: injectAdIdsIntoAllBidResponses', seatbid); for (let i = 0; i < seatbid.length; i++) { let sb = seatbid[i]; for (let j = 0; j < sb.bid.length; j++) { // modify the bidId per-bid, so each bid has a unique adId within this response, and dfp can select one. - sb.bid[j]['adId'] = sb.bid[j]['impid'] + '-' + i; + // 2020-06 we now need a second level of ID because there might be multiple identical impid's within a seatbid! + sb.bid[j]['adId'] = `${sb.bid[j]['impid']}-${i}-${j}`; } } return seatbid; @@ -773,10 +919,10 @@ export function ozoneGetWinnerForRequestBid(requestBidId, serverResponseSeatBid) } /** - * Get a list of all the bids, for this bidId + * Get a list of all the bids, for this bidId. The keys in the response object will be {seatname} OR {seatname}{w}x{h} if seatname already exists * @param matchBidId * @param serverResponseSeatBid - * @returns {} = {ozone:{obj}, appnexus:{obj}, ... } + * @returns {} = {ozone|320x600:{obj}, ozone|320x250:{obj}, appnexus|300x250:{obj}, ... } */ export function ozoneGetAllBidsForBidId(matchBidId, serverResponseSeatBid) { let objBids = {}; @@ -785,7 +931,14 @@ export function ozoneGetAllBidsForBidId(matchBidId, serverResponseSeatBid) { let thisSeat = serverResponseSeatBid[j].seat; for (let k = 0; k < theseBids.length; k++) { if (theseBids[k].impid === matchBidId) { - objBids[thisSeat] = theseBids[k]; + if (objBids.hasOwnProperty(thisSeat)) { // > 1 bid for an adunit from a bidder - only use the one with the highest bid + // objBids[`${thisSeat}${theseBids[k].w}x${theseBids[k].h}`] = theseBids[k]; + if (objBids[thisSeat]['price'] < theseBids[k].price) { + objBids[thisSeat] = theseBids[k]; + } + } else { + objBids[thisSeat] = theseBids[k]; + } } } } @@ -822,7 +975,7 @@ export function getRoundedBid(price, mediaType) { }; if (granularityNamePriceStringsKeyMapping.hasOwnProperty(theConfigKey)) { let priceStringsKey = granularityNamePriceStringsKeyMapping[theConfigKey]; - utils.logInfo('OZONE: looking for priceStringsKey:', priceStringsKey); + utils.logInfo('OZONE: getRoundedBid: looking for priceStringsKey:', priceStringsKey); return priceStringsObj[priceStringsKey]; } return priceStringsObj['auto']; @@ -880,26 +1033,6 @@ export function ozoneAddStandardProperties(seatBid, defaultWidth, defaultHeight) return seatBid; } -function createObjectForInternalVideoRender(bid) { - let obj = { - url: OZONE_RENDERER_URL, - callback: () => onOutstreamRendererLoaded(bid) - } - return obj; -} - -function onOutstreamRendererLoaded(bid) { - try { - bid.renderer.setRender(outstreamRender); - } catch (err) { - utils.logWarn('Prebid Error calling setRender on renderer', err) - } -} - -function outstreamRender(bid) { - window.ozoneVideo.outstreamRender(bid); -} - /** * * @param objVideo will be like {"playerSize":[640,480],"mimes":["video/mp4"],"context":"outstream"} or POSSIBLY {"playerSize":[[640,480]],"mimes":["video/mp4"],"context":"outstream"} @@ -947,17 +1080,45 @@ export function playerSizeIsNestedArray(objVideo) { */ function getPlayerSizeFromObject(objVideo) { utils.logInfo('OZONE: getPlayerSizeFromObject received object', objVideo); - if (!objVideo.hasOwnProperty('playerSize')) { - utils.logError('OZONE: getPlayerSizeFromObject FAILED: no playerSize in video object', objVideo); + let playerSize = utils.deepAccess(objVideo, 'playerSize'); + if (!playerSize) { + playerSize = utils.deepAccess(objVideo, 'ext.playerSize'); + } + if (!playerSize) { + utils.logError('OZONE: getPlayerSizeFromObject FAILED: no playerSize in video object or ext', objVideo); return null; } - let playerSize = objVideo.playerSize; if (typeof playerSize !== 'object') { utils.logError('OZONE: getPlayerSizeFromObject FAILED: playerSize is not an object/array', objVideo); return null; } return playerSize; } +/* + Rendering video ads - create a renderer instance, mark it as not loaded, set a renderer function. + The renderer function will not assume that the renderer script is loaded - it will push() the ultimate render function call + */ +function newRenderer(adUnitCode, rendererOptions = {}) { + const renderer = Renderer.install({ + url: OZONE_RENDERER_URL, + config: rendererOptions, + loaded: false, + adUnitCode + }); + try { + renderer.setRender(outstreamRender); + } catch (err) { + utils.logWarn('OZONE Prebid Error calling setRender on renderer', err); + } + return renderer; +} +function outstreamRender(bid) { + utils.logInfo('OZONE: outstreamRender called. Going to push the call to window.ozoneVideo.outstreamRender(bid) bid =', bid); + // push to render queue because ozoneVideo may not be loaded yet + bid.renderer.push(() => { + window.ozoneVideo.outstreamRender(bid); + }); +} registerBidder(spec); utils.logInfo('OZONE: ozoneBidAdapter was loaded'); diff --git a/modules/ozoneBidAdapter.md b/modules/ozoneBidAdapter.md index 1fe5e681e25..bc8cb6a6102 100644 --- a/modules/ozoneBidAdapter.md +++ b/modules/ozoneBidAdapter.md @@ -37,7 +37,7 @@ adUnits = [{ siteId: '4204204201', /* An ID used to identify a site within a publisher account - required */ placementId: '0420420421', /* an ID used to identify the piece of inventory - required - for appnexus test use 13144370. */ customData: [{"settings": {}, "targeting": {"key": "value", "key2": ["value1", "value2"]}}],/* optional array with 'targeting' placeholder for passing publisher specific key-values for targeting. */ - lotameData: {"key1": "value1", "key2": "value2"} /* optional JSON placeholder for passing Lotame DMP data */ + lotameData: {"Profile": {"tpid":"value","pid":"value","Audiences": {"Audience":[{"id":"value"},{"id":"value2"}]}}}, /* optional JSON placeholder for passing Lotame DMP data */ } }] }]; @@ -64,8 +64,7 @@ adUnits = [{ siteId: '4204204201', /* An ID used to identify a site within a publisher account - required */ customData: [{"settings": {}, "targeting": { "key": "value", "key2": ["value1", "value2"]}}] placementId: '0440440442', /* an ID used to identify the piece of inventory - required - for unruly test use 0440440442. */ - customData: [{"settings": {}, "targeting": {"key": "value", "key2": ["value1", "value2"]}}],/* optional array with 'targeting' placeholder for passing publisher specific key-values for targeting. */ - lotameData: {"key1": "value1", "key2": "value2"}, /* optional JSON placeholder for passing Lotame DMP data */ + lotameData: {"Profile": {"tpid":"value","pid":"value","Audiences": {"Audience":[{"id":"value"},{"id":"value2"}]}}}, /* optional JSON placeholder for passing Lotame DMP data */ video: { skippable: true, /* optional */ playback_method: ['auto_play_sound_off'], /* optional */ diff --git a/modules/padsquadBidAdapter.js b/modules/padsquadBidAdapter.js index 088cac265b9..24b1d5be3be 100644 --- a/modules/padsquadBidAdapter.js +++ b/modules/padsquadBidAdapter.js @@ -83,6 +83,7 @@ export const spec = { ad: bid.adm, ttl: DEFAULT_BID_TTL, creativeId: bid.crid, + meta: { advertiserDomains: bid.adomain }, netRevenue: DEFAULT_NET_REVENUE, currency: DEFAULT_CURRENCY, }) diff --git a/modules/parrableIdSystem.js b/modules/parrableIdSystem.js index 8c487c783ae..2d6a2d6d6e5 100644 --- a/modules/parrableIdSystem.js +++ b/modules/parrableIdSystem.js @@ -10,8 +10,50 @@ import { ajax } from '../src/ajax.js'; import { submodule } from '../src/hook.js'; import { getRefererInfo } from '../src/refererDetection.js'; import { uspDataHandler } from '../src/adapterManager.js'; +import { getStorageManager } from '../src/storageManager.js'; const PARRABLE_URL = 'https://h.parrable.com/prebid'; +const PARRABLE_COOKIE_NAME = '_parrable_id'; +const LEGACY_ID_COOKIE_NAME = '_parrable_eid'; +const LEGACY_OPTOUT_COOKIE_NAME = '_parrable_optout'; +const ONE_YEAR_MS = 364 * 24 * 60 * 60 * 1000; +const EXPIRE_COOKIE_DATE = 'Thu, 01 Jan 1970 00:00:00 GMT'; + +const storage = getStorageManager(); + +function getExpirationDate() { + const oneYearFromNow = new Date(utils.timestamp() + ONE_YEAR_MS); + return oneYearFromNow.toGMTString(); +} + +function deserializeParrableId(parrableIdStr) { + const parrableId = {}; + const values = parrableIdStr.split(','); + + values.forEach(function(value) { + const pair = value.split(':'); + // unpack a value of 1 as true + parrableId[pair[0]] = +pair[1] === 1 ? true : pair[1]; + }); + + return parrableId; +} + +function serializeParrableId(parrableId) { + let components = []; + + if (parrableId.eid) { + components.push('eid:' + parrableId.eid); + } + if (parrableId.ibaOptout) { + components.push('ibaOptout:1'); + } + if (parrableId.ccpaOptout) { + components.push('ccpaOptout:1'); + } + + return components.join(','); +} function isValidConfig(configParams) { if (!configParams) { @@ -22,17 +64,119 @@ function isValidConfig(configParams) { utils.logError('User ID - parrableId submodule requires partner list'); return false; } + if (configParams.storage) { + utils.logWarn('User ID - parrableId submodule does not require a storage config'); + } return true; } -function fetchId(configParams, currentStoredId) { +function readCookie() { + const parrableIdStr = storage.getCookie(PARRABLE_COOKIE_NAME); + if (parrableIdStr) { + return deserializeParrableId(decodeURIComponent(parrableIdStr)); + } + return null; +} + +function writeCookie(parrableId) { + if (parrableId) { + const parrableIdStr = encodeURIComponent(serializeParrableId(parrableId)); + storage.setCookie(PARRABLE_COOKIE_NAME, parrableIdStr, getExpirationDate(), 'lax'); + } +} + +function readLegacyCookies() { + const eid = storage.getCookie(LEGACY_ID_COOKIE_NAME); + const ibaOptout = (storage.getCookie(LEGACY_OPTOUT_COOKIE_NAME) === 'true'); + if (eid || ibaOptout) { + const parrableId = {}; + if (eid) { + parrableId.eid = eid; + } + if (ibaOptout) { + parrableId.ibaOptout = ibaOptout; + } + return parrableId; + } + return null; +} + +function migrateLegacyCookies(parrableId) { + if (parrableId) { + writeCookie(parrableId); + if (parrableId.eid) { + storage.setCookie(LEGACY_ID_COOKIE_NAME, '', EXPIRE_COOKIE_DATE); + } + if (parrableId.ibaOptout) { + storage.setCookie(LEGACY_OPTOUT_COOKIE_NAME, '', EXPIRE_COOKIE_DATE); + } + } +} + +function shouldFilterImpression(configParams, parrableId) { + const config = configParams.timezoneFilter; + + if (!config) { + return false; + } + + if (parrableId) { + return false; + } + + const offset = (new Date()).getTimezoneOffset() / 60; + const zone = Intl.DateTimeFormat().resolvedOptions().timeZone; + + function isAllowed() { + if (utils.isEmpty(config.allowedZones) && + utils.isEmpty(config.allowedOffsets)) { + return true; + } + if (utils.contains(config.allowedZones, zone)) { + return true; + } + if (utils.contains(config.allowedOffsets, offset)) { + return true; + } + return false; + } + + function isBlocked() { + if (utils.isEmpty(config.blockedZones) && + utils.isEmpty(config.blockedOffsets)) { + return false; + } + if (utils.contains(config.blockedZones, zone)) { + return true; + } + if (utils.contains(config.blockedOffsets, offset)) { + return true; + } + return false; + } + + return !isAllowed() || isBlocked(); +} + +function fetchId(configParams) { if (!isValidConfig(configParams)) return; + let parrableId = readCookie(); + if (!parrableId) { + parrableId = readLegacyCookies(); + migrateLegacyCookies(parrableId); + } + + if (shouldFilterImpression(configParams, parrableId)) { + return null; + } + + const eid = (parrableId) ? parrableId.eid : null; const refererInfo = getRefererInfo(); const uspString = uspDataHandler.getConsentData(); const data = { - eid: currentStoredId || null, + eid, trackers: configParams.partner.split(','), url: refererInfo.referer }; @@ -54,16 +198,31 @@ function fetchId(configParams, currentStoredId) { const callback = function (cb) { const callbacks = { success: response => { - let eid; + let newParrableId = parrableId ? utils.deepClone(parrableId) : {}; if (response) { try { let responseObj = JSON.parse(response); - eid = responseObj ? responseObj.eid : undefined; + if (responseObj) { + if (responseObj.ccpaOptout !== true) { + newParrableId.eid = responseObj.eid; + } else { + newParrableId.eid = null; + newParrableId.ccpaOptout = true; + } + if (responseObj.ibaOptout === true) { + newParrableId.ibaOptout = true; + } + } } catch (error) { utils.logError(error); + cb(); } + writeCookie(newParrableId); + cb(newParrableId); + } else { + utils.logError('parrableId: ID fetch returned an empty result'); + cb(); } - cb(eid); }, error: error => { utils.logError(`parrableId: ID fetch encountered an error`, error); @@ -73,7 +232,10 @@ function fetchId(configParams, currentStoredId) { ajax(PARRABLE_URL, callbacks, searchParams, options); }; - return { callback }; + return { + callback, + id: parrableId + }; }; /** @type {Submodule} */ @@ -86,11 +248,14 @@ export const parrableIdSubmodule = { /** * decode the stored id value for passing to bid requests * @function - * @param {Object|string} value + * @param {ParrableId} parrableId * @return {(Object|undefined} */ - decode(value) { - return (value && typeof value === 'string') ? { 'parrableid': value } : undefined; + decode(parrableId) { + if (parrableId && utils.isPlainObject(parrableId)) { + return { parrableId }; + } + return undefined; }, /** @@ -98,10 +263,10 @@ export const parrableIdSubmodule = { * @function * @param {SubmoduleParams} [configParams] * @param {ConsentData} [consentData] - * @returns {function(callback:function)} + * @returns {function(callback:function), id:ParrableId} */ getId(configParams, gdprConsentData, currentStoredId) { - return fetchId(configParams, currentStoredId); + return fetchId(configParams); } }; diff --git a/modules/performaxBidAdapter.js b/modules/performaxBidAdapter.js new file mode 100644 index 00000000000..8e22a0b2da9 --- /dev/null +++ b/modules/performaxBidAdapter.js @@ -0,0 +1,56 @@ +import {logWarn} from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; + +const CLIENT = 'hellboy:v0.0.1' +const BIDDER_CODE = 'performax'; +const BIDDER_SHORT_CODE = 'px'; +const ENDPOINT = 'https://dale.performax.cz/hb'; + +export const spec = { + code: BIDDER_CODE, + aliases: [BIDDER_SHORT_CODE], + + isBidRequestValid: function (bid) { + return !!bid.params.slotId; + }, + + buildUrl: function (validBidRequests, bidderRequest) { + const slotIds = validBidRequests.map(request => request.params.slotId); + let url = [`${ENDPOINT}?slotId[]=${slotIds.join()}`]; + url.push('client=' + CLIENT); + url.push('auctionId=' + bidderRequest.auctionId); + return url.join('&'); + }, + + buildRequests: function (validBidRequests, bidderRequest) { + return { + method: 'POST', + url: this.buildUrl(validBidRequests, bidderRequest), + data: {'validBidRequests': validBidRequests, 'bidderRequest': bidderRequest}, + options: {contentType: 'application/json'}, + } + }, + + buildHtml: function (ad) { + const keys = Object.keys(ad.data || {}); + return ad.code.replace( + new RegExp('\\$(' + keys.join('|') + ')\\$', 'g'), + (matched, key) => ad.data[key] || matched + ); + }, + + interpretResponse: function (serverResponse, request) { + let bidResponses = []; + for (let i = 0; i < serverResponse.body.length; i++) { + const ad = serverResponse.body[i].ad; + if (ad.type === 'empty') { + logWarn(`One of ads is empty (reason=${ad.reason})`); + continue; + } + serverResponse.body[i].ad = this.buildHtml(ad); + bidResponses.push(serverResponse.body[i]); + } + return bidResponses; + } +} +registerBidder(spec); diff --git a/modules/performaxBidAdapter.md b/modules/performaxBidAdapter.md new file mode 100644 index 00000000000..4cf2984a79d --- /dev/null +++ b/modules/performaxBidAdapter.md @@ -0,0 +1,36 @@ +# Overview + +``` +Module Name: Performax Bid Adapter +Module Type: Bidder Adapter +Maintainer: development@performax.cz +``` + +# Description + +Connects to Performax exchange for bids. + +Performax bid adapter supports Banner. + + +# Sample Banner Ad Unit: For Publishers + +```javascript + var adUnits = [ + { + code: 'performax-div', + sizes: [[300, 300]], + bids: [ + { + bidder: "performax", + params: { + slotId: 28 // required + } + } + ] + } + ]; +``` + +Where: +* slotId - id of slot in PX system diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 9476b7a76a3..b153d0bf8db 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -71,6 +71,7 @@ config.setDefaults({ * @property {string} endpoint endpoint to contact * === optional params below === * @property {number} [timeout] timeout for S2S bidders - should be lower than `pbjs.requestBids({timeout})` + * @property {number} [defaultTtl] ttl for S2S bidders when pbs does not return a ttl on the response - defaults to 60` * @property {boolean} [cacheMarkup] whether to cache the adm result * @property {string} [adapter] adapter code to use for S2S * @property {string} [syncEndpoint] endpoint URL for syncing cookies @@ -239,27 +240,6 @@ function doClientSideSyncs(bidders) { }); } -function _getDigiTrustQueryParams(bidRequest = {}) { - function getDigiTrustId(bidRequest) { - const bidRequestDigitrust = utils.deepAccess(bidRequest, 'bids.0.userId.digitrustid.data'); - if (bidRequestDigitrust) { - return bidRequestDigitrust; - } - - const digiTrustUser = config.getConfig('digiTrustId'); - return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || null; - } - let digiTrustId = getDigiTrustId(bidRequest); - // Verify there is an ID and this user has not opted out - if (!digiTrustId || (digiTrustId.privacy && digiTrustId.privacy.optout)) { - return null; - } - return { - id: digiTrustId.id, - keyv: digiTrustId.keyv - }; -} - function _appendSiteAppDevice(request, pageUrl) { if (!request) return; @@ -269,11 +249,17 @@ function _appendSiteAppDevice(request, pageUrl) { request.app.publisher = {id: _s2sConfig.accountId} } else { request.site = {}; - if (typeof config.getConfig('site') === 'object') { + if (utils.isPlainObject(config.getConfig('site'))) { request.site = config.getConfig('site'); } - utils.deepSetValue(request.site, 'publisher.id', _s2sConfig.accountId); - request.site.page = pageUrl; + // set publisher.id if not already defined + if (!utils.deepAccess(request.site, 'publisher.id')) { + utils.deepSetValue(request.site, 'publisher.id', _s2sConfig.accountId); + } + // set site.page if not already defined + if (!request.site.page) { + request.site.page = pageUrl; + } } if (typeof config.getConfig('device') === 'object') { request.device = config.getConfig('device'); @@ -366,10 +352,55 @@ let nativeEventTrackerMethodMap = { */ let bidIdMap = {}; let nativeAssetCache = {}; // store processed native params to preserve + +/** + * map wurl to auction id and adId for use in the BID_WON event + */ +let wurlMap = {}; + +/** + * @param {string} auctionId + * @param {string} adId generated value set to bidObject.adId by bidderFactory Bid() + * @param {string} wurl events.winurl passed from prebidServer as wurl + */ +function addWurl(auctionId, adId, wurl) { + if ([auctionId, adId].every(utils.isStr)) { + wurlMap[`${auctionId}${adId}`] = wurl; + } +} + +/** + * @param {string} auctionId + * @param {string} adId generated value set to bidObject.adId by bidderFactory Bid() + */ +function removeWurl(auctionId, adId) { + if ([auctionId, adId].every(utils.isStr)) { + wurlMap[`${auctionId}${adId}`] = undefined; + } +} +/** + * @param {string} auctionId + * @param {string} adId generated value set to bidObject.adId by bidderFactory Bid() + * @return {(string|undefined)} events.winurl which was passed as wurl + */ +function getWurl(auctionId, adId) { + if ([auctionId, adId].every(utils.isStr)) { + return wurlMap[`${auctionId}${adId}`]; + } +} + +/** + * remove all cached wurls + */ +export function resetWurlMap() { + wurlMap = {}; +} + const OPEN_RTB_PROTOCOL = { buildRequest(s2sBidRequest, bidRequests, adUnits) { let imps = []; let aliases = {}; + const firstBidRequest = bidRequests[0]; // transform ad unit into array of OpenRTB impression objects adUnits.forEach(adUnit => { @@ -473,6 +504,9 @@ const OPEN_RTB_PROTOCOL = { // Don't push oustream w/o renderer to request object. utils.logError('Outstream bid without renderer cannot be sent to Prebid Server.'); } else { + if (videoParams.context === 'instream' && !videoParams.hasOwnProperty('placement')) { + videoParams.placement = 1; + } mediaTypes['video'] = videoParams; } } @@ -516,13 +550,24 @@ const OPEN_RTB_PROTOCOL = { */ const pbAdSlot = utils.deepAccess(adUnit, 'fpd.context.pbAdSlot'); if (typeof pbAdSlot === 'string' && pbAdSlot) { - utils.deepSetValue(imp, 'ext.context.data.adslot', pbAdSlot); + utils.deepSetValue(imp, 'ext.context.data.pbadslot', pbAdSlot); } + /** + * Copy GAM AdUnit and Name to imp + */ + ['name', 'adSlot'].forEach(name => { + /** @type {(string|undefined)} */ + const value = utils.deepAccess(adUnit, `fpd.context.adserver.${name}`); + if (typeof value === 'string' && value) { + utils.deepSetValue(imp, `ext.context.data.adserver.${name.toLowerCase()}`, value); + } + }); + Object.assign(imp, mediaTypes); // if storedAuctionResponse has been set, pass SRID - const storedAuctionResponseBid = find(bidRequests[0].bids, bid => (bid.adUnitCode === adUnit.code && bid.storedAuctionResponse)); + const storedAuctionResponseBid = find(firstBidRequest.bids, bid => (bid.adUnitCode === adUnit.code && bid.storedAuctionResponse)); if (storedAuctionResponseBid) { utils.deepSetValue(imp, 'ext.prebid.storedauctionresponse.id', storedAuctionResponseBid.storedAuctionResponse.toString()); } @@ -544,6 +589,8 @@ const OPEN_RTB_PROTOCOL = { test: getConfig('debug') ? 1 : 0, ext: { prebid: { + // set ext.prebid.auctiontimestamp with the auction timestamp. Data type is long integer. + auctiontimestamp: firstBidRequest.auctionStart, targeting: { // includewinners is always true for openrtb includewinners: true, @@ -571,12 +618,7 @@ const OPEN_RTB_PROTOCOL = { request.cur = [adServerCur[0]]; } - _appendSiteAppDevice(request, bidRequests[0].refererInfo.referer); - - const digiTrust = _getDigiTrustQueryParams(bidRequests && bidRequests[0]); - if (digiTrust) { - utils.deepSetValue(request, 'user.ext.digitrust', digiTrust); - } + _appendSiteAppDevice(request, firstBidRequest.refererInfo.referer); // pass schain object if it is present const schain = utils.deepAccess(bidRequests, '0.bids.0.schain'); @@ -596,19 +638,22 @@ const OPEN_RTB_PROTOCOL = { } if (bidRequests) { - if (bidRequests[0].gdprConsent) { + if (firstBidRequest.gdprConsent) { // note - gdprApplies & consentString may be undefined in certain use-cases for consentManagement module let gdprApplies; - if (typeof bidRequests[0].gdprConsent.gdprApplies === 'boolean') { - gdprApplies = bidRequests[0].gdprConsent.gdprApplies ? 1 : 0; + if (typeof firstBidRequest.gdprConsent.gdprApplies === 'boolean') { + gdprApplies = firstBidRequest.gdprConsent.gdprApplies ? 1 : 0; } utils.deepSetValue(request, 'regs.ext.gdpr', gdprApplies); - utils.deepSetValue(request, 'user.ext.consent', bidRequests[0].gdprConsent.consentString); + utils.deepSetValue(request, 'user.ext.consent', firstBidRequest.gdprConsent.consentString); + if (firstBidRequest.gdprConsent.addtlConsent && typeof firstBidRequest.gdprConsent.addtlConsent === 'string') { + utils.deepSetValue(request, 'user.ext.ConsentedProvidersSettings.consented_providers', firstBidRequest.gdprConsent.addtlConsent); + } } // US Privacy (CCPA) support - if (bidRequests[0].uspConsent) { - utils.deepSetValue(request, 'regs.ext.us_privacy', bidRequests[0].uspConsent); + if (firstBidRequest.uspConsent) { + utils.deepSetValue(request, 'regs.ext.us_privacy', firstBidRequest.uspConsent); } } @@ -658,10 +703,28 @@ const OPEN_RTB_PROTOCOL = { bidRequest.serverResponseTimeMs = serverResponseTimeMs; } - const extPrebidTargeting = utils.deepAccess(bid, 'ext.prebid.targeting'); + // Look for seatbid[].bid[].ext.prebid.bidid and place it in the bidResponse object for use in analytics adapters as 'pbsBidId' + const bidId = utils.deepAccess(bid, 'ext.prebid.bidid'); + if (utils.isStr(bidId)) { + bidObject.pbsBidId = bidId; + } + + // store wurl by auctionId and adId so it can be accessed from the BID_WON event handler + if (utils.isStr(utils.deepAccess(bid, 'ext.prebid.events.win'))) { + addWurl(bidRequest.auctionId, bidObject.adId, utils.deepAccess(bid, 'ext.prebid.events.win')); + } + + let extPrebidTargeting = utils.deepAccess(bid, 'ext.prebid.targeting'); // If ext.prebid.targeting exists, add it as a property value named 'adserverTargeting' - if (extPrebidTargeting && typeof extPrebidTargeting === 'object') { + // The removal of hb_winurl and hb_bidid targeting values is temporary + // once we get through the transition, this block will be removed. + if (utils.isPlainObject(extPrebidTargeting)) { + // If wurl exists, remove hb_winurl and hb_bidid targeting attributes + if (utils.isStr(utils.deepAccess(bid, 'ext.prebid.events.win'))) { + extPrebidTargeting = utils.getDefinedParams(extPrebidTargeting, Object.keys(extPrebidTargeting) + .filter(i => (i.indexOf('hb_winurl') === -1 && i.indexOf('hb_bidid') === -1))); + } bidObject.adserverTargeting = extPrebidTargeting; } @@ -759,9 +822,12 @@ const OPEN_RTB_PROTOCOL = { bidObject.creativeId = bid.crid; if (bid.burl) { bidObject.burl = bid.burl; } bidObject.currency = (response.cur) ? response.cur : DEFAULT_S2S_CURRENCY; + bidObject.meta = bidObject.meta || {}; + if (bid.adomain) { bidObject.meta.advertiserDomains = bid.adomain; } - // TODO: Remove when prebid-server returns ttl and netRevenue - bidObject.ttl = (bid.ttl) ? bid.ttl : DEFAULT_S2S_TTL; + const configTtl = _s2sConfig.defaultTtl || DEFAULT_S2S_TTL; + // the OpenRTB location for "TTL" as understood by Prebid.js is "exp" (expiration). + bidObject.ttl = (bid.exp) ? bid.exp : configTtl; bidObject.netRevenue = (bid.netRevenue) ? bid.netRevenue : DEFAULT_S2S_NETREVENUE; bids.push({ adUnit: bid.impid, bid: bidObject }); @@ -773,6 +839,21 @@ const OPEN_RTB_PROTOCOL = { } }; +/** + * BID_WON event to request the wurl + * @param {Bid} bid the winning bid object + */ +function bidWonHandler(bid) { + const wurl = getWurl(bid.auctionId, bid.adId); + if (utils.isStr(wurl)) { + utils.logMessage(`Invoking image pixel for wurl on BID_WIN: "${wurl}"`); + utils.triggerPixel(wurl); + + // remove from wurl cache, since the wurl url was called + removeWurl(bid.auctionId, bid.adId); + } +} + /** * Bidder adapter for Prebid Server */ @@ -856,6 +937,9 @@ export function PrebidServer() { doClientSideSyncs(requestedBidders); } + // Listen for bid won to call wurl + events.on(EVENTS.BID_WON, bidWonHandler); + return Object.assign(this, { callBids: baseAdapter.callBids, setBidderCode: baseAdapter.setBidderCode, diff --git a/modules/priceFloors.js b/modules/priceFloors.js index 9e9ed1e0d23..1b865e05c0a 100644 --- a/modules/priceFloors.js +++ b/modules/priceFloors.js @@ -103,7 +103,7 @@ export function getFirstMatchingFloor(floorData, bidObject, responseObject = {}) // if we already have gotten the matching rule from this matching input then use it! No need to look again let previousMatch = utils.deepAccess(floorData, `matchingInputs.${matchingInput}`); if (previousMatch) { - return previousMatch; + return {...previousMatch}; } let allPossibleMatches = generatePossibleEnumerations(fieldValues, utils.deepAccess(floorData, 'schema.delimiter') || '|'); let matchingRule = find(allPossibleMatches, hashValue => floorData.values.hasOwnProperty(hashValue)); @@ -138,10 +138,10 @@ function generatePossibleEnumerations(arrayOfFields, delimiter) { /** * @summary If a the input bidder has a registered cpmadjustment it returns the input CPM after being adjusted */ -export function getBiddersCpmAdjustment(bidderName, inputCpm) { +export function getBiddersCpmAdjustment(bidderName, inputCpm, bid = {}) { const adjustmentFunction = utils.deepAccess(getGlobal(), `bidderSettings.${bidderName}.bidCpmAdjustment`); if (adjustmentFunction) { - return parseFloat(adjustmentFunction(inputCpm)); + return parseFloat(adjustmentFunction(inputCpm, {...bid, cpm: inputCpm})); } return parseFloat(inputCpm); } @@ -274,10 +274,10 @@ export function getFloorDataFromAdUnits(adUnits) { /** * @summary This function takes the adUnits for the auction and update them accordingly as well as returns the rules hashmap for the auction */ -export function updateAdUnitsForAuction(adUnits, floorData, skipped, auctionId) { +export function updateAdUnitsForAuction(adUnits, floorData, auctionId) { adUnits.forEach((adUnit) => { adUnit.bids.forEach(bid => { - if (skipped) { + if (floorData.skipped) { delete bid.getFloor; } else { bid.getFloor = getFloor; @@ -285,19 +285,40 @@ export function updateAdUnitsForAuction(adUnits, floorData, skipped, auctionId) // information for bid and analytics adapters bid.auctionId = auctionId; bid.floorData = { - skipped, - modelVersion: utils.deepAccess(floorData, 'data.modelVersion') || '', - location: floorData.data.location, + skipped: floorData.skipped, + skipRate: floorData.skipRate, + modelVersion: utils.deepAccess(floorData, 'data.modelVersion'), + location: utils.deepAccess(floorData, 'data.location', 'noData'), + floorProvider: floorData.floorProvider, + fetchStatus: _floorsConfig.fetchStatus } }); }); } +export function pickRandomModel(modelGroups, weightSum) { + // we loop through the models subtracting the current model weight from our random number + // once we are at or below zero, we return the associated model + let random = Math.floor(Math.random() * weightSum + 1) + for (let i = 0; i < modelGroups.length; i++) { + random -= modelGroups[i].modelWeight; + if (random <= 0) { + return modelGroups[i]; + } + } +}; + /** * @summary Updates the adUnits accordingly and returns the necessary floorsData for the current auction */ export function createFloorsDataForAuction(adUnits, auctionId) { let resolvedFloorsData = utils.deepClone(_floorsConfig); + // if using schema 2 pick a model here: + if (utils.deepAccess(resolvedFloorsData, 'data.floorsSchemaVersion') === 2) { + // merge the models specific stuff into the top level data settings (now it looks like floorsSchemaVersion 1!) + let { modelGroups, ...rest } = resolvedFloorsData.data; + resolvedFloorsData.data = Object.assign(rest, pickRandomModel(modelGroups, rest.modelWeightSum)); + } // if we do not have a floors data set, we will try to use data set on adUnits let useAdUnitData = Object.keys(utils.deepAccess(resolvedFloorsData, 'data.values') || {}).length === 0; @@ -306,14 +327,17 @@ export function createFloorsDataForAuction(adUnits, auctionId) { } else { resolvedFloorsData.data = getFloorsDataForAuction(resolvedFloorsData.data); } - // if we still do not have a valid floor data then floors is not on for this auction + // if we still do not have a valid floor data then floors is not on for this auction, so skip if (Object.keys(utils.deepAccess(resolvedFloorsData, 'data.values') || {}).length === 0) { - return; + resolvedFloorsData.skipped = true; + } else { + // determine the skip rate now + const auctionSkipRate = utils.getParameterByName('pbjs_skipRate') || resolvedFloorsData.skipRate; + const isSkipped = Math.random() * 100 < parseFloat(auctionSkipRate); + resolvedFloorsData.skipped = isSkipped; } - // determine the skip rate now - const isSkipped = Math.random() * 100 < parseFloat(utils.deepAccess(resolvedFloorsData, 'data.skipRate') || 0); - resolvedFloorsData.skipped = isSkipped; - updateAdUnitsForAuction(adUnits, resolvedFloorsData, isSkipped, auctionId); + // add floorData to bids + updateAdUnitsForAuction(adUnits, resolvedFloorsData, auctionId); return resolvedFloorsData; } @@ -367,6 +391,36 @@ function validateRules(floorsData, numFields, delimiter) { return Object.keys(floorsData.values).length > 0; } +function modelIsValid(model) { + // schema.fields has only allowed attributes + if (!validateSchemaFields(utils.deepAccess(model, 'schema.fields'))) { + return false; + } + return validateRules(model, model.schema.fields.length, model.schema.delimiter || '|') +} + +/** + * @summary Mapping of floor schema version to it's corresponding validation + */ +const floorsSchemaValidation = { + 1: data => modelIsValid(data), + 2: data => { + // model groups should be an array with at least one element + if (!Array.isArray(data.modelGroups) || data.modelGroups.length === 0) { + return false; + } + // every model should have valid schema, as well as an accompanying modelWeight + data.modelWeightSum = 0; + return data.modelGroups.every(model => { + if (typeof model.modelWeight === 'number' && modelIsValid(model)) { + data.modelWeightSum += model.modelWeight; + return true; + } + return false; + }); + } +}; + /** * @summary Fields array should have at least one entry and all should match allowed fields * Each rule in the values array should have a 'key' and 'floor' param @@ -377,11 +431,12 @@ export function isFloorsDataValid(floorsData) { if (typeof floorsData !== 'object') { return false; } - // schema.fields has only allowed attributes - if (!validateSchemaFields(utils.deepAccess(floorsData, 'schema.fields'))) { + floorsData.floorsSchemaVersion = floorsData.floorsSchemaVersion || 1; + if (typeof floorsSchemaValidation[floorsData.floorsSchemaVersion] !== 'function') { + utils.logError(`${MODULE_NAME}: Unknown floorsSchemaVersion: `, floorsData.floorsSchemaVersion); return false; } - return validateRules(floorsData, floorsData.schema.fields.length, floorsData.schema.delimiter || '|') + return floorsSchemaValidation[floorsData.floorsSchemaVersion](floorsData); } /** @@ -389,6 +444,7 @@ export function isFloorsDataValid(floorsData) { */ export function parseFloorData(floorsData, location) { if (floorsData && typeof floorsData === 'object' && isFloorsDataValid(floorsData)) { + utils.logInfo(`${MODULE_NAME}: A ${location} set the auction floor data set to `, floorsData); return { ...floorsData, location @@ -416,6 +472,7 @@ export function requestBidsHook(fn, reqBidsConfigObj) { if (_floorsConfig.auctionDelay > 0 && fetching) { hookConfig.timer = setTimeout(() => { utils.logWarn(`${MODULE_NAME}: Fetch attempt did not return in time for auction`); + _floorsConfig.fetchStatus = 'timeout'; continueAuction(hookConfig); }, _floorsConfig.auctionDelay); _delayedAuctions.push(hookConfig); @@ -443,6 +500,7 @@ function resumeDelayedAuctions() { */ export function handleFetchResponse(fetchResponse) { fetching = false; + _floorsConfig.fetchStatus = 'success'; let floorResponse; try { floorResponse = JSON.parse(fetchResponse); @@ -450,7 +508,14 @@ export function handleFetchResponse(fetchResponse) { floorResponse = fetchResponse; } // Update the global floors object according to the fetched data - _floorsConfig.data = parseFloorData(floorResponse, 'fetch') || _floorsConfig.data; + const fetchData = parseFloorData(floorResponse, 'fetch'); + if (fetchData) { + // set .data to it + _floorsConfig.data = fetchData; + // set skipRate override if necessary + _floorsConfig.skipRate = utils.isNumber(fetchData.skipRate) ? fetchData.skipRate : _floorsConfig.skipRate; + _floorsConfig.floorProvider = fetchData.floorProvider || _floorsConfig.floorProvider; + } // if any auctions are waiting for fetch to finish, we need to continue them! resumeDelayedAuctions(); @@ -458,7 +523,8 @@ export function handleFetchResponse(fetchResponse) { function handleFetchError(status) { fetching = false; - utils.logError(`${MODULE_NAME}: Fetch errored with: ${status}`); + _floorsConfig.fetchStatus = 'error'; + utils.logError(`${MODULE_NAME}: Fetch errored with: `, status); // if any auctions are waiting for fetch to finish, we need to continue them! resumeDelayedAuctions(); @@ -504,7 +570,9 @@ export function handleSetFloorsConfig(config) { _floorsConfig = utils.pick(config, [ 'enabled', enabled => enabled !== false, // defaults to true 'auctionDelay', auctionDelay => auctionDelay || 0, + 'floorProvider', floorProvider => utils.deepAccess(config, 'data.floorProvider', floorProvider), 'endpoint', endpoint => endpoint || {}, + 'skipRate', () => !isNaN(utils.deepAccess(config, 'data.skipRate')) ? config.data.skipRate : config.skipRate || 0, 'enforcement', enforcement => utils.pick(enforcement || {}, [ 'enforceJS', enforceJS => enforceJS !== false, // defaults to true 'enforcePBS', enforcePBS => enforcePBS === true, // defaults to false @@ -522,8 +590,10 @@ export function handleSetFloorsConfig(config) { if (!addedFloorsHook) { // register hooks / listening events - // when auction finishes remove it's associated floor data - events.on(CONSTANTS.EVENTS.AUCTION_END, (args) => delete _floorDataForAuction[args.auctionId]); + // when auction finishes remove it's associated floor data after 3 seconds so we stil have it for latent responses + events.on(CONSTANTS.EVENTS.AUCTION_END, (args) => { + setTimeout(() => delete _floorDataForAuction[args.auctionId], 3000); + }); // we want our hooks to run after the currency hooks getGlobal().requestBids.before(requestBidsHook, 50); @@ -612,7 +682,7 @@ export function addBidResponseHook(fn, adUnitCode, bid) { } // ok we got the bid response cpm in our desired currency. Now we need to run the bidders CPMAdjustment function if it exists - adjustedCpm = getBiddersCpmAdjustment(bid.bidderCode, adjustedCpm); + adjustedCpm = getBiddersCpmAdjustment(bid.bidderCode, adjustedCpm, bid); // add necessary data information for analytics adapters / floor providers would possibly need addFloorDataToBid(floorData, floorInfo, bid, adjustedCpm); diff --git a/modules/priceFloors.md b/modules/priceFloors.md index d09be78c620..36ac07ee972 100644 --- a/modules/priceFloors.md +++ b/modules/priceFloors.md @@ -11,6 +11,7 @@ pbjs.setConfig({ enforceJS: true //defaults to true }, auctionDelay: 150, // in milliseconds defaults to 0 + floorProvider: 'awesomeFloorProviderName', // name of the floor provider (optional) endpoint: { url: 'http://localhost:1500/floor-domains', method: 'GET' // Only get supported for now @@ -40,6 +41,7 @@ pbjs.setConfig({ | enabled | Wether to turn off or on the floors module | | enforcement | object of booleans which control certain features of the module | | auctionDelay | The time to suspend and auction while waiting for a real time price floors fetch to come back | +| floorProvider | A string identifying the floor provider.| | endpoint | An object describing the endpoint to retrieve floor data from. GET only | | data | The data to be used to select appropriate floors. See schema for more detail | | additionalSchemaFields | An object of additional fields to be used in a floor data object. The schema is KEY: function to retrieve the match | @@ -59,4 +61,4 @@ This function can takes in an object with the following optional parameters: If a bid adapter passes in `*` as an attribute, then the `priceFloors` module will attempt to select the best rule based on context. -For example, if an adapter passes in a `*`, but the bidRequest only has a single size and a single mediaType, then the `getFloor` function will attempt to get a rule for that size before matching with the `*` catch-all. Similarily, if mediaType can be inferred on the bidRequest, it will use it. \ No newline at end of file +For example, if an adapter passes in a `*`, but the bidRequest only has a single size and a single mediaType, then the `getFloor` function will attempt to get a rule for that size before matching with the `*` catch-all. Similarily, if mediaType can be inferred on the bidRequest, it will use it. diff --git a/modules/projectLimeLightBidAdapter.js b/modules/projectLimeLightBidAdapter.js index f2ff77f6229..1beba906917 100644 --- a/modules/projectLimeLightBidAdapter.js +++ b/modules/projectLimeLightBidAdapter.js @@ -4,7 +4,6 @@ import {ajax} from '../src/ajax.js'; import * as utils from '../src/utils.js'; const BIDDER_CODE = 'project-limelight'; -const URL = 'https://ads.project-limelight.com/hb'; /** * Determines whether or not the given bid response is valid. @@ -25,19 +24,6 @@ function isBidResponseValid(bid) { return false; } -function extractBidSizes(bid) { - const bidSizes = []; - - bid.sizes.forEach(size => { - bidSizes.push({ - width: size[0], - height: size[1] - }); - }); - - return bidSizes; -} - export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO], @@ -65,30 +51,10 @@ export const spec = { } catch (e) { utils.logMessage(e); winTop = window; - }; - const placements = []; - const request = { - 'secure': (location.protocol === 'https:'), - 'deviceWidth': winTop.screen.width, - 'deviceHeight': winTop.screen.height, - 'adUnits': placements - }; - for (let i = 0; i < validBidRequests.length; i++) { - const bid = validBidRequests[i]; - const params = bid.params; - placements.push({ - id: params.adUnitId, - bidId: bid.bidId, - transactionId: bid.transactionId, - sizes: extractBidSizes(bid), - type: params.adUnitType.toUpperCase() - }); } - return { - method: 'POST', - url: URL, - data: request - }; + const placements = utils.groupBy(validBidRequests.map(bidRequest => buildPlacement(bidRequest)), 'host') + return Object.keys(placements) + .map(host => buildRequest(winTop, host, placements[host].map(placement => placement.adUnit))); }, onBidWon: (bid) => { @@ -123,3 +89,34 @@ export const spec = { }; registerBidder(spec); + +function buildRequest(winTop, host, adUnits) { + return { + method: 'POST', + url: `https://${host}/hb`, + data: { + secure: (location.protocol === 'https:'), + deviceWidth: winTop.screen.width, + deviceHeight: winTop.screen.height, + adUnits: adUnits + } + } +} + +function buildPlacement(bidRequest) { + return { + host: bidRequest.params.host, + adUnit: { + id: bidRequest.params.adUnitId, + bidId: bidRequest.bidId, + transactionId: bidRequest.transactionId, + sizes: bidRequest.sizes.map(size => { + return { + width: size[0], + height: size[1] + } + }), + type: bidRequest.params.adUnitType.toUpperCase() + } + } +} diff --git a/modules/projectLimeLightBidAdapter.md b/modules/projectLimeLightBidAdapter.md index 71621983b89..15aa170cd2e 100644 --- a/modules/projectLimeLightBidAdapter.md +++ b/modules/projectLimeLightBidAdapter.md @@ -18,6 +18,7 @@ Module that connects to Project Limelight SSP demand sources bids: [{ bidder: 'project-limelight', params: { + host: 'ads.project-limelight.com', adUnitId: 0, adUnitType: 'banner' } @@ -34,6 +35,7 @@ var videoAdUnit = [{ bids: [{ bidder: 'project-limelight', params: { + host: 'ads.project-limelight.com', adUnitId: 0, adUnitType: 'video' } diff --git a/modules/proxistoreBidAdapter.js b/modules/proxistoreBidAdapter.js index e8ef4878d8e..c546337c47f 100644 --- a/modules/proxistoreBidAdapter.js +++ b/modules/proxistoreBidAdapter.js @@ -1,11 +1,23 @@ -const { registerBidder } = require('../src/adapters/bidderFactory.js'); + +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { getStorageManager } from '../src/storageManager.js'; const BIDDER_CODE = 'proxistore'; +const storage = getStorageManager(); const PROXISTORE_VENDOR_ID = 418; function _createServerRequest(bidRequests, bidderRequest) { const sizeIds = []; - bidRequests.forEach(bid => { - const sizeId = {id: bid.bidId, sizes: bid.sizes.map(size => { return { width: size[0], height: size[1] } })}; + + bidRequests.forEach(function (bid) { + const sizeId = { + id: bid.bidId, + sizes: bid.sizes.map(function (size) { + return { + width: size[0], + height: size[1] + }; + }) + }; sizeIds.push(sizeId); }); const payload = { @@ -18,22 +30,22 @@ function _createServerRequest(bidRequests, bidderRequest) { applies: false } }; - const options = { contentType: 'application/json', withCredentials: true }; if (bidderRequest && bidderRequest.gdprConsent) { - if ((typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') && bidderRequest.gdprConsent.gdprApplies) { + if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean' && bidderRequest.gdprConsent.gdprApplies) { payload.gdpr.applies = true; } - if ((typeof bidderRequest.gdprConsent.consentString === 'string') && bidderRequest.gdprConsent.consentString) { + + if (typeof bidderRequest.gdprConsent.consentString === 'string' && bidderRequest.gdprConsent.consentString) { payload.gdpr.consentString = bidderRequest.gdprConsent.consentString; } - if (bidderRequest.gdprConsent.vendorData && bidderRequest.gdprConsent.vendorData.vendorConsents && - typeof bidderRequest.gdprConsent.vendorData.vendorConsents[PROXISTORE_VENDOR_ID.toString(10)] !== 'undefined') { - payload.gdpr.consentGiven = !!(bidderRequest.gdprConsent.vendorData.vendorConsents[PROXISTORE_VENDOR_ID.toString(10)]); + + if (bidderRequest.gdprConsent.vendorData && bidderRequest.gdprConsent.vendorData.vendorConsents && typeof bidderRequest.gdprConsent.vendorData.vendorConsents[PROXISTORE_VENDOR_ID.toString(10)] !== 'undefined') { + payload.gdpr.consentGiven = !!bidderRequest.gdprConsent.vendorData.vendorConsents[PROXISTORE_VENDOR_ID.toString(10)]; } } @@ -59,17 +71,31 @@ function _createBidResponse(response) { vastUrl: response.vastUrl, vastXml: response.vastXml, dealId: response.dealId - } + }; } - /** * Determines whether or not the given bid request is valid. * * @param bid The bid params to validate. * @return boolean True if this is a valid bid, and false otherwise. */ + function isBidRequestValid(bid) { - return !!(bid.params.website && bid.params.language); + const hasNoAd = function() { + if (!storage.hasLocalStorage()) { + return false; + } + const pxNoAds = storage.getDataFromLocalStorage(`PX_NoAds_${bid.params.website}`); + if (!pxNoAds) { + return false; + } else { + const storedDate = new Date(pxNoAds); + const now = new Date(); + const diff = Math.abs(storedDate.getTime() - now.getTime()) / 60000; + return diff <= 5; + } + } + return !!(bid.params.website && bid.params.language) && !hasNoAd(); } /** @@ -79,11 +105,11 @@ function isBidRequestValid(bid) { * @param bidderRequest * @return ServerRequest Info describing the request to the server. */ + function buildRequests(bidRequests, bidderRequest) { - var request = _createServerRequest(bidRequests, bidderRequest); + const request = _createServerRequest(bidRequests, bidderRequest); return request; } - /** * Unpack the response from the server into a list of bids. * @@ -91,14 +117,26 @@ function buildRequests(bidRequests, bidderRequest) { * @param bidRequest Request original server request * @return An array of bids which were nested inside the server. */ + function interpretResponse(serverResponse, bidRequest) { + const itemName = `PX_NoAds_${websiteFromBidRequest(bidRequest)}`; if (serverResponse.body.length > 0) { + storage.removeDataFromLocalStorage(itemName, true); return serverResponse.body.map(_createBidResponse); } else { + storage.setDataInLocalStorage(itemName, new Date()); return []; } } +const websiteFromBidRequest = function(bidR) { + if (bidR.data) { + return JSON.parse(bidR.data).website + } else if (bidR.params.website) { + return bidR.params.website; + } +} + /** * Register the user sync pixels which should be dropped after the auction. * @@ -106,11 +144,12 @@ function interpretResponse(serverResponse, bidRequest) { * @param serverResponses List of server's responses. * @return The user syncs which should be dropped. */ + function getUserSyncs(syncOptions, serverResponses) { return []; } -const spec = { +export const spec = { code: BIDDER_CODE, isBidRequestValid: isBidRequestValid, buildRequests: buildRequests, @@ -119,5 +158,3 @@ const spec = { }; registerBidder(spec); - -module.exports = spec; diff --git a/modules/pubCommonIdSystem.js b/modules/pubCommonIdSystem.js index 8e2be1207f5..9516934de42 100644 --- a/modules/pubCommonIdSystem.js +++ b/modules/pubCommonIdSystem.js @@ -7,11 +7,14 @@ import * as utils from '../src/utils.js'; import {submodule} from '../src/hook.js'; +import {getStorageManager} from '../src/storageManager.js'; const PUB_COMMON_ID = 'PublisherCommonId'; const MODULE_NAME = 'pubCommonId'; +const storage = getStorageManager(null, 'pubCommonId'); + /** @type {Submodule} */ export const pubCommonIdSubmodule = { /** @@ -90,6 +93,33 @@ export const pubCommonIdSubmodule = { const callback = this.makeCallback(pixelUrl, storedId); return callback ? {callback: callback} : {id: storedId}; } + }, + + /** + * @param {string} domain + * @param {HTMLDocument} document + * @return {(string|undefined)} + */ + domainOverride: function () { + const domainElements = document.domain.split('.'); + const cookieName = `_gd${Date.now()}`; + for (let i = 0, topDomain; i < domainElements.length; i++) { + const nextDomain = domainElements.slice(i).join('.'); + + // write test cookie + storage.setCookie(cookieName, '1', undefined, undefined, nextDomain); + + // read test cookie to verify domain was valid + if (storage.getCookie(cookieName) === '1') { + // delete test cookie + storage.setCookie(cookieName, '', 'Thu, 01 Jan 1970 00:00:01 GMT', undefined, nextDomain); + // cookie was written successfully using test domain so the topDomain is updated + topDomain = nextDomain; + } else { + // cookie failed to write using test domain so exit by returning the topDomain + return topDomain; + } + } } }; diff --git a/modules/pubProvidedSystem.js b/modules/pubProvidedSystem.js new file mode 100644 index 00000000000..575633e622f --- /dev/null +++ b/modules/pubProvidedSystem.js @@ -0,0 +1,53 @@ +/** + * This module adds Publisher Provided ids support to the User ID module + * The {@link module:modules/userId} module is required. + * @module modules/pubProvidedSystem + * @requires module:modules/userId + */ + +import {submodule} from '../src/hook.js'; +import * as utils from '../src/utils.js'; + +const MODULE_NAME = 'pubProvidedId'; + +/** @type {Submodule} */ +export const pubProvidedIdSubmodule = { + + /** + * used to link submodule with config + * @type {string} + */ + name: MODULE_NAME, + + /** + * decode the stored id value for passing to bid request + * @function + * @param {string} value + * @returns {{pubProvidedId: array}} or undefined if value doesn't exists + */ + decode(value) { + const res = value ? {pubProvidedId: value} : undefined; + utils.logInfo('PubProvidedId: Decoded value ' + JSON.stringify(res)); + return res; + }, + + /** + * performs action to obtain id and return a value. + * @function + * @param {SubmoduleParams} [configParams] + * @returns {{id: array}} + */ + getId(configParams) { + let res = []; + if (utils.isArray(configParams.eids)) { + res = res.concat(configParams.eids); + } + if (typeof configParams.eidsFunction === 'function') { + res = res.concat(configParams.eidsFunction()); + } + return {id: res}; + } +}; + +// Register submodule for userId +submodule('userId', pubProvidedIdSubmodule); diff --git a/modules/pubgeniusBidAdapter.js b/modules/pubgeniusBidAdapter.js new file mode 100644 index 00000000000..05f18f99a9a --- /dev/null +++ b/modules/pubgeniusBidAdapter.js @@ -0,0 +1,224 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { ajax } from '../src/ajax.js'; +import { config } from '../src/config.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { + deepAccess, + deepSetValue, + inIframe, + isArrayOfNums, + isInteger, + isNumber, + isStr, + logError, + parseQueryStringParameters, +} from '../src/utils.js'; + +const BIDDER_VERSION = '1.0.0'; +const BASE_URL = 'https://ortb.adpearl.io'; + +export const spec = { + code: 'pubgenius', + + supportedMediaTypes: [ BANNER ], + + isBidRequestValid(bid) { + const adUnitId = bid.params.adUnitId; + if (!isStr(adUnitId) && !isInteger(adUnitId)) { + logError('pubgenius bidder params: adUnitId must be a string or integer.'); + return false; + } + + const sizes = deepAccess(bid, 'mediaTypes.banner.sizes'); + return !!(sizes && sizes.length) && sizes.every(size => isArrayOfNums(size, 2)); + }, + + buildRequests: function (bidRequests, bidderRequest) { + const data = { + id: bidderRequest.auctionId, + imp: bidRequests.map(buildImp), + tmax: config.getConfig('bidderTimeout'), + ext: { + pbadapter: { + version: BIDDER_VERSION, + }, + }, + }; + + const site = buildSite(bidderRequest); + if (site) { + data.site = site; + } + + const gdpr = bidderRequest.gdprConsent; + if (gdpr) { + const applies = gdpr.gdprApplies; + const consent = gdpr.consentString; + deepSetValue(data, 'regs.ext.gdpr', numericBoolean(applies)); + if (applies && consent) { + deepSetValue(data, 'user.ext.consent', consent); + } + } + + const usp = bidderRequest.uspConsent; + if (usp) { + deepSetValue(data, 'regs.ext.us_privacy', usp); + } + + const schain = bidRequests[0].schain; + if (schain) { + deepSetValue(data, 'source.ext.schain', schain); + } + + if (config.getConfig('coppa')) { + deepSetValue(data, 'regs.coppa', 1); + } + + const bidUserIdAsEids = deepAccess(bidRequests, '0.userIdAsEids'); + if (bidUserIdAsEids && bidUserIdAsEids.length) { + const eids = bidUserIdAsEids.filter(eid => eid.source === 'adserver.org'); + if (eids.length) { + deepSetValue(data, 'user.ext.eids', eids); + } + } + + return { + method: 'POST', + url: `${getBaseUrl()}/prebid/auction`, + data, + }; + }, + + interpretResponse({ body }) { + const bidResponses = []; + const currency = body.cur || 'USD'; + const seatbids = body.seatbid; + + if (seatbids) { + seatbids.forEach(seatbid => { + seatbid.bid.forEach(bid => { + const bidResponse = interpretBid(bid); + bidResponse.currency = currency; + bidResponses.push(bidResponse); + }); + }); + } + + return bidResponses; + }, + + getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) { + const syncs = [] + + if (syncOptions.iframeEnabled) { + let params = {}; + + if (gdprConsent) { + params.gdpr = numericBoolean(gdprConsent.gdprApplies); + if (gdprConsent.consentString) { + params.consent = gdprConsent.consentString; + } + } + + if (uspConsent) { + params.us_privacy = uspConsent; + } + + const qs = parseQueryStringParameters(params); + syncs.push({ + type: 'iframe', + url: `${getBaseUrl()}/usersync/pixels.html?${qs}`, + }); + } + + return syncs; + }, + + onTimeout(data) { + ajax(`${getBaseUrl()}/prebid/events?type=timeout`, null, JSON.stringify(data), { + method: 'POST', + }); + }, +}; + +function buildImp(bid) { + const imp = { + id: bid.bidId, + banner: { + format: deepAccess(bid, 'mediaTypes.banner.sizes').map(size => ({ w: size[0], h: size[1] })), + topframe: numericBoolean(!inIframe()), + }, + tagid: String(bid.params.adUnitId), + }; + + const bidFloor = bid.params.bidFloor; + if (isNumber(bidFloor)) { + imp.bidfloor = bidFloor; + } + + const pos = bid.params.position; + if (isInteger(pos)) { + imp.banner.pos = pos; + } + + if (bid.params.test) { + deepSetValue(imp, 'ext.test', 1); + } + + return imp; +} + +function buildSite(bidderRequest) { + let site = null; + const { refererInfo } = bidderRequest; + + const pageUrl = config.getConfig('pageUrl') || refererInfo.canonicalUrl || refererInfo.referer; + if (pageUrl) { + site = site || {}; + site.page = pageUrl; + } + + if (refererInfo.reachedTop) { + try { + const pageRef = window.top.document.referrer; + if (pageRef) { + site = site || {}; + site.ref = pageRef; + } + } catch (e) {} + } + + return site; +} + +function interpretBid(bid) { + const bidResponse = { + requestId: bid.impid, + cpm: bid.price, + width: bid.w, + height: bid.h, + ad: bid.adm, + ttl: bid.exp, + creativeId: bid.crid, + netRevenue: true, + }; + + if (bid.adomain && bid.adomain.length) { + bidResponse.meta = { + advertiserDomains: bid.adomain, + }; + } + + return bidResponse; +} + +function numericBoolean(value) { + return value ? 1 : 0; +} + +function getBaseUrl() { + const pubg = config.getConfig('pubgenius'); + return (pubg && pubg.endpoint) || BASE_URL; +} + +registerBidder(spec); diff --git a/modules/pubgeniusBidAdapter.md b/modules/pubgeniusBidAdapter.md new file mode 100644 index 00000000000..66851af9c3f --- /dev/null +++ b/modules/pubgeniusBidAdapter.md @@ -0,0 +1,65 @@ +# Overview + +``` +Module Name: pubGENIUS Bidder Adapter +Module Type: Bidder Adapter +Maintainer: meng@pubgenius.io +``` + +# Description + +Module that connects to pubGENIUS's demand sources + +# Test Parameters + +Test bids have $0.01 CPM by default. Use `bidFloor` in bidder params to control CPM for testing purposes. + +``` +var adUnits = [ + { + code: 'test-desktop-banner', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [ + { + bidder: 'pubgenius', + params: { + adUnitId: '1000', + test: true + } + } + ] + }, + { + code: 'test-mobile-banner', + mediaTypes: { + banner: { + sizes: [[320, 50]] + } + }, + bids: [ + { + bidder: 'pubgenius', + params: { + adUnitId: '1000', + bidFloor: 0.5, + test: true + } + } + ] + } +]; +``` + +# Optional Config + +By default, the adapter uses the page URL as provided in referer info by Prebid.js. +The following config overrides this behavior and specifies the URL to be used: +``` +pbjs.setConfig({ + pageUrl: 'https://example.com/top-page-url/' +}); +``` diff --git a/modules/pubmaticAnalyticsAdapter.js b/modules/pubmaticAnalyticsAdapter.js index 9d2f45159e9..04c6606a299 100755 --- a/modules/pubmaticAnalyticsAdapter.js +++ b/modules/pubmaticAnalyticsAdapter.js @@ -4,6 +4,7 @@ import CONSTANTS from '../src/constants.json'; import { ajax } from '../src/ajax.js'; import { config } from '../src/config.js'; import * as utils from '../src/utils.js'; +import { getGlobal } from '../src/prebidGlobal.js'; /// /////////// CONSTANTS ////////////// const ADAPTER_CODE = 'pubmatic'; @@ -124,7 +125,19 @@ function parseBidResponse(bid) { if (typeof bid.getCpmInNewCurrency === 'function') { return window.parseFloat(Number(bid.getCpmInNewCurrency(CURRENCY_USD)).toFixed(BID_PRECISION)); } - utils.logWarn(LOG_PRE_FIX + 'Could not determine the bidPriceUSD of the bid ', bid); + utils.logWarn(LOG_PRE_FIX + 'Could not determine the Net cpm in USD for the bid thus using bid.cpm', bid); + return bid.cpm + }, + 'bidGrossCpmUSD', () => { + if (typeof bid.originalCurrency === 'string' && bid.originalCurrency.toUpperCase() === CURRENCY_USD) { + return window.parseFloat(Number(bid.originalCpm).toFixed(BID_PRECISION)); + } + // use currency conversion function if present + if (typeof getGlobal().convertCurrency === 'function') { + return window.parseFloat(Number(getGlobal().convertCurrency(bid.originalCpm, bid.originalCurrency, CURRENCY_USD)).toFixed(BID_PRECISION)); + } + utils.logWarn(LOG_PRE_FIX + 'Could not determine the Gross cpm in USD for the bid, thus using bid.originalCpm', bid); + return bid.originalCpm }, 'dealId', 'currency', @@ -139,6 +152,7 @@ function parseBidResponse(bid) { 'mediaType', 'params', 'mi', + 'partnerImpId', // partner impression ID 'dimensions', () => utils.pick(bid, [ 'width', 'height' @@ -152,20 +166,8 @@ function getDomainFromUrl(url) { return a.hostname; } -function getHighestBidForAdUnit(adUnit) { - return Object.keys(adUnit.bids).reduce(function(currentHighestBid, bidId) { - // todo: later we will need to consider grossECPM and netECPM - let bid = adUnit.bids[bidId]; - if (bid.bidResponse && bid.bidResponse.bidPriceUSD > currentHighestBid.bidPriceUSD) { - currentHighestBid.bidPriceUSD = bid.bidResponse.bidPriceUSD; - currentHighestBid.bidId = bidId; - } - return currentHighestBid; - }, {bidId: '', bidPriceUSD: 0}); -} - -function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId) { - const highestsBid = getHighestBidForAdUnit(adUnit); +function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid) { + highestBid = (highestBid && highestBid.length > 0) ? highestBid[0] : null; return Object.keys(adUnit.bids).reduce(function(partnerBids, bidId) { let bid = adUnit.bids[bidId]; partnerBids.push({ @@ -175,26 +177,27 @@ function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId) { 'kgpv': bid.params.kgpv ? bid.params.kgpv : adUnitId, 'kgpsv': bid.params.kgpv ? bid.params.kgpv : adUnitId, 'psz': bid.bidResponse ? (bid.bidResponse.dimensions.width + 'x' + bid.bidResponse.dimensions.height) : '0x0', - 'eg': bid.bidResponse ? bid.bidResponse.bidPriceUSD : 0, // todo: later we will need to consider grossECPM and netECPM, precision - 'en': bid.bidResponse ? bid.bidResponse.bidPriceUSD : 0, // todo: later we will need to consider grossECPM and netECPM, precision + 'eg': bid.bidResponse ? bid.bidResponse.bidGrossCpmUSD : 0, + 'en': bid.bidResponse ? bid.bidResponse.bidPriceUSD : 0, 'di': bid.bidResponse ? (bid.bidResponse.dealId || EMPTY_STRING) : EMPTY_STRING, 'dc': bid.bidResponse ? (bid.bidResponse.dealChannel || EMPTY_STRING) : EMPTY_STRING, 'l1': bid.bidResponse ? bid.clientLatencyTimeMs : 0, 'l2': 0, - // 'ss': (bid.source === 'server' ? 1 : 0), // todo: is there any special handling required as per OW? 'ss': (s2sBidders.indexOf(bid.bidder) > -1) ? 1 : 0, 't': (bid.status == ERROR && bid.error.code == TIMEOUT_ERROR) ? 1 : 0, - 'wb': highestsBid.bidId === bid.bidId ? 1 : 0, + 'wb': (highestBid && highestBid.requestId === bid.bidId ? 1 : 0), 'mi': bid.bidResponse ? (bid.bidResponse.mi || undefined) : undefined, 'af': bid.bidResponse ? (bid.bidResponse.mediaType || undefined) : undefined, 'ocpm': bid.bidResponse ? (bid.bidResponse.originalCpm || 0) : 0, - 'ocry': bid.bidResponse ? (bid.bidResponse.originalCurrency || CURRENCY_USD) : CURRENCY_USD + 'ocry': bid.bidResponse ? (bid.bidResponse.originalCurrency || CURRENCY_USD) : CURRENCY_USD, + 'piid': bid.bidResponse ? (bid.bidResponse.partnerImpId || EMPTY_STRING) : EMPTY_STRING }); return partnerBids; }, []) } -function executeBidsLoggerCall(auctionId) { +function executeBidsLoggerCall(e, highestCpmBids) { + let auctionId = e.auctionId; let referrer = config.getConfig('pageUrl') || cache.auctions[auctionId].referer || ''; let auctionCache = cache.auctions[auctionId]; let outputObj = { s: [] }; @@ -217,20 +220,20 @@ function executeBidsLoggerCall(auctionId) { outputObj['tst'] = Math.round((new window.Date()).getTime() / 1000); outputObj['pid'] = '' + profileId; outputObj['pdvid'] = '' + profileVersionId; - - // GDPR support - if (auctionCache.gdprConsent) { - outputObj['cns'] = auctionCache.gdprConsent.consentString || ''; - outputObj['gdpr'] = auctionCache.gdprConsent.gdprApplies === true ? 1 : 0; - pixelURL += '&gdEn=1'; - } + outputObj['tgid'] = (function() { + var testGroupId = parseInt(config.getConfig('testGroupId') || 0); + if (testGroupId <= 15 && testGroupId >= 0) { + return testGroupId; + } + return 0; + })(); outputObj.s = Object.keys(auctionCache.adUnitCodes).reduce(function(slotsArray, adUnitId) { let adUnit = auctionCache.adUnitCodes[adUnitId]; let slotObject = { 'sn': adUnitId, 'sz': adUnit.dimensions.map(e => e[0] + 'x' + e[1]), - 'ps': gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId) + 'ps': gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestCpmBids.filter(bid => bid.adUnitCode === adUnitId)) }; slotsArray.push(slotObject); return slotsArray; @@ -263,9 +266,10 @@ function executeBidWonLoggerCall(auctionId, adUnitId) { pixelURL += '&pdvid=' + enc(profileVersionId); pixelURL += '&slot=' + enc(adUnitId); pixelURL += '&pn=' + enc(winningBid.bidder); - pixelURL += '&en=' + enc(winningBid.bidResponse.bidPriceUSD); // todo: later we will need to consider grossECPM and netECPM - pixelURL += '&eg=' + enc(winningBid.bidResponse.bidPriceUSD); // todo: later we will need to consider grossECPM and netECPM + pixelURL += '&en=' + enc(winningBid.bidResponse.bidPriceUSD); + pixelURL += '&eg=' + enc(winningBid.bidResponse.bidGrossCpmUSD); pixelURL += '&kgpv=' + enc(winningBid.params.kgpv || adUnitId); + pixelURL += '&piid=' + enc(winningBid.bidResponse.partnerImpId || EMPTY_STRING); ajax( pixelURL, null, @@ -296,7 +300,6 @@ function auctionInitHandler(args) { } function bidRequestedHandler(args) { - cache.auctions[args.auctionId].gdprConsent = args.gdprConsent || undefined; args.bids.forEach(function(bid) { if (!cache.auctions[args.auctionId].adUnitCodes.hasOwnProperty(bid.adUnitCode)) { cache.auctions[args.auctionId].adUnitCodes[bid.adUnitCode] = { @@ -345,8 +348,9 @@ function bidWonHandler(args) { function auctionEndHandler(args) { // if for the given auction bidderDonePendingCount == 0 then execute logger call sooners + let highestCpmBids = getGlobal().getHighestCpmBids() || []; setTimeout(() => { - executeBidsLoggerCall.call(this, args.auctionId); + executeBidsLoggerCall.call(this, args, highestCpmBids); }, (cache.auctions[args.auctionId].bidderDonePendingCount === 0 ? 500 : SEND_TIMEOUT)); } diff --git a/modules/pubmaticAnalyticsAdapter.md b/modules/pubmaticAnalyticsAdapter.md new file mode 100644 index 00000000000..097f0b3d792 --- /dev/null +++ b/modules/pubmaticAnalyticsAdapter.md @@ -0,0 +1,23 @@ +# PubMatic Analytics Adapter + +``` +Module Name: PubMatic Analytics Adapter +Module Type: Analytics Adapter +Maintainer: header-bidding@pubmatic.com +``` + +## How to configure? +``` +pbjs.enableAnalytics({ + provider: 'pubmatic', + options: { + "publisherId": 12345 // please contact PubMatic to get a publisherId for yourself + } +}); +``` + +## Limitations: +- Supports only Banner and Video media-type +- Does not supports Native media type +- Does not supports instream-video creative-render tracker +- If a currency module is NOT included and a bidder responds in a non-USD currency then PubMatic analytics bidder will log values in original bid currency otherwise always logged in USD \ No newline at end of file diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js index 4502dc66a65..b5514ab0344 100644 --- a/modules/pubmaticBidAdapter.js +++ b/modules/pubmaticBidAdapter.js @@ -2,6 +2,7 @@ import * as utils from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; import {config} from '../src/config.js'; +import { Renderer } from '../src/Renderer.js'; const BIDDER_CODE = 'pubmatic'; const LOG_WARN_PREFIX = 'PubMatic: '; @@ -10,11 +11,12 @@ const USER_SYNC_URL_IFRAME = 'https://ads.pubmatic.com/AdServer/js/showad.js#PIX const USER_SYNC_URL_IMAGE = 'https://image8.pubmatic.com/AdServer/ImgSync?p='; const DEFAULT_CURRENCY = 'USD'; const AUCTION_TYPE = 1; -const PUBMATIC_DIGITRUST_KEY = 'nFIn8aLzbd'; const UNDEFINED = undefined; const DEFAULT_WIDTH = 0; const DEFAULT_HEIGHT = 0; const PREBID_NATIVE_HELP_LINK = 'http://prebid.org/dev-docs/show-native-ads.html'; +const PUBLICATION = 'pubmatic'; // Your publication on Blue Billywig, potentially with environment (e.g. publication.bbvms.com or publication.test.bbvms.com) +const RENDERER_URL = 'https://pubmatic.bbvms.com/r/'.concat('$RENDERER', '.js'); // URL of the renderer application const CUSTOM_PARAMS = { 'kadpageurl': '', // Custom page url 'gender': '', // User gender @@ -105,6 +107,60 @@ const dealChannelValues = { 5: 'PREF', 6: 'PMPG' }; +// BB stands for Blue BillyWig +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(`${LOG_WARN_PREFIX}: No vastXml or vastUrl on bid, bailing...`); + return; + } + + const rendererId = BB_RENDERER.getRendererId(PUBLICATION, 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(`${LOG_WARN_PREFIX}: Couldn't find a renderer with ${rendererId}`); + }, + newRenderer: function(rendererCode, adUnitCode) { + var rendererUrl = RENDERER_URL.replace('$RENDERER', rendererCode); + const renderer = Renderer.install({ + url: rendererUrl, + loaded: false, + adUnitCode + }); + + try { + renderer.setRender(BB_RENDERER.outstreamRender); + } catch (err) { + utils.logWarn(`${LOG_WARN_PREFIX}: 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! + } +}; let publisherId = 0; let isInvalidNativeRequest = false; @@ -586,96 +642,41 @@ function _createImpressionObject(bid, conf) { impObj.banner = bannerObj; } + _addFloorFromFloorModule(impObj, bid); + return impObj.hasOwnProperty(BANNER) || impObj.hasOwnProperty(NATIVE) || impObj.hasOwnProperty(VIDEO) ? impObj : UNDEFINED; } -function _getDigiTrustObject(key) { - function getDigiTrustId() { - let digiTrustUser = window.DigiTrust && (config.getConfig('digiTrustId') || window.DigiTrust.getUser({member: key})); - return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || null; - } - let digiTrustId = getDigiTrustId(); - // Verify there is an ID and this user has not opted out - if (!digiTrustId || (digiTrustId.privacy && digiTrustId.privacy.optout)) { - return null; - } - return digiTrustId; -} - -function _handleDigitrustId(eids) { - let digiTrustId = _getDigiTrustObject(PUBMATIC_DIGITRUST_KEY); - if (digiTrustId !== null) { - eids.push({ - 'source': 'digitru.st', - 'uids': [{ - 'id': digiTrustId.id || '', - 'atype': 1, - 'ext': { - 'keyv': parseInt(digiTrustId.keyv) || 0 +function _addFloorFromFloorModule(impObj, bid) { + let bidFloor = -1; + // get lowest floor from floorModule + if (typeof bid.getFloor === 'function' && !config.getConfig('pubmatic.disableFloors')) { + [BANNER, VIDEO, NATIVE].forEach(mediaType => { + if (impObj.hasOwnProperty(mediaType)) { + let floorInfo = bid.getFloor({ currency: impObj.bidfloorcur, mediaType: mediaType, size: '*' }); + if (typeof floorInfo === 'object' && floorInfo.currency === impObj.bidfloorcur && !isNaN(parseInt(floorInfo.floor))) { + let mediaTypeFloor = parseFloat(floorInfo.floor); + bidFloor = (bidFloor == -1 ? mediaTypeFloor : Math.min(mediaTypeFloor, bidFloor)) } - }] + } }); } -} - -function _handleTTDId(eids, validBidRequests) { - let ttdId = null; - let adsrvrOrgId = config.getConfig('adsrvrOrgId'); - if (utils.isStr(utils.deepAccess(validBidRequests, '0.userId.tdid'))) { - ttdId = validBidRequests[0].userId.tdid; - } else if (adsrvrOrgId && utils.isStr(adsrvrOrgId.TDID)) { - ttdId = adsrvrOrgId.TDID; + // get highest from impObj.bidfllor and floor from floor module + // as we are using Math.max, it is ok if we have not got any floor from floorModule, then value of bidFloor will be -1 + if (impObj.bidfloor) { + bidFloor = Math.max(bidFloor, impObj.bidfloor) } - if (ttdId !== null) { - eids.push({ - 'source': 'adserver.org', - 'uids': [{ - 'id': ttdId, - 'atype': 1, - 'ext': { - 'rtiPartner': 'TDID' - } - }] - }); - } -} - -/** - * Produces external userid object in ortb 3.0 model. - */ -function _addExternalUserId(eids, value, source, atype) { - if (utils.isStr(value)) { - eids.push({ - source, - uids: [{ - id: value, - atype - }] - }); - } + // assign value only if bidFloor is > 0 + impObj.bidfloor = ((!isNaN(bidFloor) && bidFloor > 0) ? bidFloor : UNDEFINED); } function _handleEids(payload, validBidRequests) { - let eids = []; - _handleDigitrustId(eids); - _handleTTDId(eids, validBidRequests); - const bidRequest = validBidRequests[0]; - if (bidRequest && bidRequest.userId) { - _addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.pubcid`), 'pubcid.org', 1); - _addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.digitrustid.data.id`), 'digitru.st', 1); - _addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.id5id`), 'id5-sync.com', 1); - _addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.criteoId`), 'criteo.com', 1);// replacing criteoRtus - _addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.idl_env`), 'liveramp.com', 1); - _addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.lipb.lipbid`), 'liveintent.com', 1); - _addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.parrableid`), 'parrable.com', 1); - _addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.britepoolid`), 'britepool.com', 1); - _addExternalUserId(eids, utils.deepAccess(bidRequest, `userId.netId`), 'netid.de', 1); - } - if (eids.length > 0) { - payload.user.eids = eids; + const bidUserIdAsEids = utils.deepAccess(validBidRequests, '0.userIdAsEids'); + if (utils.isArray(bidUserIdAsEids) && bidUserIdAsEids.length > 0) { + utils.deepSetValue(payload, 'user.eids', bidUserIdAsEids); } } @@ -816,6 +817,23 @@ function _handleDealCustomTargetings(payload, dctrArr, validBidRequests) { } } +function _assignRenderer(newBid, request) { + let bidParams, context, adUnitCode; + if (request.bidderRequest && request.bidderRequest.bids) { + for (let bidderRequestBidsIndex = 0; bidderRequestBidsIndex < request.bidderRequest.bids.length; bidderRequestBidsIndex++) { + if (request.bidderRequest.bids[bidderRequestBidsIndex].bidId === newBid.requestId) { + bidParams = request.bidderRequest.bids[bidderRequestBidsIndex].params; + context = request.bidderRequest.bids[bidderRequestBidsIndex].mediaTypes[VIDEO].context; + adUnitCode = request.bidderRequest.bids[bidderRequestBidsIndex].adUnitCode; + } + } + if (context && context === 'outstream' && bidParams && bidParams.outstreamAU && adUnitCode) { + newBid.rendererCode = bidParams.outstreamAU; + newBid.renderer = BB_RENDERER.newRenderer(newBid.rendererCode, adUnitCode); + } + } +}; + export const spec = { code: BIDDER_CODE, gvlid: 76, @@ -829,7 +847,7 @@ export const spec = { isBidRequestValid: bid => { if (bid && bid.params) { if (!utils.isStr(bid.params.publisherId)) { - utils.logWarn(LOG_WARN_PREFIX + 'Error: publisherId is mandatory and cannot be numeric. Call to OpenBid will not be sent for ad unit: ' + JSON.stringify(bid)); + utils.logWarn(LOG_WARN_PREFIX + 'Error: publisherId is mandatory and cannot be numeric (wrap it in quotes in your config). Call to OpenBid will not be sent for ad unit: ' + JSON.stringify(bid)); return false; } // video ad validation @@ -838,6 +856,19 @@ export const spec = { utils.logWarn(LOG_WARN_PREFIX + 'Error: For video ads, mimes is mandatory and must specify atlease 1 mime value. Call to OpenBid will not be sent for ad unit:' + JSON.stringify(bid)); return false; } + if (bid.hasOwnProperty('mediaTypes') && bid.mediaTypes.hasOwnProperty(VIDEO)) { + if (!bid.mediaTypes[VIDEO].hasOwnProperty('context')) { + utils.logError(`${LOG_WARN_PREFIX}: no context specified in bid. Rejecting bid: `, bid); + return false; + } + if (bid.mediaTypes[VIDEO].context === 'outstream' && !utils.isStr(bid.params.outstreamAU)) { + utils.logError(`${LOG_WARN_PREFIX}: for "outstream" bids outstreamAU is required. Rejecting bid: `, bid); + return false; + } + } else { + utils.logError(`${LOG_WARN_PREFIX}: mediaTypes or mediaTypes.video is not specified. Rejecting bid: `, bid); + return false; + } } return true; } @@ -907,7 +938,7 @@ export const spec = { payload.ext.wrapper = {}; payload.ext.wrapper.profile = parseInt(conf.profId) || UNDEFINED; payload.ext.wrapper.version = parseInt(conf.verId) || UNDEFINED; - payload.ext.wrapper.wiid = conf.wiid || UNDEFINED; + payload.ext.wrapper.wiid = conf.wiid || bidderRequest.auctionId; // eslint-disable-next-line no-undef payload.ext.wrapper.wv = $$REPO_AND_VERSION$$; payload.ext.wrapper.transactionId = conf.transactionId; @@ -921,6 +952,11 @@ export const spec = { payload.site.page = conf.kadpageurl.trim() || payload.site.page.trim(); payload.site.domain = _getDomainFromURL(payload.site.page); + // add the content object from config in request + if (typeof config.getConfig('content') === 'object') { + payload.site.content = config.getConfig('content'); + } + // merge the device from config.getConfig('device') if (typeof config.getConfig('device') === 'object') { payload.device = Object.assign(payload.device, config.getConfig('device')); @@ -966,13 +1002,19 @@ export const spec = { // not copying domain from site as it is a derived value from page payload.app.publisher = payload.site.publisher; payload.app.ext = payload.site.ext || UNDEFINED; + // We will also need to pass content object in app.content if app object is also set into the config; + // BUT do not use content object from config if content object is present in app as app.content + if (typeof payload.app.content !== 'object') { + payload.app.content = payload.site.content || UNDEFINED; + } delete payload.site; } return { method: 'POST', url: ENDPOINT, - data: JSON.stringify(payload) + data: JSON.stringify(payload), + bidderRequest: bidderRequest }; }, @@ -1008,7 +1050,8 @@ export const spec = { referrer: parsedReferrer, ad: bid.adm, pm_seat: seatbidder.seat || null, - pm_dspid: bid.ext && bid.ext.dspid ? bid.ext.dspid : null + pm_dspid: bid.ext && bid.ext.dspid ? bid.ext.dspid : null, + partnerImpId: bid.id || '' // partner impression Id }; if (parsedRequest.imp && parsedRequest.imp.length > 0) { parsedRequest.imp.forEach(req => { @@ -1021,6 +1064,7 @@ export const spec = { newBid.width = bid.hasOwnProperty('w') ? bid.w : req.video.w; newBid.height = bid.hasOwnProperty('h') ? bid.h : req.video.h; newBid.vastXml = bid.adm; + _assignRenderer(newBid, request); break; case NATIVE: _parseNativeResponse(bid, newBid); @@ -1041,6 +1085,7 @@ export const spec = { newBid.meta.buyerId = bid.ext.advid; } if (bid.adomain && bid.adomain.length > 0) { + newBid.meta.advertiserDomains = bid.adomain; newBid.meta.clickUrl = bid.adomain[0]; } diff --git a/modules/pubmaticBidAdapter.md b/modules/pubmaticBidAdapter.md index a045bed3e2b..0ef89a22cbd 100644 --- a/modules/pubmaticBidAdapter.md +++ b/modules/pubmaticBidAdapter.md @@ -24,7 +24,8 @@ var adUnits = [ bids: [{ bidder: 'pubmatic', params: { - publisherId: '156209', // required + publisherId: '156209', // required, must be wrapped in quotes + oustreamAU: 'renderer_test_pubmatic', // required if mediaTypes-> video-> context is 'outstream'. This value can be get by BlueBillyWig Team. adSlot: 'pubmatic_test2', // optional pmzoneid: 'zone1, zone11', // optional lat: '40.712775', // optional diff --git a/modules/pubperfAnalyticsAdapter.js b/modules/pubperfAnalyticsAdapter.js new file mode 100644 index 00000000000..800ea1cd550 --- /dev/null +++ b/modules/pubperfAnalyticsAdapter.js @@ -0,0 +1,36 @@ +/** + * Analytics Adapter for Pubperf + */ + +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; + +var pubperfAdapter = adapter({ + global: 'pubperf_pbjs', + analyticsType: 'bundle', + handler: 'on' +}); + +pubperfAdapter.originEnableAnalytics = pubperfAdapter.enableAnalytics; + +pubperfAdapter.enableAnalytics = config => { + if (!config || !config.provider || config.provider !== 'pubperf') { + utils.logError('expected config.provider to equal pubperf'); + return; + } + if (!window['pubperf_pbjs']) { + utils.logError( + `Make sure that Pubperf tag from https://www.pubperf.com is included before the Prebid configuration.` + ); + return; + } + pubperfAdapter.originEnableAnalytics(config); +} + +adapterManager.registerAnalyticsAdapter({ + adapter: pubperfAdapter, + code: 'pubperf' +}); + +export default pubperfAdapter; diff --git a/modules/pubperfAnalyticsAdapter.md b/modules/pubperfAnalyticsAdapter.md new file mode 100644 index 00000000000..50ac3691dda --- /dev/null +++ b/modules/pubperfAnalyticsAdapter.md @@ -0,0 +1,27 @@ +# Overview + +``` +Module Name: Pubperf Analytics Adapter +Module Type: Analytics Adapter +Maintainer: support@transfon.com +``` + +# Description + +Transfon's pubperf analytics adaptor allows you to view detailed auction and prebid information in Meridian. Contact support@transfon.com for more information or to sign up for analytics. + +For more information, please visit https://www.pubperf.com. + + +# Sample pubperf tag to be placed before prebid tag + +``` +(function(i, s, o, g, r, a, m, z) {i['pubperf_pbjs'] = r;i[r] = i[r] || function() {z = Array.prototype.slice.call(arguments);z.unshift(+new Date());(i[r].q = i[r].q || []).push(z)}, i[r].t = 1, i[r].l = 1 * new Date();a = s.createElement(o),m = s.getElementsByTagName(o)[0];a.async = 1;a.src = g;m.parentNode.insertBefore(a, m)})(window, document, 'script', 'https://t.pubperf.com/t/b5a635e307.js', 'pubperf_pbjs'); +``` + +# Test Parameters +``` +{ + provider: 'pubperf' +} +``` diff --git a/modules/pubwiseAnalyticsAdapter.js b/modules/pubwiseAnalyticsAdapter.js index 915aeb58f99..fe217454b88 100644 --- a/modules/pubwiseAnalyticsAdapter.js +++ b/modules/pubwiseAnalyticsAdapter.js @@ -4,7 +4,6 @@ import adapterManager from '../src/adapterManager.js'; import CONSTANTS from '../src/constants.json'; import { getStorageManager } from '../src/storageManager.js'; const utils = require('../src/utils.js'); - const storage = getStorageManager(); /**** @@ -17,30 +16,54 @@ const storage = getStorageManager(); pbjs.enableAnalytics({ provider: 'pubwise', options: { - site: 'test-test-test-test', - endpoint: 'https://api.pubwise.io/api/v4/event/add/', + site: 'b1ccf317-a6fc-428d-ba69-0c9c208aa61c' } }); - */ + +Changes in 4.0 Version +4.0.1 - Initial Version for Prebid 4.x, adds activationId, adds additiona testing, removes prebid global in favor of a prebid.version const +4.0.2 - Updates to include dedicated default site to keep everything from getting rate limited + +*/ const analyticsType = 'endpoint'; -const analyticsName = 'PubWise Analytics: '; -let defaultUrl = 'https://api.pubwise.io/api/v4/event/default/'; -let pubwiseVersion = '3.0'; -let pubwiseSchema = 'AVOCET'; -let configOptions = {site: '', endpoint: 'https://api.pubwise.io/api/v4/event/default/', debug: ''}; +const analyticsName = 'PubWise:'; +const prebidVersion = '$prebid.version$'; +let pubwiseVersion = '4.0.1'; +let configOptions = {site: '', endpoint: 'https://api.pubwise.io/api/v5/event/add/', debug: null}; let pwAnalyticsEnabled = false; let utmKeys = {utm_source: '', utm_medium: '', utm_campaign: '', utm_term: '', utm_content: ''}; +let sessionData = {sessionId: '', activationId: ''}; +let pwNamespace = 'pubwise'; +let pwEvents = []; +let metaData = {}; +let auctionEnded = false; +let sessTimeout = 60 * 30 * 1000; // 30 minutes, G Analytics default session length +let sessName = 'sess_id'; +let sessTimeoutName = 'sess_timeout'; -function markEnabled() { - utils.logInfo(`${analyticsName}Enabled`, configOptions); - pwAnalyticsEnabled = true; +function enrichWithSessionInfo(dataBag) { + try { + // eslint-disable-next-line + // console.log(sessionData); + dataBag['session_id'] = sessionData.sessionId; + dataBag['activation_id'] = sessionData.activationId; + } catch (e) { + dataBag['error_sess'] = 1; + } + + return dataBag; } function enrichWithMetrics(dataBag) { try { + if (window.PREBID_TIMEOUT) { + dataBag['target_timeout'] = window.PREBID_TIMEOUT; + } else { + dataBag['target_timeout'] = 'NA'; + } dataBag['pw_version'] = pubwiseVersion; - dataBag['pbjs_version'] = $$PREBID_GLOBAL$$.version; + dataBag['pbjs_version'] = prebidVersion; dataBag['debug'] = configOptions.debug; } catch (e) { dataBag['error_metric'] = 1; @@ -54,7 +77,7 @@ function enrichWithUTM(dataBag) { try { for (let prop in utmKeys) { utmKeys[prop] = utils.getParameterByName(prop); - if (utmKeys[prop] != '') { + if (utmKeys[prop]) { newUtm = true; dataBag[prop] = utmKeys[prop]; } @@ -62,70 +85,253 @@ function enrichWithUTM(dataBag) { if (newUtm === false) { for (let prop in utmKeys) { - let itemValue = storage.getDataFromLocalStorage(`pw-${prop}`); - if (itemValue.length !== 0) { + let itemValue = storage.getDataFromLocalStorage(setNamespace(prop)); + if (itemValue !== null && typeof itemValue !== 'undefined' && itemValue.length !== 0) { dataBag[prop] = itemValue; } } } else { for (let prop in utmKeys) { - storage.setDataInLocalStorage(`pw-${prop}`, utmKeys[prop]); + storage.setDataInLocalStorage(setNamespace(prop), utmKeys[prop]); } } } catch (e) { - utils.logInfo(`${analyticsName}Error`, e); + pwInfo(`Error`, e); dataBag['error_utm'] = 1; } return dataBag; } -function sendEvent(eventType, data) { - utils.logInfo(`${analyticsName}Event ${eventType} ${pwAnalyticsEnabled}`, data); +function expireUtmData() { + pwInfo(`Session Expiring UTM Data`); + for (let prop in utmKeys) { + storage.removeDataFromLocalStorage(setNamespace(prop)); + } +} + +function enrichWithCustomSegments(dataBag) { + // c_script_type: '', c_slot1: '', c_slot2: '', c_slot3: '', c_slot4: '' + if (configOptions.custom) { + if (configOptions.custom.c_script_type) { + dataBag['c_script_type'] = configOptions.custom.c_script_type; + } + + if (configOptions.custom.c_host) { + dataBag['c_host'] = configOptions.custom.c_host; + } + + if (configOptions.custom.c_slot1) { + dataBag['c_slot1'] = configOptions.custom.c_slot1; + } + + if (configOptions.custom.c_slot2) { + dataBag['c_slot2'] = configOptions.custom.c_slot2; + } + + if (configOptions.custom.c_slot3) { + dataBag['c_slot3'] = configOptions.custom.c_slot3; + } + + if (configOptions.custom.c_slot4) { + dataBag['c_slot4'] = configOptions.custom.c_slot4; + } + } + + return dataBag; +} + +function setNamespace(itemText) { + return pwNamespace.concat('_' + itemText); +} + +function localStorageSessTimeoutName() { + return setNamespace(sessTimeoutName); +} + +function localStorageSessName() { + return setNamespace(sessName); +} + +function extendUserSessionTimeout() { + storage.setDataInLocalStorage(localStorageSessTimeoutName(), Date.now().toString()); +} + +function userSessionID() { + return storage.getDataFromLocalStorage(localStorageSessName()) ? localStorage.getItem(localStorageSessName()) : ''; +} + +function sessionExpired() { + let sessLastTime = storage.getDataFromLocalStorage(localStorageSessTimeoutName()); + return (Date.now() - parseInt(sessLastTime)) > sessTimeout; +} + +function flushEvents() { + if (pwEvents.length > 0) { + let dataBag = {metaData: metaData, eventList: pwEvents.splice(0)}; // put all the events together with the metadata and send + ajax(configOptions.endpoint, (result) => pwInfo(`Result`, result), JSON.stringify(dataBag)); + } +} + +function isIngestedEvent(eventType) { + const ingested = [ + CONSTANTS.EVENTS.AUCTION_INIT, + CONSTANTS.EVENTS.BID_REQUESTED, + CONSTANTS.EVENTS.BID_RESPONSE, + CONSTANTS.EVENTS.BID_WON, + CONSTANTS.EVENTS.BID_TIMEOUT, + CONSTANTS.EVENTS.AD_RENDER_FAILED, + CONSTANTS.EVENTS.TCF2_ENFORCEMENT + ]; + return ingested.indexOf(eventType) !== -1; +} - // put the typical items in the data bag - let dataBag = { - eventType: eventType, - args: data, - target_site: configOptions.site, - pubwiseSchema: pubwiseSchema, - debug: configOptions.debug ? 1 : 0, - }; +function markEnabled() { + pwInfo(`Enabled`, configOptions); + pwAnalyticsEnabled = true; + setInterval(flushEvents, 100); +} + +function pwInfo(info, context) { + utils.logInfo(`${analyticsName} ` + info, context); +} - dataBag = enrichWithMetrics(dataBag); - // for certain events, track additional info - if (eventType == CONSTANTS.EVENTS.AUCTION_INIT) { - dataBag = enrichWithUTM(dataBag); +function filterBidResponse(data) { + let modified = Object.assign({}, data); + // clean up some properties we don't track in public version + if (typeof modified.ad !== 'undefined') { + modified.ad = ''; } + if (typeof modified.adUrl !== 'undefined') { + modified.adUrl = ''; + } + if (typeof modified.adserverTargeting !== 'undefined') { + modified.adserverTargeting = ''; + } + if (typeof modified.ts !== 'undefined') { + modified.ts = ''; + } + // clean up a property to make simpler + if (typeof modified.statusMessage !== 'undefined' && modified.statusMessage === 'Bid returned empty or error response') { + modified.statusMessage = 'eoe'; + } + modified.auctionEnded = auctionEnded; + return modified; +} - ajax(configOptions.endpoint, (result) => utils.logInfo(`${analyticsName}Result`, result), JSON.stringify(dataBag)); +function filterAuctionInit(data) { + let modified = Object.assign({}, data); + + modified.refererInfo = {}; + // handle clean referrer, we only need one + if (typeof modified.bidderRequests !== 'undefined' && typeof modified.bidderRequests[0] !== 'undefined' && typeof modified.bidderRequests[0].refererInfo !== 'undefined') { + modified.refererInfo = modified.bidderRequests[0].refererInfo; + } + + if (typeof modified.adUnitCodes !== 'undefined') { + delete modified.adUnitCodes; + } + if (typeof modified.adUnits !== 'undefined') { + delete modified.adUnits; + } + if (typeof modified.bidderRequests !== 'undefined') { + delete modified.bidderRequests; + } + if (typeof modified.bidsReceived !== 'undefined') { + delete modified.bidsReceived; + } + if (typeof modified.config !== 'undefined') { + delete modified.config; + } + if (typeof modified.noBids !== 'undefined') { + delete modified.noBids; + } + if (typeof modified.winningBids !== 'undefined') { + delete modified.winningBids; + } + + return modified; } -let pubwiseAnalytics = Object.assign(adapter( - { - defaultUrl, - analyticsType - }), -{ +let pubwiseAnalytics = Object.assign(adapter({analyticsType}), { // Override AnalyticsAdapter functions by supplying custom methods track({eventType, args}) { - sendEvent(eventType, args); + this.handleEvent(eventType, args); } }); +pubwiseAnalytics.handleEvent = function(eventType, data) { + // we log most events, but some are information + if (isIngestedEvent(eventType)) { + pwInfo(`Emitting Event ${eventType} ${pwAnalyticsEnabled}`, data); + + // record metadata + metaData = { + target_site: configOptions.site, + debug: configOptions.debug ? 1 : 0, + }; + metaData = enrichWithSessionInfo(metaData); + metaData = enrichWithMetrics(metaData); + metaData = enrichWithUTM(metaData); + metaData = enrichWithCustomSegments(metaData); + + // add data on init to the metadata container + if (eventType === CONSTANTS.EVENTS.AUCTION_INIT) { + data = filterAuctionInit(data); + } else if (eventType === CONSTANTS.EVENTS.BID_RESPONSE) { + data = filterBidResponse(data); + } + + // add all ingested events + pwEvents.push({ + eventType: eventType, + args: data + }); + } else { + pwInfo(`Skipping Event ${eventType} ${pwAnalyticsEnabled}`, data); + } + + // once the auction ends, or the event is a bid won send events + if (eventType === CONSTANTS.EVENTS.AUCTION_END || eventType === CONSTANTS.EVENTS.BID_WON) { + flushEvents(); + } +} + +pubwiseAnalytics.storeSessionID = function (userSessID) { + storage.setDataInLocalStorage(localStorageSessName(), userSessID); + pwInfo(`New Session Generated`, userSessID); +}; + +// ensure a session exists, if not make one, always store it +pubwiseAnalytics.ensureSession = function () { + if (sessionExpired() === true || userSessionID() === null || userSessionID() === '') { + let generatedId = utils.generateUUID(); + expireUtmData(); + this.storeSessionID(generatedId); + sessionData.sessionId = generatedId; + } + // eslint-disable-next-line + // console.log('ensured session'); + extendUserSessionTimeout(); +}; + pubwiseAnalytics.adapterEnableAnalytics = pubwiseAnalytics.enableAnalytics; pubwiseAnalytics.enableAnalytics = function (config) { - if (config.options.debug === undefined) { - config.options.debug = utils.debugTurnedOn(); + configOptions = Object.assign(configOptions, config.options); + // take the PBJS debug for our debug setting if no PW debug is defined + if (configOptions.debug === null) { + configOptions.debug = utils.debugTurnedOn(); } - configOptions = config.options; markEnabled(); + sessionData.activationId = utils.generateUUID(); + this.ensureSession(); pubwiseAnalytics.adapterEnableAnalytics(config); }; adapterManager.registerAnalyticsAdapter({ adapter: pubwiseAnalytics, - code: 'pubwise' + code: 'pubwise', + gvlid: 842 }); export default pubwiseAnalytics; diff --git a/modules/pubxBidAdapter.js b/modules/pubxBidAdapter.js new file mode 100644 index 00000000000..44c95e8e19a --- /dev/null +++ b/modules/pubxBidAdapter.js @@ -0,0 +1,47 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +const BIDDER_CODE = 'pubx'; +const BID_ENDPOINT = 'https://api.primecaster.net/adlogue/api/slot/bid'; +export const spec = { + code: BIDDER_CODE, + isBidRequestValid: function(bid) { + if (!(bid.params.sid)) { + return false; + } else { return true } + }, + buildRequests: function(validBidRequests) { + return validBidRequests.map(bidRequest => { + const bidId = bidRequest.bidId; + const params = bidRequest.params; + const sid = params.sid; + const payload = { + sid: sid + }; + return { + id: bidId, + method: 'GET', + url: BID_ENDPOINT, + data: payload, + } + }); + }, + interpretResponse: function(serverResponse, bidRequest) { + const body = serverResponse.body; + const bidResponses = []; + if (body.cid) { + const bidResponse = { + requestId: bidRequest.id, + cpm: body.cpm, + currency: body.currency, + width: body.width, + height: body.height, + creativeId: body.cid, + netRevenue: true, + ttl: body.TTL, + ad: body.adm + }; + bidResponses.push(bidResponse); + } else {}; + return bidResponses; + } +} +registerBidder(spec); diff --git a/modules/pubxBidAdapter.md b/modules/pubxBidAdapter.md new file mode 100644 index 00000000000..da7d960c831 --- /dev/null +++ b/modules/pubxBidAdapter.md @@ -0,0 +1,32 @@ +# Overview + +Module Name: pubx Bid Adapter + +Maintainer: x@pub-x.io + +# Description + +Module that connects to Pub-X's demand sources +Supported MediaTypes: banner only + +# Test Parameters +```javascript + var adUnits = [ + { + code: 'test', + mediaTypes: { + banner: { + sizes: [300,250] + } + }, + bids: [ + { + bidder: 'pubx', + params: { + sid: 'eDMR' //ID should be provided by Pub-X + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/modules/pulsepointBidAdapter.js b/modules/pulsepointBidAdapter.js index 7bfa8686728..12937dbec9d 100644 --- a/modules/pulsepointBidAdapter.js +++ b/modules/pulsepointBidAdapter.js @@ -420,8 +420,8 @@ function user(bidRequest, bidderRequest) { addExternalUserId(ext.eids, bidRequest.userId.britepoolid, 'britepool.com'); addExternalUserId(ext.eids, bidRequest.userId.criteoId, 'criteo'); addExternalUserId(ext.eids, bidRequest.userId.idl_env, 'identityLink'); - addExternalUserId(ext.eids, bidRequest.userId.id5id, 'id5-sync.com'); - addExternalUserId(ext.eids, bidRequest.userId.parrableid, 'parrable.com'); + addExternalUserId(ext.eids, utils.deepAccess(bidRequest, 'userId.id5id.uid'), 'id5-sync.com', utils.deepAccess(bidRequest, 'userId.id5id.ext')); + addExternalUserId(ext.eids, utils.deepAccess(bidRequest, 'userId.parrableId.eid'), 'parrable.com'); // liveintent if (bidRequest.userId.lipb && bidRequest.userId.lipb.lipbid) { addExternalUserId(ext.eids, bidRequest.userId.lipb.lipbid, 'liveintent.com'); diff --git a/modules/quantcastBidAdapter.js b/modules/quantcastBidAdapter.js index 91022d70df9..894bb991a71 100644 --- a/modules/quantcastBidAdapter.js +++ b/modules/quantcastBidAdapter.js @@ -85,11 +85,6 @@ function checkTCFv1(vendorData) { } function checkTCFv2(tcData) { - if (tcData.purposeOneTreatment && tcData.publisherCC === 'DE') { - // special purpose 1 treatment for Germany - return true; - } - let restrictions = tcData.publisher ? tcData.publisher.restrictions : {}; let qcRestriction = restrictions && restrictions[PURPOSE_DATA_COLLECT] ? restrictions[PURPOSE_DATA_COLLECT][QUANTCAST_VENDOR_ID] diff --git a/modules/quantcastIdSystem.js b/modules/quantcastIdSystem.js new file mode 100644 index 00000000000..e86c130dc5b --- /dev/null +++ b/modules/quantcastIdSystem.js @@ -0,0 +1,44 @@ +/** + * This module adds QuantcastID to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/quantcastIdSystem + * @requires module:modules/userId + */ + +import {submodule} from '../src/hook.js' +import { getStorageManager } from '../src/storageManager.js'; + +const QUANTCAST_FPA = '__qca'; + +export const storage = getStorageManager(); + +/** @type {Submodule} */ +export const quantcastIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: 'quantcastId', + + /** + * decode the stored id value for passing to bid requests + * @function + * @returns {{quantcastId: string} | undefined} + */ + decode(value) { + return value; + }, + + /** + * read Quantcast first party cookie and pass it along in quantcastId + * @function + * @returns {{id: {quantcastId: string} | undefined}}} + */ + getId() { + // Consent signals are currently checked on the server side. + let fpa = storage.getCookie(QUANTCAST_FPA); + return { id: fpa ? { quantcastId: fpa } : undefined } + } +}; + +submodule('userId', quantcastIdSubmodule); diff --git a/modules/quantumBidAdapter.js b/modules/quantumBidAdapter.js deleted file mode 100644 index f5da6e022f1..00000000000 --- a/modules/quantumBidAdapter.js +++ /dev/null @@ -1,320 +0,0 @@ -import * as utils from '../src/utils.js'; -import { BANNER, NATIVE } from '../src/mediaTypes.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; - -const BIDDER_CODE = 'quantum'; -const ENDPOINT_URL = 'https://s.sspqns.com/hb'; -export const spec = { - code: BIDDER_CODE, - aliases: ['quantx', 'qtx'], // short code - supportedMediaTypes: [BANNER, NATIVE], - - /** - * 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.placementId); - }, - /** - * 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) { - return bidRequests.map(bid => { - const qtxRequest = {}; - let bidId = ''; - - const params = bid.params; - let placementId = params.placementId; - - let devEnpoint = false; - if (params.useDev && params.useDev === '1') { - devEnpoint = 'https://sdev.sspqns.com/hb'; - } - let renderMode = 'native'; - for (let i = 0; i < bid.sizes.length; i++) { - if (bid.sizes[i][0] > 1 && bid.sizes[i][1] > 1) { - renderMode = 'banner'; - break; - } - } - - let mediaType = (bid.mediaType === 'native' || utils.deepAccess(bid, 'mediaTypes.native')) ? 'native' : 'banner'; - - if (mediaType === 'native') { - renderMode = 'native'; - } - - if (!bidId) { - bidId = bid.bidId; - } - qtxRequest.auid = placementId; - - if (bidderRequest && bidderRequest.gdprConsent) { - qtxRequest.quantx_user_consent_string = bidderRequest.gdprConsent.consentString; - qtxRequest.quantx_gdpr = bidderRequest.gdprConsent.gdprApplies === true ? 1 : 0; - }; - - const url = devEnpoint || ENDPOINT_URL; - - return { - method: 'GET', - bidId: bidId, - sizes: bid.sizes, - mediaType: mediaType, - renderMode: renderMode, - url: url, - 'data': qtxRequest, - bidderRequest - }; - }); - }, - /** - * 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, bidRequest) { - const serverBody = serverResponse.body; - const bidResponses = []; - let responseCPM; - let bid = {}; - let id = bidRequest.bidId; - - if (serverBody.price && serverBody.price !== 0) { - responseCPM = parseFloat(serverBody.price); - - bid.creativeId = serverBody.creative_id || '0'; - bid.cpm = responseCPM; - bid.requestId = bidRequest.bidId; - bid.width = 1; - bid.height = 1; - bid.ttl = 200; - bid.netRevenue = true; - bid.currency = 'USD'; - - if (serverBody.native) { - bid.native = serverBody.native; - } - if (serverBody.cobj) { - bid.cobj = serverBody.cobj; - } - if (!utils.isEmpty(bidRequest.sizes)) { - bid.width = bidRequest.sizes[0][0]; - bid.height = bidRequest.sizes[0][1]; - } - - bid.nurl = serverBody.nurl; - bid.sync = serverBody.sync; - if (bidRequest.renderMode && bidRequest.renderMode === 'banner') { - bid.mediaType = 'banner'; - if (serverBody.native) { - const adAssetsUrl = 'https://cdn.elasticad.net/native/serve/js/quantx/quantumAd/'; - let assets = serverBody.native.assets; - let link = serverBody.native.link; - - let trackers = []; - if (serverBody.native.imptrackers) { - trackers = serverBody.native.imptrackers; - } - - let jstracker = ''; - if (serverBody.native.jstracker) { - jstracker = encodeURIComponent(serverBody.native.jstracker); - } - - if (serverBody.nurl) { - trackers.push(serverBody.nurl); - } - - let ad = {}; - ad['trackers'] = trackers; - ad['jstrackers'] = jstracker; - ad['eventtrackers'] = serverBody.native.eventtrackers || []; - - for (let i = 0; i < assets.length; i++) { - let asset = assets[i]; - switch (asset['id']) { - case 1: - ad['title'] = asset['title']['text']; - break; - case 2: - ad['sponsor_logo'] = asset['img']['url']; - break; - case 3: - ad['content'] = asset['data']['value']; - break; - case 4: - ad['main_image'] = asset['img']['url']; - break; - case 6: - ad['teaser_type'] = 'vast'; - ad['video_url'] = asset['video']['vasttag']; - break; - case 10: - ad['sponsor_name'] = asset['data']['value']; - break; - case 2001: - ad['expanded_content_type'] = 'embed'; - ad['expanded_summary'] = asset['data']['value']; - break; - case 2002: - ad['expanded_content_type'] = 'vast'; - ad['expanded_summary'] = asset['data']['value']; - break; - case 2003: - ad['sponsor_url'] = asset['data']['value']; - break; - case 2004: // prism - ad['content_type'] = 'prism'; - break; - case 2005: // internal_landing_page - ad['content_type'] = 'internal_landing_page'; - ad['internal_content_link'] = asset['data']['value']; - break; - case 2006: // teaser as vast - ad['teaser_type'] = 'vast'; - ad['video_url'] = asset['data']['value']; - break; - case 2007: - ad['autoexpand_content_type'] = asset['data']['value']; - break; - case 2022: // content page - ad['content_type'] = 'full_text'; - ad['full_text'] = asset['data']['value']; - break; - } - } - - ad['action_url'] = link.url; - - if (!ad['sponsor_url']) { - ad['sponsor_url'] = ad['action_url']; - } - - ad['clicktrackers'] = []; - if (link.clicktrackers) { - ad['clicktrackers'] = link.clicktrackers; - } - - ad['main_image'] = 'https://resize-ssp.adux.com/scalecrop-290x130/' + window.btoa(ad['main_image']) + '/external'; - - bid.ad = '
' + - '
' + - '
' + - ' ' + - ' ' + - '
' + - '

' + ad['title'] + '

' + - '

' + ad['content'] + ' 

' + - ' ' + - '
' + - '' + - '' + - '' + - '
'; - } - } else { - // native - bid.mediaType = 'native'; - if (bidRequest.mediaType === 'native') { - if (serverBody.native) { - let assets = serverBody.native.assets; - let link = serverBody.native.link; - - let trackers = []; - if (serverBody.native.imptrackers) { - trackers = serverBody.native.imptrackers; - } - - if (serverBody.nurl) { - trackers.push(serverBody.nurl); - } - - let native = {}; - - for (let i = 0; i < assets.length; i++) { - let asset = assets[i]; - switch (asset['id']) { - case 1: - native.title = asset['title']['text']; - break; - case 2: - native.icon = { - url: asset['img']['url'], - width: asset['img']['w'], - height: asset['img']['h'] - }; - break; - case 3: - native.body = asset['data']['value']; - break; - case 4: - native.image = { - url: asset['img']['url'], - width: asset['img']['w'], - height: asset['img']['h'] - }; - break; - case 10: - native.sponsoredBy = asset['data']['value']; - break; - } - } - native.cta = 'read more'; - if (serverBody.language) { - native.cta = 'read more'; - } - - native.clickUrl = link.url; - native.impressionTrackers = trackers; - if (link.clicktrackers) { - native.clickTrackers = link.clicktrackers; - } - native.eventtrackers = native.eventtrackers || []; - - bid.qtx_native = utils.deepClone(serverBody.native); - bid.native = native; - } - } - } - bidResponses.push(bid); - } - - return bidResponses; - }, - - /** - * Register the user sync pixels which should be dropped after the auction. - * - * @param {SyncOptions} syncOptions Which user syncs are allowed? - * @param {ServerResponse} serverResponse A successful response from the server - * @return {UserSync[]} The user syncs which should be dropped. - */ - getUserSyncs: function (syncOptions, serverResponse) { - const syncs = []; - utils._each(serverResponse, function(serverResponse) { - if (serverResponse.body && serverResponse.body.sync) { - utils._each(serverResponse.body.sync, function (pixel) { - syncs.push({ - type: 'image', - url: pixel - }); - }); - } - }); - return syncs; - } -} -registerBidder(spec); diff --git a/modules/quantumBidAdapter.md b/modules/quantumBidAdapter.md deleted file mode 100644 index 572ca9ecd37..00000000000 --- a/modules/quantumBidAdapter.md +++ /dev/null @@ -1,94 +0,0 @@ -# Overview - -``` -Module Name: Quantum Advertising Bid Adapter -Module Type: Bidder Adapter -Maintainer: support.mediareporting@adux.com -``` - -# Description - -Connects to Quantum's ssp for bids. - -# Sample Ad Unit: For Publishers -``` -var adUnits = [{ - code: 'quantum-adUnit-id-1', - sizes: [[300, 250]], - bids: [{ - bidder: 'quantum', - params: { - placementId: 21546 //quantum adUnit id - } - }] - },{ - code: 'quantum-native-adUnit-id-1', - sizes: [[0, 0]], - mediaTypes: 'native', - bids: [{ - bidder: 'quantum', - params: { - placementId: 21546 //quantum adUnit id - } - }] - }]; -``` - -# Ad Unit and Setup: For Testing - -``` - - - - - - - - - - ``` diff --git a/modules/quantumdexBidAdapter.js b/modules/quantumdexBidAdapter.js index c2a130f789d..738b6165f79 100644 --- a/modules/quantumdexBidAdapter.js +++ b/modules/quantumdexBidAdapter.js @@ -1,15 +1,25 @@ import * as utils from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'quantumdex'; -const ENDPOINT = 'https://useast.quantumdex.io/auction/adapter'; -const USER_SYNC_URL = 'https://useast.quantumdex.io/usersync/adapter'; +const CONFIG = { + 'quantumdex': { + 'ENDPOINT': 'https://useast.quantumdex.io/auction/quantumdex', + 'USERSYNC': 'https://sync.quantumdex.io/usersync/quantumdex' + }, + 'valueimpression': { + 'ENDPOINT': 'https://useast.quantumdex.io/auction/adapter', + 'USERSYNC': 'https://sync.quantumdex.io/usersync/adapter' + } +}; + +var bidderConfig = CONFIG['quantumdex']; var bySlotTargetKey = {}; var bySlotSizesCount = {} export const spec = { code: BIDDER_CODE, supportedMediaTypes: ['banner', 'video'], - aliases: ['qde'], + aliases: ['valueimpression'], isBidRequestValid: function (bid) { if (!bid.params) { return false; @@ -36,6 +46,7 @@ export const spec = { buildRequests: function (validBidRequests, bidderRequest) { var bids = JSON.parse(JSON.stringify(validBidRequests)) + bidderConfig = CONFIG[bids[0].bidder]; const payload = {}; bids.forEach(bidReq => { @@ -74,14 +85,14 @@ export const spec = { // Apply GDPR parameters to request. payload.gdpr = {}; if (bidderRequest && bidderRequest.gdprConsent) { - payload.gdpr.gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 'true' : 'false'; + payload.gdpr.gdprApplies = !!bidderRequest.gdprConsent.gdprApplies; if (bidderRequest.gdprConsent.consentString) { payload.gdpr.consentString = bidderRequest.gdprConsent.consentString; } } // Apply schain. if (bids[0].schain) { - payload.schain = JSON.stringify(bids[0].schain) + payload.schain = bids[0].schain } // Apply us_privacy. if (bidderRequest && bidderRequest.uspConsent) { @@ -92,7 +103,7 @@ export const spec = { return { method: 'POST', - url: ENDPOINT, + url: bidderConfig.ENDPOINT, data: payload, withCredentials: true, bidderRequests: bids @@ -138,15 +149,23 @@ export const spec = { if (syncOptions.iframeEnabled) { syncs.push({ type: 'iframe', - url: USER_SYNC_URL + url: bidderConfig.USERSYNC }); } - if (syncOptions.pixelEnabled && serverResponses.length > 0) { + if (serverResponses.length > 0 && serverResponses[0].body && serverResponses[0].body.pixel) { serverResponses[0].body.pixel.forEach(px => { - syncs.push({ - type: px.type, - url: px.url - }); + if (px.type === 'image' && syncOptions.pixelEnabled) { + syncs.push({ + type: 'image', + url: px.url + }); + } + if (px.type === 'iframe' && syncOptions.iframeEnabled) { + syncs.push({ + type: 'iframe', + url: px.url + }); + } }); } } catch (e) { } diff --git a/modules/qwarryBidAdapter.js b/modules/qwarryBidAdapter.js new file mode 100644 index 00000000000..36c1562324a --- /dev/null +++ b/modules/qwarryBidAdapter.js @@ -0,0 +1,75 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { deepClone } from '../src/utils.js'; +import { ajax } from '../src/ajax.js'; +import { VIDEO } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'qwarry'; +export const ENDPOINT = 'https://ui-bidder.kantics.co/bid/adtag?prebid=true' + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: ['banner', 'video'], + + isBidRequestValid: function (bid) { + return !!(bid.params && bid.params.zoneToken); + }, + + buildRequests: function (validBidRequests, bidderRequest) { + let bids = []; + validBidRequests.forEach(bidRequest => { + bids.push({ + bidId: bidRequest.bidId, + zoneToken: bidRequest.params.zoneToken + }) + }) + + return { + method: 'POST', + url: ENDPOINT, + data: { requestId: bidderRequest.bidderRequestId, bids }, + options: { + contentType: 'application/json', + customHeaders: { + 'Rtb-Direct': true + } + } + }; + }, + + interpretResponse: function (serverResponse, request) { + const serverBody = serverResponse.body; + if (!serverBody || typeof serverBody !== 'object') { + return []; + } + + const { prebidResponse } = serverBody; + if (!prebidResponse || typeof prebidResponse !== 'object') { + return []; + } + + let bids = []; + prebidResponse.forEach(bidResponse => { + let bid = deepClone(bidResponse); + bid.cpm = parseFloat(bidResponse.cpm); + + // banner or video + if (VIDEO === bid.format) { + bid.vastXml = bid.ad; + } + + bids.push(bid); + }) + + return bids; + }, + + onBidWon: function (bid) { + if (bid.winUrl) { + ajax(bid.winUrl, null); + return true; + } + return false; + } +} + +registerBidder(spec); diff --git a/modules/qwarryBidAdapter.md b/modules/qwarryBidAdapter.md new file mode 100644 index 00000000000..056ccb51293 --- /dev/null +++ b/modules/qwarryBidAdapter.md @@ -0,0 +1,28 @@ +# Overview + +``` +Module Name: Qwarry Bidder Adapter +Module Type: Bidder Adapter +Maintainer: akascheev@asteriosoft.com +``` + +# Description + +Connects to Qwarry Bidder for bids. +Qwarry bid adapter supports Banner and Video ads. + +# Test Parameters +``` +const adUnits = [ + { + bids: [ + { + bidder: 'qwarry', + params: { + zoneToken: '?????????????????????', // zoneToken provided by Qwarry + } + } + ] + } +]; +``` diff --git a/modules/relaidoBidAdapter.js b/modules/relaidoBidAdapter.js index 22551877a93..b3b8a647137 100644 --- a/modules/relaidoBidAdapter.js +++ b/modules/relaidoBidAdapter.js @@ -6,7 +6,7 @@ import { getStorageManager } from '../src/storageManager.js'; const BIDDER_CODE = 'relaido'; const BIDDER_DOMAIN = 'api.relaido.jp'; -const ADAPTER_VERSION = '1.0.0'; +const ADAPTER_VERSION = '1.0.1'; const DEFAULT_TTL = 300; const UUID_KEY = 'relaido_uuid'; @@ -45,13 +45,12 @@ function buildRequests(validBidRequests, bidderRequest) { const bidRequest = validBidRequests[i]; const placementId = utils.getBidIdParameter('placementId', bidRequest.params); const bidDomain = bidRequest.params.domain || BIDDER_DOMAIN; - const bidUrl = `https://${bidDomain}/vast/v1/out/bid/${placementId}`; + const bidUrl = `https://${bidDomain}/bid/v1/prebid/${placementId}`; const uuid = getUuid(); const mediaType = getMediaType(bidRequest); let payload = { version: ADAPTER_VERSION, - ref: bidderRequest.refererInfo.referer, timeout_ms: bidderRequest.timeout, ad_unit_code: bidRequest.adUnitCode, auction_id: bidRequest.auctionId, @@ -74,6 +73,9 @@ function buildRequests(validBidRequests, bidderRequest) { payload.height = sizes[0][1]; } + // It may not be encoded, so add it at the end of the payload + payload.ref = bidderRequest.refererInfo.referer; + bidRequests.push({ method: 'GET', url: bidUrl, diff --git a/modules/revcontentBidAdapter.js b/modules/revcontentBidAdapter.js index 270302fd617..b429f94eae0 100644 --- a/modules/revcontentBidAdapter.js +++ b/modules/revcontentBidAdapter.js @@ -3,7 +3,6 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import * as utils from '../src/utils.js'; -import {ajax} from '../src/ajax.js'; const BIDDER_CODE = 'revcontent'; const NATIVE_PARAMS = { @@ -223,13 +222,7 @@ export const spec = { return bidResponses; }, onBidWon: function (bid) { - var winUrl = bid.nurl; - winUrl = winUrl.replace(/\$\{AUCTION_PRICE\}/, bid.cpm); - var host = extractHostname(winUrl); - - ajax(winUrl + '&viewed=1', null, {withCredentials: true}); - ajax('https://' + host + '/imp.php', null, 'v=' + encodeURIComponent(encodeURIComponent(getQueryVariable('d', winUrl))) + '&i=' + encodeURIComponent(window.location.href), {method: 'POST', contentType: 'application/x-www-form-urlencoded'}); - + utils.triggerPixel(bid.nurl); return true; } }; @@ -280,14 +273,3 @@ function extractHostname(url) { return hostname; } - -function getQueryVariable(variable, url) { - var query = url; - var vars = query.split('&'); - for (var i = 0; i < vars.length; i++) { - var pair = vars[i].split('='); - if (decodeURIComponent(pair[0]) == variable) { - return decodeURIComponent(pair[1]); - } - } -} diff --git a/modules/richaudienceBidAdapter.js b/modules/richaudienceBidAdapter.js index 22db9709c7c..3b899e2179d 100755 --- a/modules/richaudienceBidAdapter.js +++ b/modules/richaudienceBidAdapter.js @@ -2,6 +2,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import * as utils from '../src/utils.js'; +import { Renderer } from '../src/Renderer.js'; const BIDDER_CODE = 'richaudience'; let REFERER = ''; @@ -46,7 +47,7 @@ export const spec = { transactionId: bid.transactionId, timeout: config.getConfig('bidderTimeout'), user: raiSetEids(bid), - demand: raiGetDemandType(bid) ? 'video' : 'display', + demand: raiGetDemandType(bid), videoData: raiGetVideoInfo(bid) }; @@ -97,8 +98,18 @@ export const spec = { if (response.media_type === 'video') { bidResponse.vastXml = response.vastXML; + try { + if (JSON.parse(bidRequest.data).videoData.format == 'outstream') { + bidResponse.renderer = Renderer.install({ + url: 'https://cdn3.richaudience.com/prebidVideo/player.js' + }); + bidResponse.renderer.setRender(renderer); + } + } catch (e) { + bidResponse.ad = response.adm; + } } else { - bidResponse.ad = response.adm + bidResponse.ad = response.adm; } bidResponses.push(bidResponse); @@ -121,7 +132,7 @@ export const spec = { var consent = ''; if (gdprConsent && typeof gdprConsent.consentString === 'string' && typeof gdprConsent.consentString != 'undefined') { - consent = `pubconsent='${gdprConsent.consentString}'&euconsent='${gdprConsent.consentString}'` + consent = `consentString=${gdprConsent.consentString}` } if (syncOptions.iframeEnabled) { @@ -165,20 +176,23 @@ function raiGetSizes(bid) { } function raiGetDemandType(bid) { + let raiFormat = 'display'; if (bid.mediaTypes != undefined) { if (bid.mediaTypes.video != undefined) { - return true; + raiFormat = 'video'; } } - return false; + return raiFormat; } function raiGetVideoInfo(bid) { - let videoData = []; - if (raiGetDemandType(bid)) { - videoData.push({format: bid.mediaTypes.video.context}); - videoData.push({playerSize: bid.mediaTypes.video.playerSize}); - videoData.push({mimes: bid.mediaTypes.video.mimes}); + let videoData; + if (raiGetDemandType(bid) == 'video') { + videoData = { + format: bid.mediaTypes.video.context, + playerSize: bid.mediaTypes.video.playerSize, + mimes: bid.mediaTypes.video.mimes + }; } return videoData; } @@ -187,7 +201,7 @@ function raiSetEids(bid) { let eids = []; if (bid && bid.userId) { - raiSetUserId(bid, eids, 'id5-sync.com', utils.deepAccess(bid, `userId.id5id`)); + raiSetUserId(bid, eids, 'id5-sync.com', utils.deepAccess(bid, `userId.id5id.uid`)); raiSetUserId(bid, eids, 'pubcommon', utils.deepAccess(bid, `userId.pubcid`)); raiSetUserId(bid, eids, 'criteo.com', utils.deepAccess(bid, `userId.criteoId`)); raiSetUserId(bid, eids, 'liveramp.com', utils.deepAccess(bid, `userId.idl_env`)); @@ -206,3 +220,24 @@ function raiSetUserId(bid, eids, source, value) { }); } } + +function renderer(bid) { + bid.renderer.push(() => { + renderAd(bid) + }); +} + +function renderAd(bid) { + let raOutstreamHBPassback = `${bid.vastXml}`; + let raPlayerHB = { + config: bid.params[0].player != undefined ? { + end: bid.params[0].player.end != null ? bid.params[0].player.end : 'close', + init: bid.params[0].player.init != null ? bid.params[0].player.init : 'close', + skin: bid.params[0].player.skin != null ? bid.params[0].player.skin : 'light', + } : {end: 'close', init: 'close', skin: 'light'}, + pid: bid.params[0].pid, + adUnit: bid.adUnitCode + }; + + window.raParams(raPlayerHB, raOutstreamHBPassback, true); +} diff --git a/modules/richaudienceBidAdapter.md b/modules/richaudienceBidAdapter.md index 852af5f1844..932cdb8f8de 100644 --- a/modules/richaudienceBidAdapter.md +++ b/modules/richaudienceBidAdapter.md @@ -3,7 +3,7 @@ ``` Module Name: Rich Audience Bidder Adapter Module Type: Bidder Adapter -Maintainer: cert@richaudience.com +Maintainer: cert@richaudience.com ``` # Description @@ -15,7 +15,7 @@ Please reach out to your account manager for more information. # Test Parameters -## Web +## Web - DISPLAY ``` var adUnits = [ { @@ -45,6 +45,33 @@ Please reach out to your account manager for more information. ]; ``` +## Web - VIDEO +``` + var adUnits = [{ + code: 'video1', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480] + } + }, + + bids: [{ + bidder: 'richaudience', + params: { + pid: 'OjUW9KhuQV', + supplyType: 'site', + player: { + init: "open", + end: "close", + skin: "light" + } + } + }] + + }]; +``` + ## In-app ``` var adUnits = [ diff --git a/modules/rtbhouseBidAdapter.js b/modules/rtbhouseBidAdapter.js index ca760ca49eb..3337c3f1b59 100644 --- a/modules/rtbhouseBidAdapter.js +++ b/modules/rtbhouseBidAdapter.js @@ -46,9 +46,7 @@ export const spec = { site: mapSite(validBidRequests, bidderRequest), cur: DEFAULT_CURRENCY_ARR, test: validBidRequests[0].params.test || 0, - source: { - tid: validBidRequests[0].transactionId - } + source: mapSource(validBidRequests[0]), }; if (bidderRequest && bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) { const consentStr = (bidderRequest.gdprConsent.consentString) @@ -145,6 +143,52 @@ function mapSite(slot, bidderRequest) { } } +/** + * @param {object} slot Ad Unit Params by Prebid + * @returns {object} Source by OpenRTB 2.5 §3.2.2 + */ +function mapSource(slot) { + const source = { + tid: slot.transactionId, + }; + const schain = mapSchain(slot.schain); + if (schain) { + source.ext = { + schain: schain + } + } + return source; +} + +/** + * @param {object} schain object set by Publisher + * @returns {object} OpenRTB SupplyChain object + */ +function mapSchain(schain) { + if (!schain) { + return null; + } + if (!validateSchain(schain)) { + utils.logError('RTB House: required schain params missing'); + return null; + } + return schain; +} + +/** + * @param {object} schain object set by Publisher + * @returns {object} bool + */ +function validateSchain(schain) { + if (!schain.nodes) { + return false; + } + const requiredFields = ['asi', 'sid', 'hp']; + return schain.nodes.every(node => { + return requiredFields.every(field => node[field]); + }); +} + /** * @param {object} slot Ad Unit Params by Prebid * @returns {object} Request by OpenRTB Native Ads 1.1 §4 diff --git a/modules/rtbsapeBidAdapter.js b/modules/rtbsapeBidAdapter.js new file mode 100644 index 00000000000..8473ef4dbb3 --- /dev/null +++ b/modules/rtbsapeBidAdapter.js @@ -0,0 +1,142 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {OUTSTREAM} from '../src/video.js'; +import {Renderer} from '../src/Renderer.js'; +import {triggerPixel} from '../src/utils.js'; + +const BIDDER_CODE = 'rtbsape'; +const ENDPOINT = 'https://ssp-rtb.sape.ru/prebid'; +const RENDERER_SRC = 'https://cdn-rtb.sape.ru/js/player.js'; +const MATCH_SRC = 'https://www.acint.net/mc/?dp=141'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['sape'], + 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 && bid.mediaTypes && (bid.mediaTypes.banner || bid.mediaTypes.video) && bid.params && bid.params.placeId); + }, + + /** + * 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) { + let tz = (new Date()).getTimezoneOffset() + let padInt = (v) => (v < 10 ? '0' + v : '' + v); + + return { + url: ENDPOINT, + method: 'POST', + data: { + auctionId: bidderRequest.auctionId, + requestId: bidderRequest.bidderRequestId, + bids: validBidRequests, + timezone: (tz > 0 ? '-' : '+') + padInt(Math.floor(Math.abs(tz) / 60)) + ':' + padInt(Math.abs(tz) % 60), + refererInfo: bidderRequest.refererInfo + }, + } + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @param {{data: {bids: [{mediaTypes: {banner: boolean}}]}}} bidRequest Info describing the request to the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, bidRequest) { + if (!(serverResponse.body && Array.isArray(serverResponse.body.bids))) { + return []; + } + + let bids = {}; + bidRequest.data.bids.forEach(bid => bids[bid.bidId] = bid); + + return serverResponse.body.bids.map(bid => { + let requestBid = bids[bid.requestId]; + let context = utils.deepAccess(requestBid, 'mediaTypes.video.context'); + + if (context === OUTSTREAM && (bid.vastUrl || bid.vastXml)) { + let renderer = Renderer.install({ + id: bid.requestId, + url: RENDERER_SRC, + loaded: false + }); + + let muted = utils.deepAccess(requestBid, 'params.video.playerMuted'); + if (typeof muted === 'undefined') { + muted = true; + } + + bid.playerMuted = muted; + bid.renderer = renderer + + renderer.setRender(setOutstreamRenderer); + } + + return bid; + }); + }, + + /** + * Register the user sync pixels which should be dropped after the auction. + * + * @param {SyncOptions} syncOptions Which user syncs are allowed? + * @return {UserSync[]} The user syncs which should be dropped. + */ + getUserSyncs: function (syncOptions) { + const sync = []; + if (syncOptions.iframeEnabled) { + sync.push({ + type: 'iframe', + url: MATCH_SRC + }); + } + return sync; + }, + + /** + * Register bidder specific code, which will execute if a bid from this bidder won the auction + * @param {Bid} bid The bid that won the auction + */ + onBidWon: function(bid) { + if (bid.nurl) { + triggerPixel(bid.nurl); + } + } +} + +/** + * Initialize RtbSape outstream player + * + * @param bid + */ +function setOutstreamRenderer(bid) { + let props = {}; + if (bid.vastUrl) { + props.url = bid.vastUrl; + } + if (bid.vastXml) { + props.xml = bid.vastXml; + } + bid.renderer.push(() => { + let player = window.sapeRtbPlayerHandler(bid.adUnitCode, bid.width, bid.height, bid.playerMuted, {singleton: true}); + props.onComplete = () => player.destroy(); + props.onError = () => player.destroy(); + player.addSlot(props); + }); +} + +registerBidder(spec); diff --git a/modules/rtbsapeBidAdapter.md b/modules/rtbsapeBidAdapter.md new file mode 100644 index 00000000000..6b1afe3867d --- /dev/null +++ b/modules/rtbsapeBidAdapter.md @@ -0,0 +1,51 @@ +# Overview + +``` +Module Name: RtbSape Bid Adapter +Module Type: Bidder Adapter +Maintainer: sergey@sape.ru +``` + +# Description +Our module makes it easy to integrate RtbSape demand sources into your website. + +Supported Ad format: +* Banner +* Video (instream and outstream) + +# Test Parameters +``` +var adUnits = [ + // Banner adUnit + { + code: 'banner-div', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [{ + bidder: 'rtbsape', + params: { + placeId: 553307 + } + }] + }, + // Video adUnit + { + code: 'video-div', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [600, 340] + } + }, + bids: [{ + bidder: 'rtbsape', + params: { + placeId: 553309 + } + }] + } +]; +``` diff --git a/modules/rtdModule/index.js b/modules/rtdModule/index.js index cff09fbd4fb..9acd484cec8 100644 --- a/modules/rtdModule/index.js +++ b/modules/rtdModule/index.js @@ -23,14 +23,56 @@ */ /** - * @interface ModuleConfig + * @property + * @summary used to link submodule with config + * @name RtdSubmodule#config + * @type {Object} */ /** - * @property - * @summary sub module name - * @name ModuleConfig#name - * @type {string} + * @function + * @summary init sub module + * @name RtdSubmodule#init + * @param {Object} config + * @param {Object} gdpr settings + * @param {Object} usp settings + * @return {boolean} false to remove sub module + */ + +/** + * @function? + * @summary on auction init event + * @name RtdSubmodule#auctionInit + * @param {Object} data + * @param {SubmoduleConfig} config + */ + +/** + * @function? + * @summary on auction end event + * @name RtdSubmodule#auctionEnd + * @param {Object} data + * @param {SubmoduleConfig} config + */ + +/** + * @function? + * @summary on bid request event + * @name RtdSubmodule#updateBidRequest + * @param {Object} data + * @param {SubmoduleConfig} config + */ + +/** + * @function? + * @summary on bid response event + * @name RtdSubmodule#updateBidResponse + * @param {Object} data + * @param {SubmoduleConfig} config + */ + +/** + * @interface ModuleConfig */ /** @@ -40,18 +82,43 @@ * @type {number} */ +/** + * @property + * @summary timeout (if no auction dealy) + * @name ModuleConfig#timeout + * @type {number} + */ + +/** + * @property + * @summary list of sub modules + * @name ModuleConfig#dataProviders + * @type {SubmoduleConfig[]} + */ + +/** + * @interface SubModuleConfig + */ + /** * @property * @summary params for provide (sub module) - * @name ModuleConfig#params + * @name SubModuleConfig#params * @type {Object} */ /** * @property - * @summary timeout (if no auction dealy) - * @name ModuleConfig#timeout - * @type {number} + * @summary name + * @name ModuleConfig#name + * @type {string} + */ + +/** + * @property + * @summary delay auction for this sub module + * @name ModuleConfig#waitForIt + * @type {boolean} */ import {getGlobal} from '../../src/prebidGlobal.js'; @@ -59,15 +126,21 @@ import {config} from '../../src/config.js'; import {targeting} from '../../src/targeting.js'; import {getHook, module} from '../../src/hook.js'; import * as utils from '../../src/utils.js'; +import events from '../../src/events.js'; +import CONSTANTS from '../../src/constants.json'; +import {gdprDataHandler, uspDataHandler} from '../../src/adapterManager.js'; +import find from 'core-js-pure/features/array/find.js'; /** @type {string} */ const MODULE_NAME = 'realTimeData'; /** @type {number} */ const DEF_TIMEOUT = 1000; /** @type {RtdSubmodule[]} */ -let subModules = []; +export let subModules = []; /** @type {ModuleConfig} */ let _moduleConfig; +/** @type {SubmoduleConfig[]} */ +let _dataProviders = []; /** * enable submodule in User ID @@ -85,6 +158,9 @@ export function init(config) { } confListener(); // unsubscribe config listener _moduleConfig = realTimeData; + _dataProviders = realTimeData.dataProviders; + getHook('makeBidRequests').before(initSubModules); + setEventsListeners(); if (typeof (_moduleConfig.auctionDelay) === 'undefined') { _moduleConfig.auctionDelay = 0; } @@ -97,35 +173,82 @@ export function init(config) { }); } +/** + * call each sub module init function by config order + * if no init function / init return failure / module not configured - remove it from submodules list + */ +export function initSubModules(next, adUnits, auctionStart, auctionId, cbTimeout, labels) { + let subModulesByOrder = []; + _dataProviders.forEach(provider => { + const sm = find(subModules, s => s.name === provider.name); + const initResponse = sm && sm.init && sm.init(provider, gdprDataHandler.getConsentData(), uspDataHandler.getConsentData()); + if (initResponse) { + subModulesByOrder.push(Object.assign(sm, {config: provider})); + } + }); + subModules = subModulesByOrder; + next(adUnits, auctionStart, auctionId, cbTimeout, labels) +} + +/** + * call each sub module event function by config order + */ +function setEventsListeners() { + events.on(CONSTANTS.EVENTS.AUCTION_INIT, (args) => { + subModules.forEach(sm => { sm.auctionInit && sm.auctionInit(args, sm.config) }) + }); + events.on(CONSTANTS.EVENTS.AUCTION_END, (args) => { + subModules.forEach(sm => { sm.auctionEnd && sm.auctionEnd(args, sm.config) }) + }); + events.on(CONSTANTS.EVENTS.BEFORE_REQUEST_BIDS, (args) => { + subModules.forEach(sm => { sm.updateBidRequest && sm.updateBidRequest(args, sm.config) }) + }); + events.on(CONSTANTS.EVENTS.BID_RESPONSE, (args) => { + subModules.forEach(sm => { sm.updateBidResponse && sm.updateBidResponse(args, sm.config) }) + }); +} + /** * get data from sub module * @param {AdUnit[]} adUnits received from auction * @param {function} callback callback function on data received */ -function getProviderData(adUnits, callback) { - const callbackExpected = subModules.length; - let dataReceived = []; - let processDone = false; - const dataWaitTimeout = setTimeout(() => { - processDone = true; - callback(dataReceived); - }, _moduleConfig.auctionDelay || _moduleConfig.timeout || DEF_TIMEOUT); +export function getProviderData(adUnits, callback) { + /** + * invoke callback if one of the conditions met: + * timeout reached + * all submodules answered + * all sub modules configured "waitForIt:true" answered (as long as there is at least one configured) + */ + const waitForSubModulesLength = subModules.filter(sm => sm.config && sm.config.waitForIt).length; + let callbacksExpected = waitForSubModulesLength || subModules.length; + const shouldWaitForAllSubModules = waitForSubModulesLength === 0; + let dataReceived = {}; + let processDone = false; + const dataWaitTimeout = setTimeout(done, _moduleConfig.auctionDelay || _moduleConfig.timeout || DEF_TIMEOUT); subModules.forEach(sm => { - sm.getData(adUnits, onDataReceived); + sm.getData(adUnits, onDataReceived.bind(sm)); }); function onDataReceived(data) { if (processDone) { return } - dataReceived.push(data); - if (dataReceived.length === callbackExpected) { - processDone = true; + dataReceived[this.name] = data; + if (shouldWaitForAllSubModules || (this.config && this.config.waitForIt)) { + callbacksExpected-- + } + if (callbacksExpected <= 0) { clearTimeout(dataWaitTimeout); - callback(dataReceived); + done(); } } + + function done() { + processDone = true; + callback(dataReceived); + } } /** @@ -137,7 +260,7 @@ function getProviderData(adUnits, callback) { export function setTargetsAfterRequestBids(next, adUnits) { getProviderData(adUnits, (data) => { if (data && Object.keys(data).length) { - const _mergedData = deepMerge(data); + const _mergedData = deepMerge(setDataOrderByProvider(subModules, data)); if (Object.keys(_mergedData).length) { setDataForPrimaryAdServer(_mergedData); } @@ -146,6 +269,22 @@ export function setTargetsAfterRequestBids(next, adUnits) { }); } +/** + * return an array providers data in reverse order,so the data merge will be according to correct config order + * @param {Submodule[]} modules + * @param {Object} data - data retrieved from providers + * @return {array} reversed order ready for merge + */ +function setDataOrderByProvider(modules, data) { + let rd = []; + for (let i = modules.length; i--; i > 0) { + if (data[modules[i].name]) { + rd.push(data[modules[i].name]) + } + } + return rd; +} + /** * deep merge array of objects * @param {array} arr - objects array @@ -181,7 +320,7 @@ export function deepMerge(arr) { export function requestBidsHook(fn, reqBidsConfigObj) { getProviderData(reqBidsConfigObj.adUnits || getGlobal().adUnits, (data) => { if (data && Object.keys(data).length) { - const _mergedData = deepMerge(data); + const _mergedData = deepMerge(setDataOrderByProvider(subModules, data)); if (Object.keys(_mergedData).length) { setDataForPrimaryAdServer(_mergedData); addIdDataToAdUnitBids(reqBidsConfigObj.adUnits || getGlobal().adUnits, _mergedData); @@ -196,11 +335,15 @@ export function requestBidsHook(fn, reqBidsConfigObj) { * @param {Object} data - key values to set */ function setDataForPrimaryAdServer(data) { - if (!utils.isGptPubadsDefined()) { - utils.logError('window.googletag is not defined on the page'); - return; + if (utils.isGptPubadsDefined()) { + targeting.setTargetingForGPT(data, null) + } else { + window.googletag = window.googletag || {}; + window.googletag.cmd = window.googletag.cmd || []; + window.googletag.cmd.push(() => { + targeting.setTargetingForGPT(data, null); + }); } - targeting.setTargetingForGPT(data, null); } /** @@ -216,5 +359,5 @@ function addIdDataToAdUnitBids(adUnits, data) { }); } -init(config); module('realTimeData', attachRealTimeDataProvider); +init(config); diff --git a/modules/rubiconAnalyticsAdapter.js b/modules/rubiconAnalyticsAdapter.js index 28c11ef8264..f6d30e06e9a 100644 --- a/modules/rubiconAnalyticsAdapter.js +++ b/modules/rubiconAnalyticsAdapter.js @@ -5,7 +5,15 @@ import { ajax } from '../src/ajax.js'; import { config } from '../src/config.js'; import * as utils from '../src/utils.js'; import { getGlobal } from '../src/prebidGlobal.js'; +import { getStorageManager } from '../src/storageManager.js'; +const RUBICON_GVL_ID = 52; +export const storage = getStorageManager(RUBICON_GVL_ID, 'rubicon'); +const COOKIE_NAME = 'rpaSession'; +const LAST_SEEN_EXPIRE_TIME = 1800000; // 30 mins +const END_EXPIRE_TIME = 21600000; // 6 hours + +let prebidGlobal = getGlobal(); const { EVENTS: { AUCTION_INIT, @@ -38,7 +46,22 @@ const cache = { auctions: {}, targeting: {}, timeouts: {}, + gpt: {}, +}; + +const BID_REJECTED_IPF = 'rejected-ipf'; + +export let rubiConf = { + pvid: utils.generateUUID().slice(0, 8) }; +// we are saving these as global to this module so that if a pub accidentally overwrites the entire +// rubicon object, then we do not lose other data +config.getConfig('rubicon', config => { + utils.mergeDeep(rubiConf, config.rubicon); + if (utils.deepAccess(config, 'rubicon.updatePageView') === true) { + rubiConf.pvid = utils.generateUUID().slice(0, 8) + } +}); export function getHostNameFromReferer(referer) { try { @@ -87,7 +110,7 @@ function sendMessage(auctionId, bidWonId) { function formatBid(bid) { return utils.pick(bid, [ 'bidder', - 'bidId', bidId => utils.deepAccess(bid, 'bidResponse.seatBidId') || bidId, + 'bidId', bidId => utils.deepAccess(bid, 'bidResponse.pbsBidId') || utils.deepAccess(bid, 'bidResponse.seatBidId') || bidId, 'status', 'error', 'source', (source, bid) => { @@ -126,18 +149,17 @@ function sendMessage(auctionId, bidWonId) { }); } let auctionCache = cache.auctions[auctionId]; - let referrer = config.getConfig('pageUrl') || auctionCache.referrer; + let referrer = config.getConfig('pageUrl') || (auctionCache && auctionCache.referrer); let message = { eventTimeMillis: Date.now(), - integration: config.getConfig('rubicon.int_type') || DEFAULT_INTEGRATION, + integration: rubiConf.int_type || DEFAULT_INTEGRATION, + ruleId: rubiConf.rule_name, version: '$prebid.version$', referrerUri: referrer, - referrerHostname: rubiconAdapter.referrerHostname || getHostNameFromReferer(referrer) + referrerHostname: rubiconAdapter.referrerHostname || getHostNameFromReferer(referrer), + channel: 'web', + wrapperName: rubiConf.wrapperName }; - const wrapperName = config.getConfig('rubicon.wrapperName'); - if (wrapperName) { - message.wrapperName = wrapperName; - } if (auctionCache && !auctionCache.sent) { let adUnitMap = Object.keys(auctionCache.bids).reduce((adUnits, bidId) => { let bid = auctionCache.bids[bidId]; @@ -149,7 +171,8 @@ function sendMessage(auctionId, bidWonId) { 'mediaTypes', 'dimensions', 'adserverTargeting', () => stringProperties(cache.targeting[bid.adUnit.adUnitCode] || {}), - 'adSlot' + 'gam', + 'pbAdSlot' ]); adUnit.bids = []; adUnit.status = 'no-bid'; // default it to be no bid @@ -195,15 +218,50 @@ function sendMessage(auctionId, bidWonId) { // pick our of top level floor data we want to send! if (auctionCache.floorData) { - auction.floors = utils.pick(auctionCache.floorData, [ - 'location', - 'modelName', () => auctionCache.floorData.modelVersion || '', - 'skipped', - 'enforcement', () => utils.deepAccess(auctionCache.floorData, 'enforcements.enforceJS'), - 'dealsEnforced', () => utils.deepAccess(auctionCache.floorData, 'enforcements.floorDeals') + if (auctionCache.floorData.location === 'noData') { + auction.floors = utils.pick(auctionCache.floorData, [ + 'location', + 'fetchStatus', + 'floorProvider as provider' + ]); + } else { + auction.floors = utils.pick(auctionCache.floorData, [ + 'location', + 'modelVersion as modelName', + 'skipped', + 'enforcement', () => utils.deepAccess(auctionCache.floorData, 'enforcements.enforceJS'), + 'dealsEnforced', () => utils.deepAccess(auctionCache.floorData, 'enforcements.floorDeals'), + 'skipRate', + 'fetchStatus', + 'floorProvider as provider' + ]); + } + } + + // gather gdpr info + if (auctionCache.gdprConsent) { + auction.gdpr = utils.pick(auctionCache.gdprConsent, [ + 'gdprApplies as applies', + 'consentString', + 'apiVersion as version' ]); } + // gather session info + if (auctionCache.session) { + message.session = utils.pick(auctionCache.session, [ + 'id', + 'pvid', + 'start', + 'expires' + ]); + if (!utils.isEmpty(auctionCache.session.fpkvs)) { + message.fpkvs = Object.keys(auctionCache.session.fpkvs).map(key => { + return { key, value: auctionCache.session.fpkvs[key] }; + }); + } + } + if (serverConfig) { auction.serverTimeoutMillis = serverConfig.timeout; } @@ -261,13 +319,13 @@ function getBidPrice(bid) { } // otherwise we convert and return try { - return Number(getGlobal().convertCurrency(cpm, currency, 'USD')); + return Number(prebidGlobal.convertCurrency(cpm, currency, 'USD')); } catch (err) { utils.logWarn('Rubicon Analytics Adapter: Could not determine the bidPriceUSD of the bid ', bid); } } -export function parseBidResponse(bid, previousBidResponse) { +export function parseBidResponse(bid, previousBidResponse, auctionFloorData) { // The current bidResponse for this matching requestId/bidRequestId let responsePrice = getBidPrice(bid) // we need to compare it with the previous one (if there was one) @@ -279,16 +337,22 @@ export function parseBidResponse(bid, previousBidResponse) { 'dealId', 'status', 'mediaType', - 'dimensions', () => utils.pick(bid, [ - 'width', - 'height' - ]), + 'dimensions', () => { + const width = bid.width || bid.playerWidth; + const height = bid.height || bid.playerHeight; + return (width && height) ? {width, height} : undefined; + }, 'seatBidId', 'floorValue', () => utils.deepAccess(bid, 'floorData.floorValue'), 'floorRule', () => utils.debugTurnedOn() ? utils.deepAccess(bid, 'floorData.floorRule') : undefined ]); } +function getFpkvs() { + const isValid = rubiConf.fpkvs && typeof rubiConf.fpkvs === 'object' && Object.keys(rubiConf.fpkvs).every(key => typeof rubiConf.fpkvs[key] === 'string'); + return isValid ? rubiConf.fpkvs : {}; +} + let samplingFactor = 1; let accountId; // List of known rubicon aliases @@ -307,6 +371,74 @@ function setRubiconAliases(aliasRegistry) { }); } +function getRpaCookie() { + let encodedCookie = storage.getDataFromLocalStorage(COOKIE_NAME); + if (encodedCookie) { + try { + return JSON.parse(window.atob(encodedCookie)); + } catch (e) { + utils.logError(`Rubicon Analytics: Unable to decode ${COOKIE_NAME} value: `, e); + } + } + return {}; +} + +function setRpaCookie(decodedCookie) { + try { + storage.setDataInLocalStorage(COOKIE_NAME, window.btoa(JSON.stringify(decodedCookie))); + } catch (e) { + utils.logError(`Rubicon Analytics: Unable to encode ${COOKIE_NAME} value: `, e); + } +} + +function updateRpaCookie() { + const currentTime = Date.now(); + let decodedRpaCookie = getRpaCookie(); + if ( + !Object.keys(decodedRpaCookie).length || + (currentTime - decodedRpaCookie.lastSeen) > LAST_SEEN_EXPIRE_TIME || + decodedRpaCookie.expires < currentTime + ) { + decodedRpaCookie = { + id: utils.generateUUID(), + start: currentTime, + expires: currentTime + END_EXPIRE_TIME, // six hours later, + } + } + // possible that decodedRpaCookie is undefined, and if it is, we probably are blocked by storage or some other exception + if (Object.keys(decodedRpaCookie).length) { + decodedRpaCookie.lastSeen = currentTime; + decodedRpaCookie.fpkvs = {...decodedRpaCookie.fpkvs, ...getFpkvs()}; + decodedRpaCookie.pvid = rubiConf.pvid; + setRpaCookie(decodedRpaCookie) + } + return decodedRpaCookie; +} + +function subscribeToGamSlots() { + window.googletag.pubads().addEventListener('slotRenderEnded', event => { + const isMatchingAdSlot = utils.isAdUnitCodeMatchingSlot(event.slot); + // loop through auctions and adUnits and mark the info + Object.keys(cache.auctions).forEach(auctionId => { + (Object.keys(cache.auctions[auctionId].bids) || []).forEach(bidId => { + let bid = cache.auctions[auctionId].bids[bidId]; + // if this slot matches this bids adUnit, add the adUnit info + if (isMatchingAdSlot(bid.adUnit.adUnitCode)) { + bid.adUnit.gam = utils.pick(event, [ + // these come in as `null` from Gpt, which when stringified does not get removed + // so set explicitly to undefined when not a number + 'advertiserId', advertiserId => utils.isNumber(advertiserId) ? advertiserId : undefined, + 'creativeId', creativeId => utils.isNumber(creativeId) ? creativeId : undefined, + 'lineItemId', lineItemId => utils.isNumber(lineItemId) ? lineItemId : undefined, + 'adSlot', () => event.slot.getAdUnitPath(), + 'isSlotEmpty', () => event.isEmpty || undefined + ]); + } + }); + }); + }); +} + let baseAdapter = adapter({analyticsType: 'endpoint'}); let rubiconAdapter = Object.assign({}, baseAdapter, { referrerHostname: '', @@ -351,7 +483,9 @@ let rubiconAdapter = Object.assign({}, baseAdapter, { }, disableAnalytics() { this.getUrl = baseAdapter.getUrl; - accountId = null; + accountId = undefined; + rubiConf = {}; + cache.gpt.registered = false; baseAdapter.disableAnalytics.apply(this, arguments); }, track({eventType, args}) { @@ -365,11 +499,19 @@ let rubiconAdapter = Object.assign({}, baseAdapter, { ]); cacheEntry.bids = {}; cacheEntry.bidsWon = {}; - cacheEntry.referrer = args.bidderRequests[0].refererInfo.referer; - if (utils.deepAccess(args, 'bidderRequests.0.bids.0.floorData')) { - cacheEntry.floorData = {...utils.deepAccess(args, 'bidderRequests.0.bids.0.floorData')}; + cacheEntry.referrer = utils.deepAccess(args, 'bidderRequests.0.refererInfo.referer'); + const floorData = utils.deepAccess(args, 'bidderRequests.0.bids.0.floorData'); + if (floorData) { + cacheEntry.floorData = {...floorData}; } + cacheEntry.gdprConsent = utils.deepAccess(args, 'bidderRequests.0.gdprConsent'); + cacheEntry.session = storage.localStorageIsEnabled() && updateRpaCookie(); cache.auctions[args.auctionId] = cacheEntry; + // register to listen to gpt events if not done yet + if (!cache.gpt.registered && utils.isGptPubadsDefined()) { + subscribeToGamSlots(); + cache.gpt.registered = true; + } break; case BID_REQUESTED: Object.assign(cache.auctions[args.auctionId].bids, args.bids.reduce((memo, bid) => { @@ -440,6 +582,12 @@ let rubiconAdapter = Object.assign({}, baseAdapter, { } return ['banner']; }, + 'gam', () => { + if (utils.deepAccess(bid, 'fpd.context.adServer.name') === 'gam') { + return {adSlot: bid.fpd.context.adServer.adSlot} + } + }, + 'pbAdSlot', () => utils.deepAccess(bid, 'fpd.context.pbAdSlot') ]) ]); return memo; @@ -449,8 +597,8 @@ let rubiconAdapter = Object.assign({}, baseAdapter, { let auctionEntry = cache.auctions[args.auctionId]; let bid = auctionEntry.bids[args.requestId]; // If floor resolved gptSlot but we have not yet, then update the adUnit to have the adSlot name - if (!utils.deepAccess(bid, 'adUnit.adSlot') && utils.deepAccess(args, 'floorData.matchedFields.gptSlot')) { - bid.adUnit.adSlot = args.floorData.matchedFields.gptSlot; + if (!utils.deepAccess(bid, 'adUnit.gam.adSlot') && utils.deepAccess(args, 'floorData.matchedFields.gptSlot')) { + utils.deepSetValue(bid, 'adUnit.gam.adSlot', args.floorData.matchedFields.gptSlot); } // if we have not set enforcements yet set it if (!utils.deepAccess(auctionEntry, 'floorData.enforcements') && utils.deepAccess(args, 'floorData.enforcements')) { @@ -467,7 +615,7 @@ let rubiconAdapter = Object.assign({}, baseAdapter, { delete bid.error; // it's possible for this to be set by a previous timeout break; case NO_BID: - bid.status = args.status === BID_REJECTED ? 'rejected' : 'no-bid'; + bid.status = args.status === BID_REJECTED ? BID_REJECTED_IPF : 'no-bid'; delete bid.error; break; default: @@ -476,7 +624,7 @@ let rubiconAdapter = Object.assign({}, baseAdapter, { code: 'request-error' }; } - bid.clientLatencyMillis = Date.now() - cache.auctions[args.auctionId].timestamp; + bid.clientLatencyMillis = bid.timeToRespond || Date.now() - cache.auctions[args.auctionId].timestamp; bid.bidResponse = parseBidResponse(args, bid.bidResponse); break; case BIDDER_DONE: @@ -536,7 +684,8 @@ let rubiconAdapter = Object.assign({}, baseAdapter, { adapterManager.registerAnalyticsAdapter({ adapter: rubiconAdapter, - code: 'rubicon' + code: 'rubicon', + gvlid: RUBICON_GVL_ID }); export default rubiconAdapter; diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index 3c17f609a37..829fd208887 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -2,14 +2,17 @@ import * as utils from '../src/utils.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {config} from '../src/config.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import find from 'core-js-pure/features/array/find.js'; const DEFAULT_INTEGRATION = 'pbjs_lite'; const DEFAULT_PBS_INTEGRATION = 'pbjs'; -// always use https, regardless of whether or not current page is secure -export const FASTLANE_ENDPOINT = 'https://fastlane.rubiconproject.com/a/api/fastlane.json'; -export const VIDEO_ENDPOINT = 'https://prebid-server.rubiconproject.com/openrtb2/auction'; -export const SYNC_ENDPOINT = 'https://eus.rubiconproject.com/usync.html'; +let rubiConf = {}; +// we are saving these as global to this module so that if a pub accidentally overwrites the entire +// rubicon object, then we do not lose other data +config.getConfig('rubicon', config => { + utils.mergeDeep(rubiConf, config.rubicon); +}); const GVLID = 52; const DIGITRUST_PROP_NAMES = { @@ -28,6 +31,7 @@ var sizeMap = { 1: '468x60', 2: '728x90', 5: '120x90', + 7: '125x125', 8: '120x600', 9: '160x600', 10: '300x600', @@ -175,7 +179,7 @@ export const spec = { prebid: { cache: { vastxml: { - returnCreative: false // don't return the VAST + returnCreative: rubiConf.returnVast === true } }, targeting: { @@ -186,7 +190,7 @@ export const spec = { }, bidders: { rubicon: { - integration: config.getConfig('rubicon.int_type') || DEFAULT_PBS_INTEGRATION + integration: rubiConf.int_type || DEFAULT_PBS_INTEGRATION } } } @@ -201,12 +205,17 @@ export const spec = { } let bidFloor; - if (typeof bidRequest.getFloor === 'function' && !config.getConfig('rubicon.disableFloors')) { - let floorInfo = bidRequest.getFloor({ - currency: 'USD', - mediaType: 'video', - size: parseSizes(bidRequest, 'video') - }); + if (typeof bidRequest.getFloor === 'function' && !rubiConf.disableFloors) { + let floorInfo; + try { + floorInfo = bidRequest.getFloor({ + currency: 'USD', + mediaType: 'video', + size: parseSizes(bidRequest, 'video') + }); + } catch (e) { + utils.logError('Rubicon: getFloor threw an error: ', e); + } bidFloor = typeof floorInfo === 'object' && floorInfo.currency === 'USD' && !isNaN(parseInt(floorInfo.floor)) ? parseFloat(floorInfo.floor) : undefined; } else { bidFloor = parseFloat(utils.deepAccess(bidRequest, 'params.floor')); @@ -241,59 +250,25 @@ export const spec = { utils.deepSetValue(data, 'regs.ext.us_privacy', bidderRequest.uspConsent); } - if (bidRequest.userId && typeof bidRequest.userId === 'object' && - (bidRequest.userId.tdid || bidRequest.userId.pubcid || bidRequest.userId.lipb || bidRequest.userId.idl_env)) { - utils.deepSetValue(data, 'user.ext.eids', []); - - if (bidRequest.userId.tdid) { - data.user.ext.eids.push({ - source: 'adserver.org', - uids: [{ - id: bidRequest.userId.tdid, - ext: { - rtiPartner: 'TDID' - } - }] - }); - } - - if (bidRequest.userId.pubcid) { - data.user.ext.eids.push({ - source: 'pubcommon', - uids: [{ - id: bidRequest.userId.pubcid, - }] - }); - } - - // support liveintent ID - if (bidRequest.userId.lipb && bidRequest.userId.lipb.lipbid) { - data.user.ext.eids.push({ - source: 'liveintent.com', - uids: [{ - id: bidRequest.userId.lipb.lipbid - }] - }); - - data.user.ext.tpid = { - source: 'liveintent.com', - uid: bidRequest.userId.lipb.lipbid - }; - - if (Array.isArray(bidRequest.userId.lipb.segments) && bidRequest.userId.lipb.segments.length) { - utils.deepSetValue(data, 'rp.target.LIseg', bidRequest.userId.lipb.segments); + const eids = utils.deepAccess(bidderRequest, 'bids.0.userIdAsEids'); + if (eids && eids.length) { + // filter out unsupported id systems + utils.deepSetValue(data, 'user.ext.eids', eids.filter(eid => ['adserver.org', 'pubcid.org', 'liveintent.com', 'liveramp.com', 'sharedid.org'].indexOf(eid.source) !== -1)); + + // liveintent requires additional props to be set + const liveIntentEid = find(data.user.ext.eids, eid => eid.source === 'liveintent.com'); + if (liveIntentEid) { + utils.deepSetValue(data, 'user.ext.tpid', { source: liveIntentEid.source, uid: liveIntentEid.uids[0].id }); + if (liveIntentEid.ext && liveIntentEid.ext.segments) { + utils.deepSetValue(data, 'rp.target.LIseg', liveIntentEid.ext.segments); } } + } - // support identityLink (aka LiveRamp) - if (bidRequest.userId.idl_env) { - data.user.ext.eids.push({ - source: 'liveramp.com', - uids: [{ - id: bidRequest.userId.idl_env - }] - }); - } + // set user.id value from config value + const configUserId = config.getConfig('user.id'); + if (configUserId) { + utils.deepSetValue(data, 'user.id', configUserId); } if (config.getConfig('coppa') === true) { @@ -331,29 +306,43 @@ export const spec = { */ const pbAdSlot = utils.deepAccess(bidRequest, 'fpd.context.pbAdSlot'); if (typeof pbAdSlot === 'string' && pbAdSlot) { - utils.deepSetValue(data.imp[0].ext, 'context.data.adslot', pbAdSlot); + utils.deepSetValue(data.imp[0].ext, 'context.data.pbadslot', pbAdSlot); } + /** + * Copy GAM AdUnit and Name to imp + */ + ['name', 'adSlot'].forEach(name => { + /** @type {(string|undefined)} */ + const value = utils.deepAccess(bidRequest, `fpd.context.adserver.${name}`); + if (typeof value === 'string' && value) { + utils.deepSetValue(data.imp[0].ext, `context.data.adserver.${name.toLowerCase()}`, value); + } + }); + // if storedAuctionResponse has been set, pass SRID if (bidRequest.storedAuctionResponse) { utils.deepSetValue(data.imp[0], 'ext.prebid.storedauctionresponse.id', bidRequest.storedAuctionResponse.toString()); } + // set ext.prebid.auctiontimestamp using auction time + utils.deepSetValue(data.imp[0], 'ext.prebid.auctiontimestamp', bidderRequest.auctionStart); + return { method: 'POST', - url: VIDEO_ENDPOINT, + url: `https://${rubiConf.videoHost || 'prebid-server'}.rubiconproject.com/openrtb2/auction`, data, bidRequest } }); - if (config.getConfig('rubicon.singleRequest') !== true) { + if (rubiConf.singleRequest !== true) { // bids are not grouped if single request mode is not enabled requests = videoRequests.concat(bidRequests.filter(bidRequest => bidType(bidRequest) === 'banner').map(bidRequest => { const bidParams = spec.createSlotParams(bidRequest, bidderRequest); return { method: 'GET', - url: FASTLANE_ENDPOINT, + url: `https://${rubiConf.bannerHost || 'fastlane'}.rubiconproject.com/a/api/fastlane.json`, data: spec.getOrderedParams(bidParams).reduce((paramString, key) => { const propValue = bidParams[key]; return ((utils.isStr(propValue) && propValue !== '') || utils.isNumber(propValue)) ? `${paramString}${encodeParam(key, propValue)}&` : paramString; @@ -384,7 +373,7 @@ export const spec = { // SRA request returns grouped bidRequest arrays not a plain bidRequest aggregate.push({ method: 'GET', - url: FASTLANE_ENDPOINT, + url: `https://${rubiConf.bannerHost || 'fastlane'}.rubiconproject.com/a/api/fastlane.json`, data: spec.getOrderedParams(combinedSlotParams).reduce((paramString, key) => { const propValue = combinedSlotParams[key]; return ((utils.isStr(propValue) && propValue !== '') || utils.isNumber(propValue)) ? `${paramString}${encodeParam(key, propValue)}&` : paramString; @@ -491,8 +480,6 @@ export const spec = { const [latitude, longitude] = params.latLong || []; - const configIntType = config.getConfig('rubicon.int_type'); - const data = { 'account_id': params.accountId, 'site_id': params.siteId, @@ -501,7 +488,7 @@ export const spec = { 'alt_size_ids': parsedSizes.slice(1).join(',') || undefined, 'rp_floor': (params.floor = parseFloat(params.floor)) > 0.01 ? params.floor : 0.01, 'rp_secure': '1', - 'tk_flint': `${configIntType || DEFAULT_INTEGRATION}_v$prebid.version$`, + 'tk_flint': `${rubiConf.int_type || DEFAULT_INTEGRATION}_v$prebid.version$`, 'x_source.tid': bidRequest.transactionId, 'x_source.pchain': params.pchain, 'p_screen_res': _getScreenResolution(), @@ -513,12 +500,17 @@ export const spec = { }; // If floors module is enabled and we get USD floor back, send it in rp_hard_floor else undfined - if (typeof bidRequest.getFloor === 'function' && !config.getConfig('rubicon.disableFloors')) { - let floorInfo = bidRequest.getFloor({ - currency: 'USD', - mediaType: 'banner', - size: '*' - }); + if (typeof bidRequest.getFloor === 'function' && !rubiConf.disableFloors) { + let floorInfo; + try { + floorInfo = bidRequest.getFloor({ + currency: 'USD', + mediaType: 'banner', + size: '*' + }); + } catch (e) { + utils.logError('Rubicon: getFloor threw an error: ', e); + } data['rp_hard_floor'] = typeof floorInfo === 'object' && floorInfo.currency === 'USD' && !isNaN(parseInt(floorInfo.floor)) ? floorInfo.floor : undefined; } @@ -526,22 +518,42 @@ export const spec = { // For SRA we need to explicitly put empty semi colons so AE treats it as empty, instead of copying the latter value data['p_pos'] = (params.position === 'atf' || params.position === 'btf') ? params.position : ''; - if (bidRequest.userId) { - if (bidRequest.userId.tdid) { - data['tpid_tdid'] = bidRequest.userId.tdid; + if (bidRequest.userIdAsEids && bidRequest.userIdAsEids.length) { + const unifiedId = find(bidRequest.userIdAsEids, eid => eid.source === 'adserver.org'); + if (unifiedId) { + data['tpid_tdid'] = unifiedId.uids[0].id; } - - // support liveintent ID - if (bidRequest.userId.lipb && bidRequest.userId.lipb.lipbid) { - data['tpid_liveintent.com'] = bidRequest.userId.lipb.lipbid; - if (Array.isArray(bidRequest.userId.lipb.segments) && bidRequest.userId.lipb.segments.length) { - data['tg_v.LIseg'] = bidRequest.userId.lipb.segments.join(','); + const liveintentId = find(bidRequest.userIdAsEids, eid => eid.source === 'liveintent.com'); + if (liveintentId) { + data['tpid_liveintent.com'] = liveintentId.uids[0].id; + if (liveintentId.ext && Array.isArray(liveintentId.ext.segments) && liveintentId.ext.segments.length) { + data['tg_v.LIseg'] = liveintentId.ext.segments.join(','); } } + const liverampId = find(bidRequest.userIdAsEids, eid => eid.source === 'liveramp.com'); + if (liverampId) { + data['x_liverampidl'] = liverampId.uids[0].id; + } + const sharedId = find(bidRequest.userIdAsEids, eid => eid.source === 'sharedid.org'); + if (sharedId) { + data['eid_sharedid.org'] = `${sharedId.uids[0].id}^${sharedId.uids[0].atype}^${sharedId.uids[0].ext.third}`; + } + } - // support identityLink (aka LiveRamp) - if (bidRequest.userId.idl_env) { - data['tpid_liveramp.com'] = bidRequest.userId.idl_env; + // set ppuid value from config value + const configUserId = config.getConfig('user.id'); + if (configUserId) { + data['ppuid'] = configUserId; + } else { + // if config.getConfig('user.id') doesn't return anything, then look for the first eid.uids[*].ext.stype === 'ppuid' + for (let i = 0; bidRequest.userIdAsEids && i < bidRequest.userIdAsEids.length; i++) { + if (bidRequest.userIdAsEids[i].uids) { + const pubProvidedId = find(bidRequest.userIdAsEids[i].uids, uid => uid.ext && uid.ext.stype === 'ppuid'); + if (pubProvidedId && pubProvidedId.id) { + data['ppuid'] = pubProvidedId.id; + break; + } + } } } @@ -589,7 +601,16 @@ export const spec = { */ const pbAdSlot = utils.deepAccess(bidRequest, 'fpd.context.pbAdSlot'); if (typeof pbAdSlot === 'string' && pbAdSlot) { - data['tg_i.dfp_ad_unit_code'] = pbAdSlot.replace(/^\/+/, ''); + data['tg_i.pbadslot'] = pbAdSlot.replace(/^\/+/, ''); + } + + /** + * GAM Ad Unit + * @type {(string|undefined)} + */ + const gamAdUnit = utils.deepAccess(bidRequest, 'fpd.context.adServer.adSlot'); + if (typeof gamAdUnit === 'string' && gamAdUnit) { + data['tg_i.dfp_ad_unit_code'] = gamAdUnit.replace(/^\/+/, ''); } // digitrust properties @@ -662,7 +683,7 @@ export const spec = { cpm: bid.price || 0, bidderCode: seatbid.seat, ttl: 300, - netRevenue: config.getConfig('rubicon.netRevenue') !== false, // If anything other than false, netRev is true + netRevenue: rubiConf.netRevenue !== false, // If anything other than false, netRev is true width: bid.w || utils.deepAccess(bidRequest, 'mediaTypes.video.w') || utils.deepAccess(bidRequest, 'params.video.playerWidth'), height: bid.h || utils.deepAccess(bidRequest, 'mediaTypes.video.h') || utils.deepAccess(bidRequest, 'params.video.playerHeight'), }; @@ -742,7 +763,7 @@ export const spec = { cpm: ad.cpm || 0, dealId: ad.deal, ttl: 300, // 5 minutes - netRevenue: config.getConfig('rubicon.netRevenue') !== false, // If anything other than false, netRev is true + netRevenue: rubiConf.netRevenue !== false, // If anything other than false, netRev is true rubicon: { advertiserId: ad.advertiser, networkId: ad.network }, @@ -785,7 +806,7 @@ export const spec = { }, getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { if (!hasSynced && syncOptions.iframeEnabled) { - // data is only assigned if params are available to pass to SYNC_ENDPOINT + // data is only assigned if params are available to pass to syncEndpoint let params = ''; if (gdprConsent && typeof gdprConsent.consentString === 'string') { @@ -804,7 +825,7 @@ export const spec = { hasSynced = true; return { type: 'iframe', - url: SYNC_ENDPOINT + params + url: `https://${rubiConf.syncHost || 'eus'}.rubiconproject.com/usync.html` + params }; } }, @@ -1050,6 +1071,7 @@ function bidType(bid, log = false) { } } +export const resetRubiConf = () => rubiConf = {}; export function masSizeOrdering(sizes) { const MAS_SIZE_PRIORITY = [15, 2, 9]; @@ -1144,7 +1166,7 @@ export function hasValidSupplyChainParams(schain) { if (!schain.nodes) return isValid; isValid = schain.nodes.reduce((status, node) => { if (!status) return status; - return requiredFields.every(field => node[field]); + return requiredFields.every(field => node.hasOwnProperty(field)); }, true); if (!isValid) utils.logError('Rubicon: required schain params missing'); return isValid; diff --git a/modules/saambaaBidAdapter.js b/modules/saambaaBidAdapter.js new file mode 100755 index 00000000000..0e53d2a300d --- /dev/null +++ b/modules/saambaaBidAdapter.js @@ -0,0 +1,401 @@ +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.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.0'; +const BIDDER_CODE = 'saambaa'; + +export const VIDEO_ENDPOINT = 'https://nep.advangelists.com/xp/get?pubid='; +export const BANNER_ENDPOINT = 'https://nep.advangelists.com/xp/get?pubid='; +export const OUTSTREAM_SRC = 'https://player-cdn.beachfrontmedia.com/playerapi/loader/outstream.js'; +export const VIDEO_TARGETING = ['mimes', 'playbackmethod', 'maxduration', 'skip']; +export const DEFAULT_MIMES = ['video/mp4', 'application/javascript']; + +let pubid = ''; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], + + isBidRequestValid(bidRequest) { + if (typeof bidRequest != 'undefined') { + if (bidRequest.bidder !== BIDDER_CODE && typeof bidRequest.params === 'undefined') { return false; } + if (bidRequest === '' || bidRequest.params.placement === '' || bidRequest.params.pubid === '') { return false; } + return true; + } else { return false; } + }, + + buildRequests(bids, bidderRequest) { + let requests = []; + let videoBids = bids.filter(bid => isVideoBidValid(bid)); + let bannerBids = bids.filter(bid => isBannerBidValid(bid)); + videoBids.forEach(bid => { + pubid = getVideoBidParam(bid, 'pubid'); + requests.push({ + method: 'POST', + url: VIDEO_ENDPOINT + pubid, + data: createVideoRequestData(bid, bidderRequest), + bidRequest: bid + }); + }); + + bannerBids.forEach(bid => { + pubid = getBannerBidParam(bid, 'pubid'); + + requests.push({ + method: 'POST', + url: BANNER_ENDPOINT + pubid, + data: createBannerRequestData(bid, bidderRequest), + bidRequest: bid + }); + }); + return requests; + }, + + interpretResponse(serverResponse, {bidRequest}) { + let response = serverResponse.body; + if (response !== null && utils.isEmpty(response) == false) { + if (isVideoBid(bidRequest)) { + let bidResponse = { + requestId: response.id, + bidderCode: BIDDER_CODE, + cpm: response.seatbid[0].bid[0].price, + width: response.seatbid[0].bid[0].w, + height: response.seatbid[0].bid[0].h, + ttl: response.seatbid[0].bid[0].ttl || 60, + creativeId: response.seatbid[0].bid[0].crid, + currency: response.cur, + meta: { 'advertiserDomains': response.seatbid[0].bid[0].adomain }, + mediaType: VIDEO, + netRevenue: true + } + + if (response.seatbid[0].bid[0].adm) { + bidResponse.vastXml = response.seatbid[0].bid[0].adm; + bidResponse.adResponse = { + content: response.seatbid[0].bid[0].adm + }; + } else { + bidResponse.vastUrl = response.seatbid[0].bid[0].nurl; + } + + return bidResponse; + } else { + return { + requestId: response.id, + bidderCode: BIDDER_CODE, + cpm: response.seatbid[0].bid[0].price, + width: response.seatbid[0].bid[0].w, + height: response.seatbid[0].bid[0].h, + ad: response.seatbid[0].bid[0].adm, + ttl: response.seatbid[0].bid[0].ttl || 60, + creativeId: response.seatbid[0].bid[0].crid, + currency: response.cur, + meta: { 'advertiserDomains': response.seatbid[0].bid[0].adomain }, + mediaType: BANNER, + netRevenue: true + } + } + } + } +}; + +function isBannerBid(bid) { + return utils.deepAccess(bid, 'mediaTypes.banner') || !isVideoBid(bid); +} + +function isVideoBid(bid) { + return utils.deepAccess(bid, 'mediaTypes.video'); +} + +function isVideoBidValid(bid) { + return isVideoBid(bid) && getVideoBidParam(bid, 'pubid') && getVideoBidParam(bid, 'placement'); +} + +function isBannerBidValid(bid) { + return isBannerBid(bid) && getBannerBidParam(bid, 'pubid') && getBannerBidParam(bid, 'placement'); +} + +function getVideoBidParam(bid, key) { + return utils.deepAccess(bid, 'params.video.' + key) || utils.deepAccess(bid, 'params.' + key); +} + +function getBannerBidParam(bid, key) { + return utils.deepAccess(bid, 'params.banner.' + key) || utils.deepAccess(bid, 'params.' + key); +} + +function isMobile() { + return (/(ios|ipod|ipad|iphone|android)/i).test(navigator.userAgent); +} + +function isConnectedTV() { + return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(navigator.userAgent); +} + +function getDoNotTrack() { + return navigator.doNotTrack === '1' || window.doNotTrack === '1' || navigator.msDoNoTrack === '1' || navigator.doNotTrack === 'yes'; +} + +function findAndFillParam(o, key, value) { + try { + if (typeof value === 'function') { + o[key] = value(); + } else { + o[key] = value; + } + } catch (ex) {} +} + +function getOsVersion() { + let clientStrings = [ + { s: 'Android', r: /Android/ }, + { s: 'iOS', r: /(iPhone|iPad|iPod)/ }, + { s: 'Mac OS X', r: /Mac OS X/ }, + { s: 'Mac OS', r: /(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ }, + { s: 'Linux', r: /(Linux|X11)/ }, + { s: 'Windows 10', r: /(Windows 10.0|Windows NT 10.0)/ }, + { s: 'Windows 8.1', r: /(Windows 8.1|Windows NT 6.3)/ }, + { s: 'Windows 8', r: /(Windows 8|Windows NT 6.2)/ }, + { s: 'Windows 7', r: /(Windows 7|Windows NT 6.1)/ }, + { s: 'Windows Vista', r: /Windows NT 6.0/ }, + { s: 'Windows Server 2003', r: /Windows NT 5.2/ }, + { s: 'Windows XP', r: /(Windows NT 5.1|Windows XP)/ }, + { s: 'UNIX', r: /UNIX/ }, + { s: 'Search Bot', r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/ } + ]; + let cs = find(clientStrings, cs => cs.r.test(navigator.userAgent)); + return cs ? cs.s : 'unknown'; +} + +function getFirstSize(sizes) { + return (sizes && sizes.length) ? sizes[0] : { w: undefined, h: undefined }; +} + +function parseSizes(sizes) { + return utils.parseSizesInput(sizes).map(size => { + let [ width, height ] = size.split('x'); + return { + w: parseInt(width, 10) || undefined, + h: parseInt(height, 10) || undefined + }; + }); +} + +function getVideoSizes(bid) { + return parseSizes(utils.deepAccess(bid, 'mediaTypes.video.playerSize') || bid.sizes); +} + +function getBannerSizes(bid) { + return parseSizes(utils.deepAccess(bid, 'mediaTypes.banner.sizes') || bid.sizes); +} + +function getTopWindowReferrer() { + try { + return window.top.document.referrer; + } catch (e) { + return ''; + } +} + +function getVideoTargetingParams(bid) { + return Object.keys(Object(bid.params.video)) + .filter(param => includes(VIDEO_TARGETING, param)) + .reduce((obj, param) => { + obj[ param ] = bid.params.video[ param ]; + return obj; + }, {}); +} + +function createVideoRequestData(bid, bidderRequest) { + let topLocation = getTopWindowLocation(bidderRequest); + let topReferrer = getTopWindowReferrer(); + + // if size is explicitly given via adapter params + let paramSize = getVideoBidParam(bid, 'size'); + let sizes = []; + + if (typeof paramSize !== 'undefined' && paramSize != '') { + sizes = parseSizes(paramSize); + } else { + sizes = getVideoSizes(bid); + } + const firstSize = getFirstSize(sizes); + + let video = getVideoTargetingParams(bid); + const o = { + 'device': { + 'langauge': (global.navigator.language).split('-')[0], + 'dnt': (global.navigator.doNotTrack === 1 ? 1 : 0), + 'devicetype': isMobile() ? 4 : isConnectedTV() ? 3 : 2, + 'js': 1, + 'os': getOsVersion() + }, + 'at': 2, + 'site': {}, + 'tmax': 3000, + 'cur': ['USD'], + 'id': bid.bidId, + 'imp': [], + 'regs': { + 'ext': { + } + }, + 'user': { + 'ext': { + } + } + }; + + o.site['page'] = topLocation.href; + o.site['domain'] = topLocation.hostname; + o.site['search'] = topLocation.search; + o.site['domain'] = topLocation.hostname; + o.site['ref'] = topReferrer; + o.site['mobile'] = isMobile() ? 1 : 0; + const secure = topLocation.protocol.indexOf('https') === 0 ? 1 : 0; + + o.device['dnt'] = getDoNotTrack() ? 1 : 0; + + findAndFillParam(o.site, 'name', function() { + return global.top.document.title; + }); + + findAndFillParam(o.device, 'h', function() { + return global.screen.height; + }); + findAndFillParam(o.device, 'w', function() { + return global.screen.width; + }); + + let placement = getVideoBidParam(bid, 'placement'); + let floor = getVideoBidParam(bid, 'floor'); + if (floor == null) { floor = 0.5; } + + for (let j = 0; j < sizes.length; j++) { + o.imp.push({ + 'id': '' + j, + 'displaymanager': '' + BIDDER_CODE, + 'displaymanagerver': '' + ADAPTER_VERSION, + 'tagId': placement, + 'bidfloor': floor, + 'bidfloorcur': 'USD', + 'secure': secure, + 'video': Object.assign({ + 'id': utils.generateUUID(), + 'pos': 0, + 'w': firstSize.w, + 'h': firstSize.h, + 'mimes': DEFAULT_MIMES + }, video) + + }); + } + + if (bidderRequest && bidderRequest.gdprConsent) { + let { gdprApplies, consentString } = bidderRequest.gdprConsent; + o.regs.ext = {'gdpr': gdprApplies ? 1 : 0}; + o.user.ext = {'consent': consentString}; + } + + return o; +} + +function getTopWindowLocation(bidderRequest) { + let url = bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer; + return utils.parseUrl(config.getConfig('pageUrl') || url, { decodeSearchAsString: true }); +} + +function createBannerRequestData(bid, bidderRequest) { + let topLocation = getTopWindowLocation(bidderRequest); + let topReferrer = getTopWindowReferrer(); + + // if size is explicitly given via adapter params + + let paramSize = getBannerBidParam(bid, 'size'); + let sizes = []; + if (typeof paramSize !== 'undefined' && paramSize != '') { + sizes = parseSizes(paramSize); + } else { + sizes = getBannerSizes(bid); + } + + const o = { + 'device': { + 'langauge': (global.navigator.language).split('-')[0], + 'dnt': (global.navigator.doNotTrack === 1 ? 1 : 0), + 'devicetype': isMobile() ? 4 : isConnectedTV() ? 3 : 2, + 'js': 1 + }, + 'at': 2, + 'site': {}, + 'tmax': 3000, + 'cur': ['USD'], + 'id': bid.bidId, + 'imp': [], + 'regs': { + 'ext': { + } + }, + 'user': { + 'ext': { + } + } + }; + + o.site['page'] = topLocation.href; + o.site['domain'] = topLocation.hostname; + o.site['search'] = topLocation.search; + o.site['domain'] = topLocation.hostname; + o.site['ref'] = topReferrer; + o.site['mobile'] = isMobile() ? 1 : 0; + const secure = topLocation.protocol.indexOf('https') === 0 ? 1 : 0; + + o.device['dnt'] = getDoNotTrack() ? 1 : 0; + + findAndFillParam(o.site, 'name', function() { + return global.top.document.title; + }); + + findAndFillParam(o.device, 'h', function() { + return global.screen.height; + }); + findAndFillParam(o.device, 'w', function() { + return global.screen.width; + }); + + let placement = getBannerBidParam(bid, 'placement'); + for (let j = 0; j < sizes.length; j++) { + let size = sizes[j]; + + let floor = getBannerBidParam(bid, 'floor'); + if (floor == null) { floor = 0.1; } + + o.imp.push({ + 'id': '' + j, + 'displaymanager': '' + BIDDER_CODE, + 'displaymanagerver': '' + ADAPTER_VERSION, + 'tagId': placement, + 'bidfloor': floor, + 'bidfloorcur': 'USD', + 'secure': secure, + 'banner': { + 'id': utils.generateUUID(), + 'pos': 0, + 'w': size['w'], + 'h': size['h'] + } + }); + } + + if (bidderRequest && bidderRequest.gdprConsent) { + let { gdprApplies, consentString } = bidderRequest.gdprConsent; + o.regs.ext = {'gdpr': gdprApplies ? 1 : 0}; + o.user.ext = {'consent': consentString}; + } + + return o; +} +registerBidder(spec); diff --git a/modules/saambaaBidAdapter.md b/modules/saambaaBidAdapter.md new file mode 100755 index 00000000000..2d391da7628 --- /dev/null +++ b/modules/saambaaBidAdapter.md @@ -0,0 +1,69 @@ +# Overview + +``` +Module Name: Saambaa Bidder Adapter +Module Type: Bidder Adapter +Maintainer: matt.voigt@saambaa.com +``` + +# Description + +Connects to Saambaa exchange for bids. + +Saambaa bid adapter supports Banner and Video ads currently. + +For more informatio + +# Sample Display Ad Unit: For Publishers +```javascript + +var displayAdUnit = [ +{ + code: 'display', + mediaTypes: { + banner: { + sizes: [[300, 250],[320, 50]] + } + } + bids: [{ + bidder: 'saambaa', + params: { + pubid: '121ab139faf7ac67428a23f1d0a9a71b', + placement: 1234, + size: '320x50' + } + }] +}]; +``` + +# Sample Video Ad Unit: For Publishers +```javascript + +var videoAdUnit = { + code: 'video', + sizes: [320,480], + mediaTypes: { + video: { + playerSize : [[320, 480]], + context: 'instream' + } + }, + bids: [ + { + bidder: 'saambaa', + params: { + pubid: '121ab139faf7ac67428a23f1d0a9a71b', + placement: 1234, + size: "320x480", + video: { + id: 123, + skip: 1, + mimes : ['video/mp4', 'application/javascript'], + playbackmethod : [2,6], + maxduration: 30 + } + } + } + ] + }; +``` \ No newline at end of file diff --git a/modules/seedingAllianceBidAdapter.js b/modules/seedingAllianceBidAdapter.js index b6acd7214a2..d85ae856317 100755 --- a/modules/seedingAllianceBidAdapter.js +++ b/modules/seedingAllianceBidAdapter.js @@ -62,7 +62,6 @@ export const spec = { const pt = setOnAny(validBidRequests, 'params.pt') || setOnAny(validBidRequests, 'params.priceType') || 'net'; const tid = validBidRequests[0].transactionId; const cur = [config.getConfig('currency.adServerCurrency') || DEFAULT_CUR]; - let pubcid = null; let url = bidderRequest.refererInfo.referer; const imp = validBidRequests.map((bid, id) => { @@ -112,10 +111,6 @@ export const spec = { }; }); - if (validBidRequests[0].crumbs && validBidRequests[0].crumbs.pubcid) { - pubcid = validBidRequests[0].crumbs.pubcid; - } - const request = { id: bidderRequest.auctionId, site: { @@ -126,15 +121,26 @@ export const spec = { }, cur, imp, - user: { - buyeruid: pubcid + user: {}, + regs: { + ext: { + gdpr: 0 + } } }; + if (bidderRequest && bidderRequest.gdprConsent) { + utils.deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + utils.deepSetValue(request, 'regs.ext.gdpr', (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean' && bidderRequest.gdprConsent.gdprApplies) ? 1 : 0); + } + return { method: 'POST', url: ENDPOINT_URL, data: JSON.stringify(request), + options: { + contentType: 'application/json' + }, bids: validBidRequests }; }, diff --git a/modules/seedtagBidAdapter.js b/modules/seedtagBidAdapter.js index 018339fabe4..e1832e50020 100644 --- a/modules/seedtagBidAdapter.js +++ b/modules/seedtagBidAdapter.js @@ -18,8 +18,8 @@ function mapMediaType(seedtagMediaType) { else return seedtagMediaType; } -function getMediaTypeFromBid(bid) { - return bid.mediaTypes && Object.keys(bid.mediaTypes)[0] +function hasVideoMediaType(bid) { + return !!bid.mediaTypes && !!bid.mediaTypes.video } function hasMandatoryParams(params) { @@ -34,7 +34,7 @@ function hasMandatoryParams(params) { ); } -function hasVideoMandatoryParams(mediaTypes) { +function hasMandatoryVideoParams(mediaTypes) { const isVideoInStream = !!mediaTypes.video && mediaTypes.video.context === 'instream'; const isPlayerSize = @@ -65,7 +65,7 @@ function buildBidRequests(validBidRequests) { bidRequest.adPosition = params.adPosition; } - if (params.video) { + if (hasVideoMediaType(validBidRequest)) { bidRequest.videoParams = params.video || {}; bidRequest.videoParams.w = validBidRequest.mediaTypes.video.playerSize[0][0]; @@ -124,8 +124,8 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid(bid) { - return getMediaTypeFromBid(bid) === VIDEO - ? hasMandatoryParams(bid.params) && hasVideoMandatoryParams(bid.mediaTypes) + return hasVideoMediaType(bid) + ? hasMandatoryParams(bid.params) && hasMandatoryVideoParams(bid.mediaTypes) : hasMandatoryParams(bid.params); }, diff --git a/modules/serverbidBidAdapter.md b/modules/serverbidBidAdapter.md deleted file mode 100644 index 87b51e665e2..00000000000 --- a/modules/serverbidBidAdapter.md +++ /dev/null @@ -1,44 +0,0 @@ -# Overview - -Module Name: Serverbid Bid Adapter - -Module Type: Bid Adapter - -Maintainer: jgrimes@serverbid.com, jswart@serverbid.com - -# Description - -Connects to Serverbid for receiving bids from configured demand sources. - -# Test Parameters -```javascript - var adUnits = [ - { - code: 'test-ad-1', - sizes: [[300, 250]], - bids: [ - { - bidder: 'serverbid', - params: { - networkId: '9969', - siteId: '980639' - } - } - ] - }, - { - code: 'test-ad-2', - sizes: [[300, 250]], - bids: [ - { - bidder: 'serverbid', - params: { - networkId: '9969', - siteId: '980639', - zoneIds: [178503] - } - } - ] - } - ]; -``` diff --git a/modules/sharedIdSystem.js b/modules/sharedIdSystem.js new file mode 100644 index 00000000000..5c2a3df0595 --- /dev/null +++ b/modules/sharedIdSystem.js @@ -0,0 +1,333 @@ +/** + * This module adds Shared ID support to the User ID module + * The {@link module:modules/userId} module is required. + * @module modules/sharedIdSystem + * @requires module:modules/userId + */ + +import * as utils from '../src/utils.js' +import {ajax} from '../src/ajax.js'; +import {submodule} from '../src/hook.js'; + +const MODULE_NAME = 'sharedId'; +const ID_SVC = 'https://id.sharedid.org/id'; +const DEFAULT_24_HOURS = 86400; +const OPT_OUT_VALUE = '00000000000000000000000000'; +// These values should NEVER change. If +// they do, we're no longer making ulids! +const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32 +const ENCODING_LEN = ENCODING.length; +const TIME_MAX = Math.pow(2, 48) - 1; +const TIME_LEN = 10; +const RANDOM_LEN = 16; +const id = factory(); +/** + * Constructs cookie value + * @param value + * @param needsSync + * @returns {string} + */ +function constructCookieValue(value, needsSync) { + const cookieValue = {}; + cookieValue.id = value; + cookieValue.ts = utils.timestamp(); + if (needsSync) { + cookieValue.ns = true; + } + utils.logInfo('SharedId: cookie Value: ' + JSON.stringify(cookieValue)); + return cookieValue; +} + +/** + * Checks if id needs to be synced + * @param configParams + * @param storedId + * @returns {boolean} + */ +function isIdSynced(configParams, storedId) { + const needSync = storedId.ns; + if (needSync) { + return true; + } + if (!configParams || typeof configParams.syncTime !== 'number') { + utils.logInfo('SharedId: Sync time is not configured or is not a number'); + } + let syncTime = (!configParams || typeof configParams.syncTime !== 'number') ? DEFAULT_24_HOURS : configParams.syncTime; + if (syncTime > DEFAULT_24_HOURS) { + syncTime = DEFAULT_24_HOURS; + } + const cookieTimestamp = storedId.ts; + if (cookieTimestamp) { + var secondBetweenTwoDate = timeDifferenceInSeconds(utils.timestamp(), cookieTimestamp); + return secondBetweenTwoDate >= syncTime; + } + return false; +} + +/** + * Gets time difference in secounds + * @param date1 + * @param date2 + * @returns {number} + */ +function timeDifferenceInSeconds(date1, date2) { + const diff = (date1 - date2) / 1000; + return Math.abs(Math.round(diff)); +} + +/** + * id generation call back + * @param result + * @param callback + * @returns {{success: success, error: error}} + */ +function idGenerationCallback(callback) { + return { + success: function (responseBody) { + let value = {}; + if (responseBody) { + try { + let responseObj = JSON.parse(responseBody); + utils.logInfo('SharedId: Generated SharedId: ' + responseObj.sharedId); + value = constructCookieValue(responseObj.sharedId, false); + } catch (error) { + utils.logError(error); + } + } + callback(value); + }, + error: function (statusText, responseBody) { + const value = constructCookieValue(id(), true); + utils.logInfo('SharedId: Ulid Generated SharedId: ' + value.id); + callback(value); + } + } +} + +/** + * existing id generation call back + * @param result + * @param callback + * @returns {{success: success, error: error}} + */ +function existingIdCallback(storedId, callback) { + return { + success: function (responseBody) { + utils.logInfo('SharedId: id to be synced: ' + storedId.id); + if (responseBody) { + try { + let responseObj = JSON.parse(responseBody); + storedId = constructCookieValue(responseObj.sharedId, false); + utils.logInfo('SharedId: Older SharedId: ' + storedId.id); + } catch (error) { + utils.logError(error); + } + } + callback(storedId); + }, + error: function () { + utils.logInfo('SharedId: Sync error for id : ' + storedId.id); + callback(storedId); + } + } +} + +/** + * Encode the id + * @param value + * @returns {string|*} + */ +function encodeId(value) { + const result = {}; + const sharedId = (value && typeof value['id'] === 'string') ? value['id'] : undefined; + if (sharedId == OPT_OUT_VALUE) { + return undefined; + } + if (sharedId) { + const bidIds = { + id: sharedId, + } + const ns = (value && typeof value['ns'] === 'boolean') ? value['ns'] : undefined; + if (ns == undefined) { + bidIds.third = sharedId; + } + result.sharedid = bidIds; + utils.logInfo('SharedId: Decoded value ' + JSON.stringify(result)); + return result; + } + return sharedId; +} + +/** + * the factory to generate unique identifier based on time and current pseudorandom number + * @param {string} the current pseudorandom number generator + * @returns {function(*=): *} + */ +function factory(currPrng) { + if (!currPrng) { + currPrng = detectPrng(); + } + return function ulid(seedTime) { + if (isNaN(seedTime)) { + seedTime = Date.now(); + } + return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN, currPrng); + }; +} + +/** + * creates and logs the error message + * @function + * @param {string} error message + * @returns {Error} + */ +function createError(message) { + utils.logError(message); + const err = new Error(message); + err.source = 'sharedId'; + return err; +} + +/** + * gets a a random charcter from generated pseudorandom number + * @param {string} the generated pseudorandom number + * @returns {string} + */ +function randomChar(prng) { + let rand = Math.floor(prng() * ENCODING_LEN); + if (rand === ENCODING_LEN) { + rand = ENCODING_LEN - 1; + } + return ENCODING.charAt(rand); +} + +/** + * encodes the time based on the length + * @param now + * @param len + * @returns {string} encoded time. + */ +function encodeTime (now, len) { + if (isNaN(now)) { + throw new Error(now + ' must be a number'); + } + + if (Number.isInteger(now) === false) { + throw createError('time must be an integer'); + } + + if (now > TIME_MAX) { + throw createError('cannot encode time greater than ' + TIME_MAX); + } + if (now < 0) { + throw createError('time must be positive'); + } + + if (Number.isInteger(len) === false) { + throw createError('length must be an integer'); + } + if (len < 0) { + throw createError('length must be positive'); + } + + let mod; + let str = ''; + for (; len > 0; len--) { + mod = now % ENCODING_LEN; + str = ENCODING.charAt(mod) + str; + now = (now - mod) / ENCODING_LEN; + } + return str; +} + +/** + * encodes random character + * @param len + * @param prng + * @returns {string} + */ +function encodeRandom (len, prng) { + let str = ''; + for (; len > 0; len--) { + str = randomChar(prng) + str; + } + return str; +} + +/** + * detects the pseudorandom number generator and generates the random number + * @function + * @param {string} error message + * @returns {string} a random number + */ +function detectPrng(root) { + if (!root) { + root = typeof window !== 'undefined' ? window : null; + } + const browserCrypto = root && (root.crypto || root.msCrypto); + if (browserCrypto) { + return () => { + const buffer = new Uint8Array(1); + browserCrypto.getRandomValues(buffer); + return buffer[0] / 0xff; + }; + } + return () => Math.random(); +} + +/** @type {Submodule} */ +export const sharedIdSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: MODULE_NAME, + + /** + * decode the stored id value for passing to bid requests + * @function + * @param {string} value + * @returns {{sharedid:{ id: string, third:string}} or undefined if value doesn't exists + */ + decode(value) { + return (value) ? encodeId(value) : undefined; + }, + + /** + * performs action to obtain id and return a value. + * @function + * @param {SubmoduleParams} [configParams] + * @returns {sharedId} + */ + getId(configParams) { + const resp = function (callback) { + utils.logInfo('SharedId: Sharedid doesnt exists, new cookie creation'); + ajax(ID_SVC, idGenerationCallback(callback), undefined, {method: 'GET', withCredentials: true}); + }; + return {callback: resp}; + }, + + /** + * performs actions even if the id exists and returns a value + * @param configParams + * @param storedId + * @returns {{callback: *}} + */ + extendId(configParams, storedId) { + utils.logInfo('SharedId: Existing shared id ' + storedId.id); + const resp = function (callback) { + const needSync = isIdSynced(configParams, storedId); + if (needSync) { + utils.logInfo('SharedId: Existing shared id ' + storedId + ' is not synced'); + const sharedIdPayload = {}; + sharedIdPayload.sharedId = storedId.id; + const payloadString = JSON.stringify(sharedIdPayload); + ajax(ID_SVC, existingIdCallback(storedId, callback), payloadString, {method: 'POST', withCredentials: true}); + } + }; + return {callback: resp}; + } +}; + +// Register submodule for userId +submodule('userId', sharedIdSubmodule); diff --git a/modules/sharedIdSystem.md b/modules/sharedIdSystem.md new file mode 100644 index 00000000000..a4541c16c49 --- /dev/null +++ b/modules/sharedIdSystem.md @@ -0,0 +1,43 @@ +## Shared ID User ID Submodule + +Shared ID User ID Module generates a UUID that can be utilized to improve user matching.This module enables timely synchronization which handles sharedId.org optout. This module does not require any registration. + +### Building Prebid with Shared Id Support +Your Prebid build must include the modules for both **userId** and **sharedId** submodule. 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,sharedIdSystem + +### Prebid Params + +Individual params may be set for the Shared ID User ID Submodule. +``` +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'sharedId', + params: { + syncTime: 60 // in seconds, default is 24 hours + }, + storage: { + name: 'sharedid', + type: 'cookie', + expires: 28 + }, + }] + } +}); +``` + +### Parameter Descriptions for the `usersync` Configuration Section +The below parameters apply only to the Shared ID User ID Module integration. + +| Params under usersync.userIds[]| Scope | Type | Description | Example | +| --- | --- | --- | --- | --- | +| name | Required | String | ID value for the Shared ID module - `"sharedId"` | `"sharedId"` | +| params | Optional | Object | Details for sharedId syncing. | | +| params.syncTime | Optional | Object | Configuration to define the frequency(in seconds) of id synchronization. By default id is synchronized every 24 hours | 60 | +| 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. | `"sharedid"` | +| storage.expires | Optional | Integer | How long (in days) the user ID information will be stored. | `28` | diff --git a/modules/sizeMappingV2.js b/modules/sizeMappingV2.js index 339a598bae5..4df537e0eb3 100644 --- a/modules/sizeMappingV2.js +++ b/modules/sizeMappingV2.js @@ -1,6 +1,7 @@ /** - * This modules adds support for the new Size Mapping spec described here. https://github.com/prebid/Prebid.js/issues/4129 - * This implementation replaces global sizeConfig with a adUnit/bidder level sizeConfig with support for labels. + * This module adds support for the new size mapping spec, Advanced Size Mapping. It's documented here. https://github.com/prebid/Prebid.js/issues/4129 + * The implementation is an alternative to global sizeConfig. It introduces 'Ad Unit' & 'Bidder' level sizeConfigs and also supports 'labels' for conditional + * rendering. Read full API documentation on Prebid.org, http://prebid.org/dev-docs/modules/sizeMappingV2.html */ import * as utils from '../src/utils.js'; @@ -8,11 +9,9 @@ import { processNativeAdUnitParams } from '../src/native.js'; import { adunitCounter } from '../src/adUnits.js'; import includes from 'core-js-pure/features/array/includes.js'; import { getHook } from '../src/hook.js'; -import { - adUnitSetupChecks -} from '../src/prebid.js'; +import { adUnitSetupChecks } from '../src/prebid.js'; -// allows for sinon.spy, sinon.stub, etc to unit test calls made to these functions internally +// Allows for stubbing of these functions while writing unit tests. export const internal = { checkBidderSizeConfigFormat, getActiveSizeBucket, @@ -22,32 +21,37 @@ export const internal = { isLabelActivated }; -// 'sizeMappingInternalStore' contains information whether a particular auction is using size mapping V2 (the new size mapping spec), -// and it also contains additional information on each adUnit, as such, mediaTypes, activeViewport, etc. -// This information is required by the 'getBids' function. +/* + 'sizeMappingInternalStore' contains information on, whether a particular auction is using size mapping V2 (the new size mapping spec), + and it also contains additional information on each adUnit, such as, mediaTypes, activeViewport, etc. This information is required by + the 'getBids' function. +*/ + export const sizeMappingInternalStore = createSizeMappingInternalStore(); function createSizeMappingInternalStore() { const sizeMappingInternalStore = {}; return { - initializeStore: function(auctionId, isUsingSizeMappingBool) { + initializeStore: function (auctionId, isUsingSizeMappingBool) { sizeMappingInternalStore[auctionId] = { usingSizeMappingV2: isUsingSizeMappingBool, adUnits: [] }; }, - getAuctionDetail: function(auctionId) { + getAuctionDetail: function (auctionId) { return sizeMappingInternalStore[auctionId]; }, - setAuctionDetail: function(auctionId, adUnitDetail) { + setAuctionDetail: function (auctionId, adUnitDetail) { sizeMappingInternalStore[auctionId].adUnits.push(adUnitDetail); } } } -// returns "true" if atleast one of the adUnit in the adUnits array has declared a Ad Unit or(and) Bidder level sizeConfig -// returns "false" otherwise +/* + Returns "true" if at least one of the adUnits in the adUnits array is using an Ad Unit and/or Bidder level sizeConfig, + otherwise, returns "false." +*/ export function isUsingNewSizeMapping(adUnits) { let isUsingSizeMappingBool = false; adUnits.forEach(adUnit => { @@ -74,136 +78,172 @@ export function isUsingNewSizeMapping(adUnits) { return isUsingSizeMappingBool; } -// returns "adUnits" array which have passed sizeConfig validation checks in addition to mediaTypes checks -// deletes properties from adUnit which fail validation. +/** + This hooked function executes before the function 'checkAdUnitSetup', that is defined in /src/prebid.js. It's necessary to run this funtion before + because it applies a series of checks in order to determine the correctness of the 'sizeConfig' array, which, the original 'checkAdUnitSetup' function + does not recognize. + @params {Array} adUnits + @returns {Array} validateAdUnits - Unrecognized properties are deleted. +*/ export function checkAdUnitSetupHook(adUnits) { - return adUnits.filter(adUnit => { + const validateSizeConfig = function (mediaType, sizeConfig, adUnitCode) { + let isValid = true; + const associatedProperty = { + banner: 'sizes', + video: 'playerSize', + native: 'active' + } + const propertyName = associatedProperty[mediaType]; + const conditionalLogMessages = { + banner: 'Removing mediaTypes.banner from ad unit.', + video: 'Removing mediaTypes.video.sizeConfig from ad unit.', + native: 'Removing mediaTypes.native.sizeConfig from ad unit.' + } + if (Array.isArray(sizeConfig)) { + sizeConfig.forEach((config, index) => { + const keys = Object.keys(config); + /* + Check #1 (Applies to 'banner', 'video' and 'native' media types.) + Verify that all config objects include 'minViewPort' and 'sizes' property. + If they do not, return 'false'. + */ + if (!(includes(keys, 'minViewPort') && includes(keys, propertyName))) { + utils.logError(`Ad unit ${adUnitCode}: Missing required property 'minViewPort' or 'sizes' from 'mediaTypes.${mediaType}.sizeConfig[${index}]'. ${conditionalLogMessages[mediaType]}`); + isValid = false; + return; + } + /* + Check #2 (Applies to 'banner', 'video' and 'native' media types.) + Verify that 'config.minViewPort' property is in [width, height] format. + If not, return false. + */ + if (!utils.isArrayOfNums(config.minViewPort, 2)) { + utils.logError(`Ad unit ${adUnitCode}: Invalid declaration of 'minViewPort' in 'mediaTypes.${mediaType}.sizeConfig[${index}]'. ${conditionalLogMessages[mediaType]}`); + isValid = false + return; + } + /* + Check #3 (Applies only to 'banner' and 'video' media types.) + Verify that 'config.sizes' (in case of banner) or 'config.playerSize' (in case of video) + property is in [width, height] format. If not, return 'false'. + */ + if (mediaType === 'banner' || mediaType === 'video') { + let showError = false; + if (Array.isArray(config[propertyName])) { + const validatedSizes = adUnitSetupChecks.validateSizes(config[propertyName]); + if (config[propertyName].length > 0 && validatedSizes.length === 0) { + isValid = false; + showError = true; + } + } else { + // Either 'sizes' or 'playerSize' is not declared as an array, which makes it invalid by default. + isValid = false; + showError = true; + } + if (showError) { + utils.logError(`Ad unit ${adUnitCode}: Invalid declaration of '${propertyName}' in 'mediaTypes.${mediaType}.sizeConfig[${index}]'. ${conditionalLogMessages[mediaType]}`); + return; + } + } + /* + Check #4 (Applies only to 'native' media type) + Verify that 'config.active' is a 'boolean'. + If not, return 'false'. + */ + if (mediaType === 'native') { + if (typeof config[propertyName] !== 'boolean') { + utils.logError(`Ad unit ${adUnitCode}: Invalid declaration of 'active' in 'mediaTypes.${mediaType}.sizeConfig[${index}]'. ${conditionalLogMessages[mediaType]}`); + isValid = false; + } + } + }); + } else { + utils.logError(`Ad unit ${adUnitCode}: Invalid declaration of 'sizeConfig' in 'mediaTypes.${mediaType}.sizeConfig'. ${conditionalLogMessages[mediaType]}`); + isValid = false; + return isValid; + } + + // If all checks have passed, isValid should equal 'true' + return isValid; + } + const validatedAdUnits = []; + adUnits.forEach(adUnit => { const mediaTypes = adUnit.mediaTypes; + let validatedBanner, validatedVideo, validatedNative; if (!mediaTypes || Object.keys(mediaTypes).length === 0) { utils.logError(`Detected adUnit.code '${adUnit.code}' did not have a 'mediaTypes' object defined. This is a required field for the auction, so this adUnit has been removed.`); - return false; + return; } - if (mediaTypes.banner) { - const banner = mediaTypes.banner; - if (banner.sizes) { - adUnitSetupChecks.validateBannerMediaType(adUnit); - } else if (banner.sizeConfig) { - if (Array.isArray(banner.sizeConfig)) { - let deleteBannerMediaType = false; - banner.sizeConfig.forEach((config, index) => { - // verify if all config objects include "minViewPort" and "sizes" property. - // if not, remove the mediaTypes.banner object - const keys = Object.keys(config); - if (!(includes(keys, 'minViewPort') && includes(keys, 'sizes'))) { - utils.logError(`Ad Unit: ${adUnit.code}: mediaTypes.banner.sizeConfig[${index}] is missing required property minViewPort or sizes or both.`); - deleteBannerMediaType = true; - return; - } - - // check if the config.sizes property is in [w, h] format, if yes, change it to [[w, h]] format. - const bannerSizes = adUnitSetupChecks.validateSizes(config.sizes); - if (utils.isArrayOfNums(config.minViewPort, 2)) { - if (config.sizes.length > 0 && bannerSizes.length > 0) { - config.sizes = bannerSizes; - } else if (config.sizes.length === 0) { - // If a size bucket doesn't have any sizes, sizes is an empty array, i.e. sizes: []. This check takes care of that. - config.sizes = [config.sizes]; - } else { - utils.logError(`Ad Unit: ${adUnit.code}: mediaTypes.banner.sizeConfig[${index}] has propery sizes declared with invalid value. Please ensure the sizes are listed like: [[300, 250], ...] or like: [] if no sizes are present for that size bucket.`); - deleteBannerMediaType = true; - } - } else { - utils.logError(`Ad Unit: ${adUnit.code}: mediaTypes.banner.sizeConfig[${index}] has property minViewPort decalared with invalid value. Please ensure minViewPort is an Array and is listed like: [700, 0]. Declaring an empty array is not allowed, instead use: [0, 0].`); - deleteBannerMediaType = true; + if (mediaTypes.banner.sizes) { + // Ad unit is using 'mediaTypes.banner.sizes' instead of the new property 'sizeConfig'. Apply the old checks! + validatedBanner = adUnitSetupChecks.validateBannerMediaType(adUnit); + } else if (mediaTypes.banner.sizeConfig) { + // Ad unit is using the 'sizeConfig' property, 'mediaTypes.banner.sizeConfig'. Apply the new checks! + validatedBanner = utils.deepClone(adUnit); + const isBannerValid = validateSizeConfig('banner', mediaTypes.banner.sizeConfig, adUnit.code); + if (!isBannerValid) { + delete validatedBanner.mediaTypes.banner; + } else { + /* + Make sure 'sizes' field is always an array of arrays. If not, make it so. + For example, [] becomes [[]], and [360, 400] becomes [[360, 400]] + */ + validatedBanner.mediaTypes.banner.sizeConfig.forEach(config => { + if (!Array.isArray(config.sizes[0])) { + config.sizes = [config.sizes]; } }); - if (deleteBannerMediaType) { - utils.logInfo(`Ad Unit: ${adUnit.code}: mediaTypes.banner has been removed due to error in sizeConfig.`); - delete adUnit.mediaTypes.banner; - } - } else { - utils.logError(`Ad Unit: ${adUnit.code}: mediaTypes.banner.sizeConfig is NOT an Array. Removing the invalid object mediaTypes.banner from Ad Unit.`); - delete adUnit.mediaTypes.banner; } } else { - utils.logError('Detected a mediaTypes.banner object did not include required property sizes or sizeConfig. Removing invalid mediaTypes.banner object from Ad Unit.'); - delete adUnit.mediaTypes.banner; + // Ad unit is invalid since it's mediaType property does not have either 'sizes' or 'sizeConfig' declared. + utils.logError(`Ad unit ${adUnit.code}: 'mediaTypes.banner' does not contain either 'sizes' or 'sizeConfig' property. Removing 'mediaTypes.banner' from ad unit.`); + validatedBanner = utils.deepClone(adUnit); + delete validatedBanner.mediaTypes.banner; } } if (mediaTypes.video) { - const video = mediaTypes.video; - if (video.playerSize) { - adUnitSetupChecks.validateVideoMediaType(adUnit); - } else if (video.sizeConfig) { - if (Array.isArray(video.sizeConfig)) { - let deleteVideoMediaType = false; - video.sizeConfig.forEach((config, index) => { - // verify if all config objects include "minViewPort" and "playerSize" property. - // if not, remove the mediaTypes.video object - const keys = Object.keys(config); - if (!(includes(keys, 'minViewPort') && includes(keys, 'playerSize'))) { - utils.logError(`Ad Unit: ${adUnit.code}: mediaTypes.video.sizeConfig[${index}] is missing required property minViewPort or playerSize or both. Removing the invalid property mediaTypes.video.sizeConfig from Ad Unit.`); - deleteVideoMediaType = true; - return; - } - // check if the config.playerSize property is in [w, h] format, if yes, change it to [[w, h]] format. - let tarPlayerSizeLen = (typeof config.playerSize[0] === 'number') ? 2 : 1; - const videoSizes = adUnitSetupChecks.validateSizes(config.playerSize, tarPlayerSizeLen); - if (utils.isArrayOfNums(config.minViewPort, 2)) { - if (tarPlayerSizeLen === 2) { - utils.logInfo('Transforming video.playerSize from [640,480] to [[640,480]] so it\'s in the proper format.'); - } - if (config.playerSize.length > 0 && videoSizes.length > 0) { - config.playerSize = videoSizes; - } else if (config.playerSize.length === 0) { - // If a size bucket doesn't have any playerSize, playerSize is an empty array, i.e. playerSize: []. This check takes care of that. - config.playerSize = [config.playerSize]; - } else { - utils.logError(`Ad Unit: ${adUnit.code}: mediaTypes.video.sizeConfig[${index}] has propery playerSize declared with invalid value. Please ensure the playerSize is listed like: [640, 480] or like: [] if no playerSize is present for that size bucket.`); - deleteVideoMediaType = true; - } - } else { - utils.logError(`Ad Unit: ${adUnit.code}: mediaTypes.video.sizeConfig[${index}] has property minViewPort decalared with invalid value. Please ensure minViewPort is an Array and is listed like: [700, 0]. Declaring an empty array is not allowed, instead use: [0, 0].`); - deleteVideoMediaType = true; + if (mediaTypes.video.playerSize) { + // Ad unit is using 'mediaTypes.video.playerSize' instead of the new property 'sizeConfig'. Apply the old checks! + validatedVideo = validatedBanner ? adUnitSetupChecks.validateVideoMediaType(validatedBanner) : adUnitSetupChecks.validateVideoMediaType(adUnit); + } else if (mediaTypes.video.sizeConfig) { + // Ad unit is using the 'sizeConfig' property, 'mediaTypes.video.sizeConfig'. Apply the new checks! + validatedVideo = validatedBanner || utils.deepClone(adUnit); + const isVideoValid = validateSizeConfig('video', mediaTypes.video.sizeConfig, adUnit.code); + if (!isVideoValid) { + delete validatedVideo.mediaTypes.video.sizeConfig; + } else { + /* + Make sure 'playerSize' field is always an array of arrays. If not, make it so. + For example, [] becomes [[]], and [640, 400] becomes [[640, 400]] + */ + validatedVideo.mediaTypes.video.sizeConfig.forEach(config => { + if (!Array.isArray(config.playerSize[0])) { + config.playerSize = [config.playerSize]; } }); - if (deleteVideoMediaType) { - utils.logInfo(`Ad Unit: ${adUnit.code}: mediaTypes.video.sizeConfig has been removed due to error in sizeConfig.`); - delete adUnit.mediaTypes.video.sizeConfig; - } - } else { - utils.logError(`Ad Unit: ${adUnit.code}: mediaTypes.video.sizeConfig is NOT an Array. Removing the invalid property mediaTypes.video.sizeConfig from Ad Unit.`); - return delete adUnit.mediaTypes.video.sizeConfig; } } } if (mediaTypes.native) { - const native = mediaTypes.native; - adUnitSetupChecks.validateNativeMediaType(adUnit); + // Apply the old native checks + validatedNative = validatedVideo ? adUnitSetupChecks.validateNativeMediaType(validatedVideo) : validatedBanner ? adUnitSetupChecks.validateNativeMediaType(validatedBanner) : adUnitSetupChecks.validateNativeMediaType(adUnit); + // Apply the new checks if 'mediaTypes.native.sizeConfig' detected if (mediaTypes.native.sizeConfig) { - native.sizeConfig.forEach(config => { - // verify if all config objects include "minViewPort" and "active" property. - // if not, remove the mediaTypes.native object - const keys = Object.keys(config); - if (!(includes(keys, 'minViewPort') && includes(keys, 'active'))) { - utils.logError(`Ad Unit: ${adUnit.code}: mediaTypes.native.sizeConfig is missing required property minViewPort or active or both. Removing the invalid property mediaTypes.native.sizeConfig from Ad Unit.`); - return delete adUnit.mediaTypes.native.sizeConfig; - } - - if (!(utils.isArrayOfNums(config.minViewPort, 2) && typeof config.active === 'boolean')) { - utils.logError(`Ad Unit: ${adUnit.code}: mediaTypes.native.sizeConfig has properties minViewPort or active decalared with invalid values. Removing the invalid property mediaTypes.native.sizeConfig from Ad Unit.`); - return delete adUnit.mediaTypes.native.sizeConfig; - } - }); + const isNativeValid = validateSizeConfig('native', mediaTypes.native.sizeConfig, adUnit.code); + if (!isNativeValid) { + delete validatedNative.mediaTypes.native.sizeConfig; + } } } - return true; + const validatedAdUnit = Object.assign({}, validatedBanner, validatedVideo, validatedNative); + validatedAdUnits.push(validatedAdUnit); }); + return validatedAdUnits; } getHook('checkAdUnitSetup').before(function (fn, adUnits) { @@ -231,7 +271,7 @@ export function checkBidderSizeConfigFormat(sizeConfig) { Array.isArray(config.relevantMediaTypes) && config.relevantMediaTypes.length > 0 && (config.relevantMediaTypes.length > 1 ? (config.relevantMediaTypes.every(mt => (includes(['banner', 'video', 'native'], mt)))) - : (['none', 'banner', 'video', 'native'].indexOf(config.relevantMediaTypes[0] > -1)))) { + : (['none', 'banner', 'video', 'native'].indexOf(config.relevantMediaTypes[0]) > -1))) { didCheckPass = didCheckPass && true; } else { didCheckPass = false; @@ -254,6 +294,7 @@ getHook('getBids').before(function (fn, bidderInfo) { if (sizeMappingInternalStore.getAuctionDetail(bidderInfo.auctionId).usingSizeMappingV2) { // if adUnit is found using sizeMappingV2 specs, run the getBids function which processes the sizeConfig object // and returns the bids array for a particular bidder. + const bids = getBids(bidderInfo); return fn.bail(bids); } else { @@ -264,30 +305,38 @@ getHook('getBids').before(function (fn, bidderInfo) { /** * Given an Ad Unit or a Bid as an input, returns a boolean telling if the Ad Unit/ Bid is active based on label checks - * @param {Object} bidOrAdUnit Either the Ad Unit object or the Bid object - * @param {Array} activeLabels List of active labels passed as an argument to pbjs.requestBids function - * @param {string} adUnitCode Unique string identifier for an Ad Unit. + * @param {Object} bidOrAdUnit - Either the Ad Unit object or the Bid object + * @param {Array} activeLabels - List of active labels passed as an argument to pbjs.requestBids function + * @param {string} adUnitCode - Unique string identifier for an Ad Unit. + * @param {number} adUnitInstance - Instance count of an 'Identical' ad unit. * @returns {boolean} Represents if the Ad Unit or the Bid is active or not */ -export function isLabelActivated(bidOrAdUnit, activeLabels, adUnitCode) { +export function isLabelActivated(bidOrAdUnit, activeLabels, adUnitCode, adUnitInstance) { let labelOperator; const labelsFound = Object.keys(bidOrAdUnit).filter(prop => prop === 'labelAny' || prop === 'labelAll'); if (labelsFound && labelsFound.length > 1) { utils.logWarn(`Size Mapping V2:: ${(bidOrAdUnit.code) - ? (`Ad Unit: ${bidOrAdUnit.code} => Ad unit has multiple label operators. Using the first declared operator: ${labelsFound[0]}`) - : (`Ad Unit: ${adUnitCode}, Bidder: ${bidOrAdUnit.bidder} => Bidder has multiple label operators. Using the first declared operator: ${labelsFound[0]}`)}`); + ? (`Ad Unit: ${bidOrAdUnit.code}(${adUnitInstance}) => Ad unit has multiple label operators. Using the first declared operator: ${labelsFound[0]}`) + : (`Ad Unit: ${adUnitCode}(${adUnitInstance}), Bidder: ${bidOrAdUnit.bidder} => Bidder has multiple label operators. Using the first declared operator: ${labelsFound[0]}`)}`); } labelOperator = labelsFound[0]; + if (labelOperator && !activeLabels) { + utils.logWarn(`Size Mapping V2:: ${(bidOrAdUnit.code) + ? (`Ad Unit: ${bidOrAdUnit.code}(${adUnitInstance}) => Found '${labelOperator}' on ad unit, but 'labels' is not set. Did you pass 'labels' to pbjs.requestBids() ?`) + : (`Ad Unit: ${adUnitCode}(${adUnitInstance}), Bidder: ${bidOrAdUnit.bidder} => Found '${labelOperator}' on bidder, but 'labels' is not set. Did you pass 'labels' to pbjs.requestBids() ?`)}`); + return true; + } + if (labelOperator === 'labelAll' && Array.isArray(bidOrAdUnit[labelOperator])) { if (bidOrAdUnit.labelAll.length === 0) { - utils.logWarn(`Size Mapping V2:: Ad Unit: ${bidOrAdUnit.code} => Ad unit has declared property 'labelAll' with an empty array. Ad Unit is still enabled!`); + utils.logWarn(`Size Mapping V2:: Ad Unit: ${bidOrAdUnit.code}(${adUnitInstance}) => Ad unit has declared property 'labelAll' with an empty array.`); return true; } return bidOrAdUnit.labelAll.every(label => includes(activeLabels, label)); } else if (labelOperator === 'labelAny' && Array.isArray(bidOrAdUnit[labelOperator])) { if (bidOrAdUnit.labelAny.length === 0) { - utils.logWarn(`Size Mapping V2:: Ad Unit: ${bidOrAdUnit.code} => Ad unit has declared property 'labelAny' with an empty array. Ad Unit is still enabled!`); + utils.logWarn(`Size Mapping V2:: Ad Unit: ${bidOrAdUnit.code}(${adUnitInstance}) => Ad unit has declared property 'labelAny' with an empty array.`); return true; } return bidOrAdUnit.labelAny.some(label => includes(activeLabels, label)); @@ -361,7 +410,7 @@ export function getFilteredMediaTypes(mediaTypes) { // banner mediaType gets deleted incase no sizes are specified for a given size bucket, that's why this check is necessary (transformedMediaTypes.banner) ? (transformedMediaTypes.banner.sizes) : ([]) ) : ((mediaType === 'video') ? ( - // video mediaType gets deleted incase no playerSize is specified for a given size bucket, that's why this check is necessary + // video mediaType gets deleted incase no playerSize is specified for a given size bucket, that's why this check is necessary (transformedMediaTypes.video) ? (transformedMediaTypes.video.playerSize) : ([]) ) : ('NA')) }; @@ -429,7 +478,7 @@ export function getRelevantMediaTypesForBidder(sizeConfig, activeViewport) { // sets sizeMappingInternalStore for a given auctionId with relevant adUnit information returned from the call to 'getFilteredMediaTypes' function // returns adUnit details object. -export function getAdUnitDetail(auctionId, adUnit) { +export function getAdUnitDetail(auctionId, adUnit, labels) { // fetch all adUnits for an auction from the sizeMappingInternalStore const adUnitsForAuction = sizeMappingInternalStore.getAuctionDetail(auctionId).adUnits; @@ -437,28 +486,28 @@ export function getAdUnitDetail(auctionId, adUnit) { const adUnitDetail = adUnitsForAuction.filter(adUnitDetail => adUnitDetail.adUnitCode === adUnit.code && utils.deepEqual(adUnitDetail.mediaTypes, adUnit.mediaTypes)); if (adUnitDetail.length > 0) { + adUnitDetail[0].cacheHits++; return adUnitDetail[0]; } else { - const { mediaTypes, sizeBucketToSizeMap, activeViewport, transformedMediaTypes } = internal.getFilteredMediaTypes(adUnit.mediaTypes); + const identicalAdUnit = adUnitsForAuction.filter(adUnitDetail => adUnitDetail.adUnitCode === adUnit.code); + const adUnitInstance = identicalAdUnit.length > 0 && typeof identicalAdUnit[0].instance === 'number' ? identicalAdUnit[identicalAdUnit.length - 1].instance + 1 : 1; + const isLabelActivated = internal.isLabelActivated(adUnit, labels, adUnit.code, adUnitInstance); + const { mediaTypes = adUnit.mediaTypes, sizeBucketToSizeMap, activeViewport, transformedMediaTypes } = isLabelActivated && internal.getFilteredMediaTypes(adUnit.mediaTypes); const adUnitDetail = { adUnitCode: adUnit.code, mediaTypes, sizeBucketToSizeMap, activeViewport, - transformedMediaTypes + transformedMediaTypes, + instance: adUnitInstance, + isLabelActivated, + cacheHits: 0 }; // set adUnitDetail in sizeMappingInternalStore against the correct 'auctionId'. sizeMappingInternalStore.setAuctionDetail(auctionId, adUnitDetail); - - // 'filteredMediaTypes' are the mediaTypes that got removed/filtered-out from adUnit.mediaTypes after sizeConfig filtration. - const filteredMediaTypes = Object.keys(mediaTypes).filter(mt => Object.keys(transformedMediaTypes).indexOf(mt) === -1); - - utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code} => Active size buckets after filtration: `, sizeBucketToSizeMap); - if (filteredMediaTypes.length > 0) { - utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code} => Media types that got filtered out: ${filteredMediaTypes}`); - } + isLabelActivated && utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}(${adUnitInstance}) => Active size buckets after filtration: `, sizeBucketToSizeMap); return adUnitDetail; } @@ -466,20 +515,19 @@ export function getAdUnitDetail(auctionId, adUnit) { export function getBids({ bidderCode, auctionId, bidderRequestId, adUnits, labels, src }) { return adUnits.reduce((result, adUnit) => { - if (internal.isLabelActivated(adUnit, labels, adUnit.code)) { - if (adUnit.mediaTypes && utils.isValidMediaTypes(adUnit.mediaTypes)) { - const { activeViewport, transformedMediaTypes } = internal.getAdUnitDetail(auctionId, adUnit); - + if (adUnit.mediaTypes && utils.isValidMediaTypes(adUnit.mediaTypes)) { + const { activeViewport, transformedMediaTypes, instance: adUnitInstance, isLabelActivated, cacheHits } = internal.getAdUnitDetail(auctionId, adUnit, labels); + if (isLabelActivated) { // check if adUnit has any active media types remaining, if not drop the adUnit from auction, // else proceed to evaluate the bids object. if (Object.keys(transformedMediaTypes).length === 0) { - utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code} => Ad unit disabled since there are no active media types after sizeConfig filtration.`); + cacheHits === 0 && utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}(${adUnitInstance}) => Ad unit disabled since there are no active media types after sizeConfig filtration.`); return result; } result .push(adUnit.bids.filter(bid => bid.bidder === bidderCode) .reduce((bids, bid) => { - if (internal.isLabelActivated(bid, labels, adUnit.code)) { + if (internal.isLabelActivated(bid, labels, adUnit.code, adUnitInstance)) { // handle native params const nativeParams = adUnit.nativeParams || utils.deepAccess(adUnit, 'mediaTypes.native'); if (nativeParams) { @@ -493,7 +541,7 @@ export function getBids({ bidderCode, auctionId, bidderRequestId, adUnits, label if (bid.sizeConfig) { const relevantMediaTypes = internal.getRelevantMediaTypesForBidder(bid.sizeConfig, activeViewport); if (relevantMediaTypes.length === 0) { - utils.logError(`Size Mapping V2:: Ad Unit: ${adUnit.code}, Bidder: ${bidderCode} => 'sizeConfig' is not configured properly. This bidder won't be eligible for sizeConfig checks and will remail active.`); + utils.logError(`Size Mapping V2:: Ad Unit: ${adUnit.code}(${adUnitInstance}), Bidder: ${bidderCode} => 'sizeConfig' is not configured properly. This bidder won't be eligible for sizeConfig checks and will remail active.`); bid = Object.assign({}, bid); } else if (relevantMediaTypes[0] !== 'none') { const bidderMediaTypes = Object @@ -507,11 +555,11 @@ export function getBids({ bidderCode, auctionId, bidderRequestId, adUnits, label if (Object.keys(bidderMediaTypes).length > 0) { bid = Object.assign({}, bid, { mediaTypes: bidderMediaTypes }); } else { - utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}, Bidder: ${bid.bidder} => 'relevantMediaTypes' does not match with any of the active mediaTypes at the Ad Unit level. This bidder is disabled.`); + utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}(${adUnitInstance}), Bidder: ${bid.bidder} => 'relevantMediaTypes' does not match with any of the active mediaTypes at the Ad Unit level. This bidder is disabled.`); return bids; } } else { - utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}, Bidder: ${bid.bidder} => 'relevantMediaTypes' is set to 'none' in sizeConfig for current viewport size. This bidder is disabled.`); + utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}(${adUnitInstance}), Bidder: ${bid.bidder} => 'relevantMediaTypes' is set to 'none' in sizeConfig for current viewport size. This bidder is disabled.`); return bids; } } @@ -530,15 +578,15 @@ export function getBids({ bidderCode, auctionId, bidderRequestId, adUnits, label })); return bids; } else { - utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}, Bidder: ${bid.bidder} => Label check for this bidder has failed. This bidder is disabled.`); + utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}(${adUnitInstance}), Bidder: ${bid.bidder} => Label check for this bidder has failed. This bidder is disabled.`); return bids; } }, [])); } else { - utils.logWarn(`Size Mapping V2:: Ad Unit: ${adUnit.code} => Ad unit has declared invalid 'mediaTypes' or has not declared a 'mediaTypes' property`); + cacheHits === 0 && utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}(${adUnitInstance}) => Ad unit is disabled due to failing label check.`); } } else { - utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code} => Ad unit is disabled due to failing label check.`); + utils.logWarn(`Size Mapping V2:: Ad Unit: ${adUnit.code} => Ad unit has declared invalid 'mediaTypes' or has not declared a 'mediaTypes' property`); return result; } return result; diff --git a/modules/smaatoBidAdapter.js b/modules/smaatoBidAdapter.js new file mode 100644 index 00000000000..49b4ed6aa34 --- /dev/null +++ b/modules/smaatoBidAdapter.js @@ -0,0 +1,275 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'smaato'; +const SMAATO_ENDPOINT = 'https://prebid.ad.smaato.net/oapi/prebid'; +const CLIENT = 'prebid_js_$prebid.version$_1.0' + +/** +* Transform BidRequest to OpenRTB-formatted BidRequest Object +* @param {Array} validBidRequests +* @param {any} bidderRequest +* @returns {string} +*/ +const buildOpenRtbBidRequestPayload = (validBidRequests, bidderRequest) => { + /** + * Turn incoming prebid sizes into openRtb format mapping. + * @param {*} sizes in format [[10, 10], [20, 20]] + * @returns array of openRtb format mappings [{w: 10, h: 10}, {w: 20, h: 20}] + */ + const parseSizes = (sizes) => { + return sizes.map((size) => { + return {w: size[0], h: size[1]}; + }) + } + + const imp = validBidRequests.map(br => { + const bannerMediaType = utils.deepAccess(br, 'mediaTypes.banner'); + const videoMediaType = utils.deepAccess(br, 'mediaTypes.video'); + let result = { + id: br.bidId, + tagid: utils.deepAccess(br, 'params.adspaceId') + } + + if (bannerMediaType) { + const sizes = parseSizes(utils.getAdUnitSizes(br)); + result.banner = { + w: sizes[0].w, + h: sizes[0].h, + format: sizes + } + } + + if (videoMediaType) { + result.video = { + mimes: videoMediaType.mimes, + minduration: videoMediaType.minduration, + startdelay: videoMediaType.startdelay, + linearity: videoMediaType.linearity, + w: videoMediaType.playerSize[0][0], + h: videoMediaType.playerSize[0][1], + maxduration: videoMediaType.maxduration, + skip: videoMediaType.skip, + protocols: videoMediaType.protocols, + ext: { + rewarded: videoMediaType.ext && videoMediaType.ext.rewarded ? videoMediaType.ext.rewarded : 0 + }, + skipmin: videoMediaType.skipmin, + api: videoMediaType.api + } + } + + return result; + }); + + const request = { + id: bidderRequest.auctionId, + at: 1, + imp, + cur: ['USD'], + tmax: bidderRequest.timeout, + site: { + id: window.location.hostname, + publisher: { + id: utils.deepAccess(validBidRequests[0], 'params.publisherId') + }, + domain: window.location.hostname, + page: window.location.href, + ref: bidderRequest.refererInfo.referer + }, + device: { + language: (navigator && navigator.language) ? navigator.language.split('-')[0] : '', + ua: navigator.userAgent, + dnt: utils.getDNT() ? 1 : 0, + h: screen.height, + w: screen.width + }, + regs: { + coppa: config.getConfig('coppa') === true ? 1 : 0, + ext: {} + }, + user: { + ext: {} + }, + ext: { + client: CLIENT + } + }; + + Object.assign(request.user, config.getConfig('fpd.user')); + Object.assign(request.site, config.getConfig('fpd.context')); + + if (bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies === true) { + utils.deepSetValue(request, 'regs.ext.gdpr', bidderRequest.gdprConsent.gdprApplies ? 1 : 0); + utils.deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + + if (bidderRequest.uspConsent !== undefined) { + utils.deepSetValue(request, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + + if (utils.deepAccess(validBidRequests[0], 'params.app')) { + const geo = utils.deepAccess(validBidRequests[0], 'params.app.geo'); + utils.deepSetValue(request, 'device.geo', geo); + const ifa = utils.deepAccess(validBidRequests[0], 'params.app.ifa') + utils.deepSetValue(request, 'device.ifa', ifa); + } + + utils.logInfo('[SMAATO] OpenRTB Request:', request); + return JSON.stringify(request); +} + +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: (bid) => { + return typeof bid.params === 'object' && + typeof bid.params.publisherId === 'string' && + typeof bid.params.adspaceId === 'string'; + }, + + /** + * 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) => { + utils.logInfo('[SMAATO] Client version:', CLIENT); + return { + method: 'POST', + url: validBidRequests[0].params.endpoint || SMAATO_ENDPOINT, + data: buildOpenRtbBidRequestPayload(validBidRequests, bidderRequest), + options: { + withCredentials: true, + crossOrigin: true, + } + }; + }, + /** + * 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: (serverResponse, bidRequest) => { + // response is empty (HTTP 204) + if (utils.isEmpty(serverResponse.body)) { + utils.logInfo('[SMAATO] Empty response body HTTP 204, no bids'); + return []; // no bids + } + + let serverResponseHeaders = serverResponse.headers; + const smtAdType = serverResponseHeaders.get('X-SMT-ADTYPE'); + + const smtExpires = serverResponseHeaders.get('X-SMT-Expires'); + let ttlSec = 300; + utils.logInfo('[SMAATO] Expires:', smtExpires); + if (smtExpires) { + ttlSec = Math.floor((smtExpires - Date.now()) / 1000); + } + + const res = serverResponse.body; + utils.logInfo('[SMAATO] OpenRTB Response:', res); + + var bids = []; + res.seatbid.forEach(sb => { + sb.bid.forEach(b => { + let resultingBid = { + requestId: b.impid, + cpm: b.price || 0, + width: b.w, + height: b.h, + ttl: ttlSec, + creativeId: b.crid, + dealId: b.dealid || null, + netRevenue: utils.deepAccess(b, 'ext.net', true), + currency: res.cur, + meta: { + advertiserDomains: b.adomain, + networkName: b.bidderName, + agencyId: sb.seat + } + }; + + switch (smtAdType) { + case 'Img': + resultingBid.ad = createImgAd(b.adm); + resultingBid.meta.mediaType = BANNER; + bids.push(resultingBid); + break; + case 'Richmedia': + resultingBid.ad = createRichmediaAd(b.adm); + resultingBid.meta.mediaType = BANNER; + bids.push(resultingBid); + break; + case 'Video': + resultingBid.vastXml = b.adm; + resultingBid.meta.mediaType = VIDEO; + bids.push(resultingBid); + break; + default: + utils.logInfo('[SMAATO] Invalid ad type:', smtAdType); + } + }); + }); + + utils.logInfo('[SMAATO] Prebid bids:', bids); + 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: (syncOptions, serverResponses, gdprConsent, uspConsent) => { + const syncs = [] + return syncs; + } +} +registerBidder(spec); + +const createImgAd = (adm) => { + const image = JSON.parse(adm).image; + + let clickEvent = ''; + image.clicktrackers.forEach(src => { + clickEvent += `fetch(decodeURIComponent('${encodeURIComponent(src)}'), {cache: 'no-cache'});`; + }) + + let markup = `
`; + + image.impressiontrackers.forEach(src => { + markup += ``; + }); + + return markup + '
'; +}; + +const createRichmediaAd = (adm) => { + const rich = JSON.parse(adm).richmedia; + let clickEvent = ''; + rich.clicktrackers.forEach(src => { + clickEvent += `fetch(decodeURIComponent('${encodeURIComponent(src)}'), {cache: 'no-cache'});`; + }) + + let markup = `
${rich.mediadata.content}`; + + rich.impressiontrackers.forEach(src => { + markup += ``; + }); + + return markup + '
'; +}; diff --git a/modules/smaatoBidAdapter.md b/modules/smaatoBidAdapter.md new file mode 100644 index 00000000000..d26d7ecf64e --- /dev/null +++ b/modules/smaatoBidAdapter.md @@ -0,0 +1,64 @@ +# Overview + +``` +Module Name: Smaato Bidder Adapter +Module Type: Bidder Adapter +Maintainer: prebid@smaato.com +``` + +# Description + +The Smaato adapter requires setup and approval from the Smaato team, even for existing Smaato publishers. Please reach out to your account team or prebid@smaato.com for more information. + +# Test Parameters + +For banner adunits: + +``` +var adUnits = [{ + "code": "banner-unit", + "mediaTypes": { + "banner": { + "sizes": [320, 50] + } + }, + "bids": [{ + "bidder": "smaato", + "params": { + "publisherId": "1100042525", + "adspaceId": "130563103" + } + }] +}]; +``` + +For video adunits: + +``` +var adUnits = [{ + "code": "video unit", + "mediaTypes": { + "video": { + "context": "instream", + "playerSize": [640, 480], + "mimes": ["video/mp4"], + "minduration": 5, + "maxduration": 30, + "startdelay": 0, + "linearity": 1, + "protocols": [7], + "skip": 1, + "skipmin": 5, + "api": [7], + "ext": {"rewarded": 0} + } + }, + "bids": [{ + "bidder": "smaato", + "params": { + "publisherId": "1100042525", + "adspaceId": "130563103" + } + }] +}]; +``` \ No newline at end of file diff --git a/modules/smartadserverBidAdapter.js b/modules/smartadserverBidAdapter.js index bff592383a4..97dd43fc5ba 100644 --- a/modules/smartadserverBidAdapter.js +++ b/modules/smartadserverBidAdapter.js @@ -9,6 +9,9 @@ import { import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { + createEidsArray +} from './userId/eids.js'; const BIDDER_CODE = 'smartadserver'; export const spec = { code: BIDDER_CODE, @@ -88,7 +91,7 @@ export const spec = { videoProtocol: bid.params.video.protocol, playerWidth: playerSize[0], playerHeight: playerSize[1], - adBreak: bid.params.video.startDelay || 0 + adBreak: bid.params.video.startDelay || 1 }; } else { return {}; @@ -99,6 +102,10 @@ export const spec = { payload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side } + if (bid && bid.userId) { + payload.eids = createEidsArray(bid.userId); + } + if (bidderRequest && bidderRequest.uspConsent) { payload.us_privacy = bidderRequest.uspConsent; } diff --git a/modules/smartxBidAdapter.js b/modules/smartxBidAdapter.js new file mode 100644 index 00000000000..4409e4e9dfb --- /dev/null +++ b/modules/smartxBidAdapter.js @@ -0,0 +1,392 @@ +import * as utils from '../src/utils.js'; +import { + Renderer +} from '../src/Renderer.js'; +import { + registerBidder +} from '../src/adapters/bidderFactory.js'; +import { + VIDEO +} from '../src/mediaTypes.js'; +const BIDDER_CODE = 'smartx'; +const URL = 'https://bid.sxp.smartclip.net/bid/1000'; +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [VIDEO], + /** + * Determines whether or not the given bid request is valid. + * From Prebid.js: isBidRequestValid - Verify the the AdUnits.bids, respond with true (valid) or false (invalid). + * + * @param {object} bid The bid to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + if (bid && typeof bid.params !== 'object') { + utils.logError(BIDDER_CODE + ': params is not defined or is incorrect in the bidder settings.'); + return false; + } + if (!utils.deepAccess(bid, 'mediaTypes.video')) { + utils.logError(BIDDER_CODE + ': mediaTypes.video is not present in the bidder settings.'); + return false; + } + const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize'); + if (!playerSize || !utils.isArray(playerSize)) { + utils.logError(BIDDER_CODE + ': mediaTypes.video.playerSize is not defined in the bidder settings.'); + return false; + } + if (!utils.getBidIdParameter('tagId', bid.params)) { + utils.logError(BIDDER_CODE + ': tagId is not present in bidder params'); + return false; + } + if (!utils.getBidIdParameter('publisherId', bid.params)) { + utils.logError(BIDDER_CODE + ': publisherId is not present in bidder params'); + return false; + } + if (!utils.getBidIdParameter('siteId', bid.params)) { + utils.logError(BIDDER_CODE + ': siteId is not present in bidder params'); + return false; + } + if (!utils.getBidIdParameter('bidfloor', bid.params)) { + utils.logError(BIDDER_CODE + ': bidfloor is not present in bidder params'); + return false; + } + if (!utils.getBidIdParameter('bidfloorcur', bid.params)) { + utils.logError(BIDDER_CODE + ': bidfloorcur is not present in bidder params'); + return false; + } + if (utils.deepAccess(bid, 'mediaTypes.video.context') === 'outstream') { + if (!utils.getBidIdParameter('outstream_options', bid.params)) { + utils.logError(BIDDER_CODE + ': outstream_options parameter is not defined'); + return false; + } + if (!utils.getBidIdParameter('slot', bid.params.outstream_options)) { + utils.logError(BIDDER_CODE + ': slot parameter is not defined in outstream_options object in the configuration'); + return false; + } + if (!utils.getBidIdParameter('outstream_function', bid.params)) { + utils.logMessage(BIDDER_CODE + ': outstream_function parameter is not defined. The default outstream renderer will be injected in the header. You can override the default SmartX outstream rendering by defining your own Outstream function using field outstream_function.'); + return true; + } + } + + return true; + }, + /** + * Make a server request from the list of BidRequests. + * from Prebid.js: buildRequests - Takes an array of valid bid requests, all of which are guaranteed to have passed the isBidRequestValid() test. + * + * @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 page = bidderRequest.refererInfo.referer; + const isPageSecure = !!page.match(/^https:/) + + const smartxRequests = bidRequests.map(function (bid) { + const tagId = utils.getBidIdParameter('tagId', bid.params); + const publisherId = utils.getBidIdParameter('publisherId', bid.params); + const bidfloor = utils.getBidIdParameter('bidfloor', bid.params); + const bidfloorcur = utils.getBidIdParameter('bidfloorcur', bid.params); + const siteId = utils.getBidIdParameter('siteId', bid.params); + const domain = utils.getBidIdParameter('domain', bid.params); + const cat = utils.getBidIdParameter('cat', bid.params); + let pubcid = null; + const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize'); + const contentWidth = playerSize[0][0]; + const contentHeight = playerSize[0][1]; + const secure = +(isPageSecure || (utils.getBidIdParameter('secure', bid.params) ? 1 : 0)); + const ext = { + sdk_name: 'Prebid 1+' + }; + const mimes = utils.getBidIdParameter('mimes', bid.params) || ['application/javascript', 'video/mp4', 'video/webm']; + const linearity = utils.getBidIdParameter('linearity', bid.params) || 1; + const minduration = utils.getBidIdParameter('minduration', bid.params) || 0; + const maxduration = utils.getBidIdParameter('maxduration', bid.params) || 500; + const startdelay = utils.getBidIdParameter('startdelay', bid.params) || 0; + const minbitrate = utils.getBidIdParameter('minbitrate', bid.params) || 0; + const maxbitrate = utils.getBidIdParameter('maxbitrate', bid.params) || 3500; + const delivery = utils.getBidIdParameter('delivery', bid.params) || [2]; + const pos = utils.getBidIdParameter('pos', bid.params) || 1; + const api = utils.getBidIdParameter('api', bid.params) || [2]; + const protocols = utils.getBidIdParameter('protocols', bid.params) || [2, 3, 5, 6]; + var contextcustom = utils.deepAccess(bid, 'mediaTypes.video.context'); + var placement = 1; + + if (contextcustom === 'outstream') { + placement = 3; + } + + let smartxReq = { + id: bid.bidId, + secure: secure, + bidfloor: bidfloor, + bidfloorcur: bidfloorcur, + video: { + w: contentWidth, + h: contentHeight, + mimes: mimes, + linearity: linearity, + minduration: minduration, + maxduration: maxduration, + startdelay: startdelay, + protocols: protocols, + minbitrate: minbitrate, + maxbitrate: maxbitrate, + delivery: delivery, + pos: pos, + placement: placement, + api: api, + ext: ext + }, + tagid: tagId, + ext: { + 'smart.bidpricetype': 1 + } + }; + + if (bid.crumbs && bid.crumbs.pubcid) { + pubcid = bid.crumbs.pubcid; + } + + const language = navigator.language ? 'language' : 'userLanguage'; + const device = { + h: screen.height, + w: screen.width, + dnt: utils.getDNT() ? 1 : 0, + language: navigator[language].split('-')[0], + make: navigator.vendor ? navigator.vendor : '', + ua: navigator.userAgent + }; + const at = utils.getBidIdParameter('at', bid.params) || 2; + const cur = utils.getBidIdParameter('cur', bid.params) || ['EUR']; + const requestPayload = { + id: utils.generateUUID(), + imp: smartxReq, + site: { + id: siteId, + page: page, + cat: cat, + content: 'content', + domain: domain, + publisher: { + id: publisherId + } + }, + device: device, + at: at, + cur: cur + }; + const userExt = {}; + + // Add GDPR flag and consent string + if (bidderRequest && bidderRequest.gdprConsent) { + userExt.consent = bidderRequest.gdprConsent.consentString; + if (typeof bidderRequest.gdprConsent.gdprApplies !== 'undefined') { + requestPayload.regs = { + ext: { + gdpr: (bidderRequest.gdprConsent.gdprApplies ? 1 : 0) + } + }; + } + } + + // Add common id if available + if (pubcid) { + userExt.fpc = pubcid; + } + + // Only add the user object if it's not empty + if (!utils.isEmpty(userExt)) { + requestPayload.user = { + ext: userExt + }; + } + + // Targeting + if (utils.getBidIdParameter('data', bid.params.user)) { + var targetingarr = []; + for (var i = 0; i < bid.params.user.data.length; i++) { + var isemq = (bid.params.user.data[i].name) || 'empty'; + if (isemq !== 'empty') { + var provider = bid.params.user.data[i].name; + var targetingstring = (bid.params.user.data[i].segment[0].value) || 'empty'; + targetingarr.push({ + id: provider, + name: provider, + segment: { + name: provider, + value: targetingstring, + } + }) + } + } + + requestPayload.user = { + ext: userExt, + data: targetingarr + } + } + + return { + method: 'POST', + url: URL, + data: requestPayload, + bidRequest: bidderRequest, + options: { + contentType: 'application/json', + customHeaders: { + 'x-openrtb-version': '2.3' + } + } + }; + }); + + return smartxRequests; + }, + /** + * 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) { + const bidResponses = []; + const serverResponseBody = serverResponse.body; + if (serverResponseBody && utils.isArray(serverResponseBody.seatbid)) { + utils._each(serverResponseBody.seatbid, function (bids) { + utils._each(bids.bid, function (smartxBid) { + let currentBidRequest = {}; + for (let i in bidderRequest.bidRequest.bids) { + if (smartxBid.impid == bidderRequest.bidRequest.bids[i].bidId) { + currentBidRequest = bidderRequest.bidRequest.bids[i]; + } + } + /** + * Make sure currency and price are the right ones + * TODO: what about the pre_market_bid partners sizes? + */ + utils._each(currentBidRequest.params.pre_market_bids, function (pmb) { + if (pmb.deal_id == smartxBid.id) { + smartxBid.price = pmb.price; + serverResponseBody.cur = pmb.currency; + } + }); + const bid = { + requestId: currentBidRequest.bidId, + currency: serverResponseBody.cur || 'USD', + cpm: smartxBid.price, + creativeId: smartxBid.crid || '', + ttl: 360, + netRevenue: true, + vastContent: smartxBid.adm, + vastXml: smartxBid.adm, + mediaType: VIDEO, + width: smartxBid.w, + height: smartxBid.h + }; + const context = utils.deepAccess(currentBidRequest, 'mediaTypes.video.context'); + if (context === 'outstream') { + const playersize = utils.deepAccess(currentBidRequest, 'mediaTypes.video.playerSize'); + const renderer = Renderer.install({ + id: 0, + url: '//', + config: { + adText: 'SmartX Outstream Video Ad via Prebid.js', + player_width: playersize[0][0], + player_height: playersize[0][1], + content_page_url: utils.deepAccess(bidderRequest, 'data.site.page'), + ad_mute: +!!utils.deepAccess(currentBidRequest, 'params.ad_mute'), + hide_skin: +!!utils.deepAccess(currentBidRequest, 'params.hide_skin'), + outstream_options: utils.deepAccess(currentBidRequest, 'params.outstream_options'), + outstream_function: utils.deepAccess(currentBidRequest, 'params.outstream_function') + } + }); + try { + renderer.setRender(outstreamRender); + renderer.setEventHandlers({ + impression: function impression() { + return utils.logMessage('SmartX outstream video impression event'); + }, + loaded: function loaded() { + return utils.logMessage('SmartX outstream video loaded event'); + }, + ended: function ended() { + utils.logMessage('SmartX outstream renderer video event'); + } + }); + } catch (err) { + utils.logWarn('Prebid Error calling setRender or setEventHandlers on renderer', err); + } + bid.renderer = renderer; + } + bidResponses.push(bid); + }) + }); + } + return bidResponses; + } +} + +function createOutstreamScript(bid) { + // const slot = utils.getBidIdParameter('slot', bid.renderer.config.outstream_options); + utils.logMessage('[SMARTX][renderer] Handle SmartX outstream renderer'); + const elementId = bid.adUnitCode; + let smartPlayObj = { + minAdWidth: 290, + maxAdWidth: 900, + elementLocator: { + allowInViewport: false, + minimumElementWidth: 290, + scanPixelsBelowViewport: 800 + }, + onStartCallback: function (m, n) { + try { + window.sc_smartIntxtStart(n); + } catch (f) {} + }, + onCappedCallback: function (m, n) { + try { + window.sc_smartIntxtNoad(n); + } catch (f) {} + }, + onEndCallback: function (m, n) { + try { + window.sc_smartIntxtEnd(n); + } catch (f) {} + }, + }; + smartPlayObj.adResponse = bid.vastContent; + const script = window.document.createElement('script'); + script.type = 'text/javascript'; + script.async = 'true'; + script.src = 'https://dco.smartclip.net/?plc=7777777'; + script.onload = script.onreadystatechange = function () { + var rs = this.readyState; + if (rs && rs != 'complete' && rs != 'loaded') return; + try { + window.SmartPlay(elementId, smartPlayObj); + } catch (e) { + utils.logError('error caught : ' + e); + } + }; + return script; +} + +function outstreamRender(bid) { + const script = createOutstreamScript(bid); + if (bid.renderer.config.outstream_function != null && typeof bid.renderer.config.outstream_function === 'function') { + bid.renderer.config.outstream_function(bid, script); + } else { + try { + const slot = utils.getBidIdParameter('slot', bid.renderer.config.outstream_options); + if (slot && window.document.getElementById(slot)) { + window.document.getElementById(slot).appendChild(script); + } else { + window.document.getElementsByTagName('head')[0].appendChild(script); + } + } catch (err) { + utils.logError('[SMARTX][renderer] Error:' + err.message) + } + } +} +registerBidder(spec); diff --git a/modules/smartxBidAdapter.md b/modules/smartxBidAdapter.md new file mode 100644 index 00000000000..a53af839e2b --- /dev/null +++ b/modules/smartxBidAdapter.md @@ -0,0 +1,159 @@ +# Overview + +``` +Module Name: smartclip Bidder Adapter +Module Type: Bidder Adapter +Maintainer: adtech@smartclip.tv +``` + +# Description + +Connect to smartx for bids. + +This adapter requires setup and approval from the smartclip team. + +# Test Parameters - Use case #1 - Out-Stream example and default rendering options +``` + var adUnits = [{ + code: 'video1', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 360] + } + }, + bids: [{ + bidder: 'smartx', + params: { + tagId: 'Nu68JuOWAvrbzoyrOR9a7A', + publisherId: '11986', + siteId: '22860', + bidfloor: 0.3, + bidfloorcur: "EUR", + at: 2, + cur: ["EUR"], + outstream_options: { + slot: 'video1' + }, + } + }], + }]; +``` + +# Test Parameters - Use case #2 - Out-Stream with targeting example and default rendering options +``` + var adUnits = [{ + code: 'video1', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 360] + } + }, + bids: [{ + bidder: 'smartx', + params: { + tagId: 'Nu68JuOWAvrbzoyrOR9a7A', + publisherId: '11986', + siteId: '22860', + bidfloor: 0.3, + bidfloorcur: "EUR", + at: 2, + cur: ["EUR"], + outstream_options: { + slot: 'video1' + }, + user: { + data: [{ + id: 'emq', + name: 'emq', + segment: [{ + id: 'emq', + name: 'emq', + value: 'e0:k14:e24' + }] + }, { + id: 'gs', + name: 'gs', + segment: [{ + id: 'gs', + name: 'gs', + value: 'tone_of_voice_dislike:tone_of_voice_negative:gs_health' + }] + }] + } + } + }] + }]; +``` + +# Test Parameters - Use case #3 - In-Stream example and default rendering options +``` + var adUnits = [{ + code: 'video1', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 360] + } + }, + bids: [{ + bidder: 'smartx', + params: { + tagId: 'Nu68JuOWAvrbzoyrOR9a7A', + publisherId: '11986', + siteId: '22860', + bidfloor: 0.3, + bidfloorcur: "EUR", + at: 2, + cur: ["EUR"] + } + }], + }]; +``` + +# Test Parameters - Use case #4 - In-Stream with targeting example and default rendering options +``` + var adUnits = [{ + code: 'video1', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 360] + } + }, + bids: [{ + bidder: 'smartx', + params: { + tagId: 'Nu68JuOWAvrbzoyrOR9a7A', + publisherId: '11986', + siteId: '22860', + bidfloor: 0.3, + bidfloorcur: "EUR", + at: 2, + cur: ["EUR"], + user: { + data: [{ + id: 'emq', + name: 'emq', + segment: [{ + id: 'emq', + name: 'emq', + value: 'e0:k14:e24' + }] + }, + { + id: 'gs', + name: 'gs', + segment: [{ + id: 'gs', + name: 'gs', + value: 'tone_of_voice_dislike:tone_of_voice_negative:gs_health' + }] + } + ] + } + } + }], + }]; +``` \ No newline at end of file diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index ee201a72bf2..a55992cec22 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -8,7 +8,6 @@ import { userSync } from '../src/userSync.js'; const BIDDER_CODE = 'sonobi'; const STR_ENDPOINT = 'https://apex.go.sonobi.com/trinity.json'; const PAGEVIEW_ID = generateUUID(); -const SONOBI_DIGITRUST_KEY = 'fhnS5drwmH'; const OUTSTREAM_REDNERER_URL = 'https://mtrx.go.sonobi.com/sbi_outstream_renderer.js'; export const spec = { @@ -114,13 +113,6 @@ export const spec = { } } - const digitrust = _getDigiTrustObject(SONOBI_DIGITRUST_KEY); - - if (digitrust) { - payload.digid = digitrust.id; - payload.digkeyv = digitrust.keyv; - } - if (validBidRequests[0].schain) { payload.schain = JSON.stringify(validBidRequests[0].schain) } @@ -336,20 +328,6 @@ export function _getPlatform(context = window) { return 'desktop'; } -// https://github.com/digi-trust/dt-cdn/wiki/Integration-Guide -function _getDigiTrustObject(key) { - function getDigiTrustId() { - let digiTrustUser = window.DigiTrust && (config.getConfig('digiTrustId') || window.DigiTrust.getUser({member: key})); - return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || null; - } - let digiTrustId = getDigiTrustId(); - // Verify there is an ID and this user has not opted out - if (!digiTrustId || (digiTrustId.privacy && digiTrustId.privacy.optout)) { - return null; - } - return digiTrustId; -} - function newRenderer(adUnitCode, bid, rendererOptions = {}) { const renderer = Renderer.install({ id: bid.aid, diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index 98c8c8e3b33..f3260668b74 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -25,18 +25,13 @@ export const spec = { let sovrnImps = []; let iv; let schain; - let digitrust; + let unifiedID; utils._each(bidReqs, function (bid) { - if (!digitrust) { - const bidRequestDigitrust = utils.deepAccess(bid, 'userId.digitrustid.data'); - if (bidRequestDigitrust && (!bidRequestDigitrust.privacy || !bidRequestDigitrust.privacy.optout)) { - digitrust = { - id: bidRequestDigitrust.id, - keyv: bidRequestDigitrust.keyv - } - } + if (!unifiedID) { + unifiedID = utils.deepAccess(bid, 'userId.tdid'); } + if (bid.schain) { schain = schain || bid.schain; } @@ -47,6 +42,7 @@ export const spec = { bidSizes = bidSizes.filter(size => utils.isArray(size)) const processedSizes = bidSizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)})) sovrnImps.push({ + adunitcode: bid.adUnitCode, id: bid.bidId, banner: { format: processedSizes, @@ -88,15 +84,22 @@ export const spec = { utils.deepSetValue(sovrnBidReq, 'regs.ext.us_privacy', bidderRequest.uspConsent); } - if (digitrust) { - utils.deepSetValue(sovrnBidReq, 'user.ext.digitrust', { - id: digitrust.id, - keyv: digitrust.keyv - }) + if (unifiedID) { + const idArray = [{ + source: 'adserver.org', + uids: [ + { + id: unifiedID, + ext: { + rtiPartner: 'TDID' + } + } + ] + }] + utils.deepSetValue(sovrnBidReq, 'user.ext.eids', idArray) } - let url = `https://ap.lijit.com/rtb/bid?` + - `src=$$REPO_AND_VERSION$$`; + let url = `https://ap.lijit.com/rtb/bid?src=$$REPO_AND_VERSION$$`; if (iv) url += `&iv=${iv}`; return { @@ -176,7 +179,6 @@ export const spec = { .forEach(url => tracks.push({ type: 'image', url })) } } - return tracks } catch (e) { return [] diff --git a/modules/spotxBidAdapter.js b/modules/spotxBidAdapter.js index 210153548b2..6104fce1d97 100644 --- a/modules/spotxBidAdapter.js +++ b/modules/spotxBidAdapter.js @@ -1,4 +1,5 @@ import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; import { Renderer } from '../src/Renderer.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { VIDEO } from '../src/mediaTypes.js'; @@ -19,7 +20,7 @@ export const spec = { * From Prebid.js: isBidRequestValid - Verify the the AdUnits.bids, respond with true (valid) or false (invalid). * * @param {object} bid The bid to validate. - * @return boolean True if this is a valid bid, and false otherwise. + * @return {boolean} True if this is a valid bid, and false otherwise. */ isBidRequestValid: function(bid) { if (bid && typeof bid.params !== 'object') { @@ -64,14 +65,24 @@ export const spec = { * from Prebid.js: buildRequests - Takes an array of valid bid requests, all of which are guaranteed to have passed the isBidRequestValid() test. * * @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. + * @param {object} bidderRequest - The master bidRequest object. + * @return {ServerRequest} Info describing the request to the server. */ buildRequests: function(bidRequests, bidderRequest) { - const page = bidderRequest.refererInfo.referer; - const isPageSecure = !!page.match(/^https:/) + const referer = bidderRequest.refererInfo.referer; + const isPageSecure = !!referer.match(/^https:/); const siteId = ''; const spotxRequests = bidRequests.map(function(bid) { + let page; + if (utils.getBidIdParameter('page', bid.params)) { + page = utils.getBidIdParameter('page', bid.params); + } else if (config.getConfig('pageUrl')) { + page = config.getConfig('pageUrl'); + } else { + page = referer; + } + const channelId = utils.getBidIdParameter('channel_id', bid.params); let pubcid = null; @@ -160,6 +171,22 @@ export const spec = { spotxReq.video.startdelay = 0 + Boolean(utils.getBidIdParameter('start_delay', bid.params)); } + if (utils.getBidIdParameter('min_duration', bid.params) != '') { + spotxReq.video.minduration = utils.getBidIdParameter('min_duration', bid.params); + } + + if (utils.getBidIdParameter('max_duration', bid.params) != '') { + spotxReq.video.maxduration = utils.getBidIdParameter('max_duration', bid.params); + } + + if (utils.getBidIdParameter('placement_type', bid.params) != '') { + spotxReq.video.ext.placement = utils.getBidIdParameter('placement_type', bid.params); + } + + if (utils.getBidIdParameter('position', bid.params) != '') { + spotxReq.video.ext.pos = utils.getBidIdParameter('position', bid.params); + } + if (bid.crumbs && bid.crumbs.pubcid) { pubcid = bid.crumbs.pubcid; } @@ -212,14 +239,15 @@ export const spec = { } // ID5 fied - if (bid && bid.userId && bid.userId.id5id) { + if (utils.deepAccess(bid, 'userId.id5id.uid')) { userExt.eids = userExt.eids || []; userExt.eids.push( { source: 'id5-sync.com', uids: [{ - id: bid.userId.id5id - }] + id: bid.userId.id5id.uid + }], + ext: bid.userId.id5id.ext || {} } ) } @@ -304,6 +332,7 @@ export const spec = { currency: serverResponseBody.cur || 'USD', cpm: spotxBid.price, creativeId: spotxBid.crid || '', + dealId: spotxBid.dealid || '', ttl: 360, netRevenue: true, channel_id: serverResponseBody.id, @@ -315,6 +344,11 @@ export const spec = { height: spotxBid.h }; + bid.meta = bid.meta || {}; + if (spotxBid && spotxBid.adomain && spotxBid.adomain.length > 0) { + bid.meta.advertiserDomains = spotxBid.adomain; + } + const context1 = utils.deepAccess(currentBidRequest, 'mediaTypes.video.context'); const context2 = utils.deepAccess(currentBidRequest, 'params.ad_unit'); if (context1 == 'outstream' || context2 == 'outstream') { @@ -376,7 +410,7 @@ function createOutstreamScript(bid) { utils.logMessage('[SPOTX][renderer] Default beahavior'); if (utils.getBidIdParameter('ad_mute', bid.renderer.config.outstream_options)) { - dataSpotXParams['data-spotx_ad_mute'] = '0'; + dataSpotXParams['data-spotx_ad_mute'] = '1'; } dataSpotXParams['data-spotx_collapse'] = '0'; dataSpotXParams['data-spotx_autoplay'] = '1'; @@ -413,11 +447,11 @@ function createOutstreamScript(bid) { const customOverride = utils.getBidIdParameter('custom_override', bid.renderer.config.outstream_options); if (customOverride && utils.isPlainObject(customOverride)) { - utils.logMessage('[SPOTX][renderer] Custom beahavior.'); + utils.logMessage('[SPOTX][renderer] Custom behavior.'); for (let name in customOverride) { if (customOverride.hasOwnProperty(name)) { if (name === 'channel_id' || name === 'vast_url' || name === 'content_page_url' || name === 'ad_unit') { - utils.logWarn('[SPOTX][renderer] Custom beahavior: following option cannot be overrided: ' + name); + utils.logWarn('[SPOTX][renderer] Custom behavior: following option cannot be overridden: ' + name); } else { dataSpotXParams['data-spotx_' + name] = customOverride[name]; } diff --git a/modules/sspBCAdapter.js b/modules/sspBCAdapter.js new file mode 100644 index 00000000000..ef89fb08449 --- /dev/null +++ b/modules/sspBCAdapter.js @@ -0,0 +1,319 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'sspBC'; +const BIDDER_URL = 'https://ssp.wp.pl/bidder/'; +const SYNC_URL = 'https://ssp.wp.pl/bidder/usersync'; +const TMAX = 450; +const BIDDER_VERSION = '4.5'; +const W = window; +const { navigator } = W; + +const cookieSupport = () => { + const isSafari = /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent); + const useCookies = navigator.cookieEnabled || !!document.cookie.length; + + return !isSafari && useCookies; +}; + +const applyClientHints = ortbRequest => { + const connection = navigator.connection || false; + const viewport = W.visualViewport || false; + const segments = []; + const hints = { + 'CH-Ect': connection.effectiveType, + 'CH-Rtt': connection.rtt, + 'CH-SaveData': connection.saveData, + 'CH-Downlink': connection.downlink, + 'CH-DeviceMemory': navigator.deviceMemory, + 'CH-Dpr': W.devicePixelRatio, + 'CH-ViewportWidth': viewport.width, + }; + + Object.keys(hints).forEach(key => { + const hint = hints[key]; + + if (hint) { + segments.push({ + name: key, + value: hint.toString(), + }); + } + }); + const data = [ + { + id: '12', + name: 'NetInfo', + segment: segments, + }]; + + ortbRequest.user = Object.assign(ortbRequest.user, { data }); +}; + +function applyGdpr(bidderRequest, ortbRequest) { + if (bidderRequest && bidderRequest.gdprConsent) { + ortbRequest.regs = Object.assign(ortbRequest.regs, { '[ortb_extensions.gdpr]': bidderRequest.gdprConsent.gdprApplies ? 1 : 0 }); + ortbRequest.user = Object.assign(ortbRequest.user, { '[ortb_extensions.consent]': bidderRequest.gdprConsent.consentString }); + } +} + +function setOnAny(collection, key) { + for (let i = 0, result; i < collection.length; i++) { + result = utils.deepAccess(collection[i], key); + + if (result) { + return result; + } + } +} + +/** + * @param {object} slot Ad Unit Params by Prebid + * @returns {object} Banner by OpenRTB 2.5 §3.2.6 + */ +function mapBanner(slot) { + if (slot.mediaType === 'banner' || + utils.deepAccess(slot, 'mediaTypes.banner') || + (!slot.mediaType && !slot.mediaTypes)) { + const format = slot.sizes.map(size => ({ + w: size[0], + h: size[1], + })); + + // override - tylko 1szy wymiar + // format = format.slice(0, 1); + return { + format, + id: slot.bidId, + }; + } +} + +function mapImpression(slot) { + const imp = { + id: slot.params.id, + banner: mapBanner(slot), + /* native: mapNative(slot), */ + tagid: slot.params.id, + }; + + const bidfloor = parseFloat(slot.params.bidfloor); + + if (bidfloor) { + imp.bidfloor = bidfloor; + } + + return imp; +} + +function renderCreative(site, auctionId, bid, seat, request) { + let gam; + + const mcad = { + id: auctionId, + seat, + seatbid: [{ + bid: [bid], + }], + }; + + const mcbase = btoa(encodeURI(JSON.stringify(mcad))); + + if (bid.adm) { + // parse adm for gam config + try { + gam = JSON.parse(bid.adm).gam; + + if (!gam || !Object.keys(gam).length) { + gam = undefined; + } else { + gam.namedSizes = ['fluid']; + gam.div = 'div-gpt-ad-x01'; + gam.targeting = Object.assign(gam.targeting || {}, { + OAS_retarg: '0', + PREBID_ON: '1', + emptygaf: '0', + }); + } + + if (gam && !gam.targeting) { + gam.targeting = {}; + } + } catch (err) { + utils.logWarn('Could not parse adm data', bid.adm); + } + } + + let adcode = ` + + + + + + + +
+ + + `; + + return adcode; +} + +const spec = { + code: BIDDER_CODE, + aliases: [], + supportedMediaTypes: [BANNER], + isBidRequestValid(bid) { + if (bid.params && bid.params.siteId && bid.params.id) { + return true; + } + + return false; + }, + buildRequests(validBidRequests, bidderRequest) { + if ((!validBidRequests) || (validBidRequests.length < 1)) { + return false; + } + + const siteId = setOnAny(validBidRequests, 'params.siteId'); + const page = setOnAny(validBidRequests, 'params.page') || bidderRequest.refererInfo.referer; + const domain = setOnAny(validBidRequests, 'params.domain') || utils.parseUrl(page).hostname; + const tmax = setOnAny(validBidRequests, 'params.tmax') ? parseInt(setOnAny(validBidRequests, 'params.tmax'), 10) : TMAX; + const pbver = '$prebid.version$'; + const testMode = setOnAny(validBidRequests, 'params.test') ? 1 : undefined; + + let ref; + + try { + if (W.self === W.top && document.referrer) { ref = document.referrer; } + } catch (e) { + } + + const payload = { + id: bidderRequest.auctionId, + site: { id: siteId, page, domain, ref }, + imp: validBidRequests.map(slot => mapImpression(slot)), + tmax, + user: {}, + regs: {}, + test: testMode, + }; + + applyGdpr(bidderRequest, payload); + applyClientHints(payload); + + return { + method: 'POST', + url: BIDDER_URL + '?cs=' + cookieSupport() + '&bdver=' + BIDDER_VERSION + '&pbver=' + pbver + '&inver=0', + data: JSON.stringify(payload), + bidderRequest, + }; + }, + + interpretResponse(serverResponse, request) { + const response = serverResponse.body; + const bids = []; + let site = JSON.parse(request.data).site; // get page and referer data from request + site.sn = response.sn || 'mc_adapter'; // WPM site name (wp_sn) + let seat; + + if (response.seatbid !== undefined) { + response.seatbid.forEach(seatbid => { + seat = seatbid.seat; + seatbid.bid.forEach(serverBid => { + const bidRequest = request.bidderRequest.bids.filter(b => b.params.id === serverBid.impid)[0]; + + if (bidRequest) { + const bidFloor = bidRequest.params.bidFloor || 0; + const bidCpm = bidRequest.params.flatCpm; + + if (!serverBid.gam && bidRequest.params.gam) { + // build GAM config + serverBid.gam = JSON.stringify({ + placement: bidRequest.params.gam, + multiplier: 1, + floor: bidRequest.params.gamFloor, + ceil: 100, + namedSizes: ['fluid'], + div: 'div-gpt-ad-x01', + targeting: { + OAS_retarg: '0', + PREBID_ON: '1', + DFPHASH: '', + emptygaf: '0', + }, + }); + } + + const bid = { + requestId: bidRequest.bidId, + creativeId: serverBid.crid || 'mcad_' + request.bidderRequest.auctionId + '_' + request.bidderRequest.params.id, + cpm: bidCpm || serverBid.price, + currency: response.cur, + ttl: serverBid.exp || 300, + width: serverBid.w, + height: serverBid.h, + bidderCode: BIDDER_CODE, + mediaType: 'banner', + meta: { + advertiserDomains: serverBid.adomain, + }, + netRevenue: true, + ad: renderCreative(site, response.id, serverBid, seat, request.bidderRequest), + }; + + if (bid.cpm > 0) { + if (bid.cpm >= bidFloor) { + bids.push(bid); + } else { + utils.logWarn('Discarding bid due to bidFloor setting', bid.cpm, bidFloor); + } + } + } else { + utils.logWarn('Discarding response - no matching request', serverBid.impid); + } + }); + }); + } + + return bids; + }, + getUserSyncs(syncOptions) { + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: SYNC_URL, + }]; + } + utils.logWarn('sspBC adapter requires iframe based user sync.'); + }, + onTimeout() { + }, +}; + +registerBidder(spec); + +export { + spec, +}; diff --git a/modules/sspBCAdapter.md b/modules/sspBCAdapter.md new file mode 100644 index 00000000000..645f41fcdc1 --- /dev/null +++ b/modules/sspBCAdapter.md @@ -0,0 +1,40 @@ +# Overview + +Module Name: sspBC Bidder Adapter +Module Type: Bidder Adapter +Maintainer: wojciech.bialy@grupawp.pl + +# Description + +Module that connects to Wirtualna Polska Media header bidding endpoint to fetch bids. +Only banner format is supported. +Supported currencies: USD, EUR, PLN + + +Required parameters: + + +# Test Parameters +``` +var adUnits = [ + // Banner adUnit + { + code: 'banner-div', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]] + } + }, + bids: [{ + bidder: 'sspBC', + params: { + id: '006', // required + siteId: '235911', // required + domain: 'somesite.pl', // optional + page: 'somesite.pl/somepage.html', // optional + tmax: 250 // optional + } + }] + } +]; +``` diff --git a/modules/sublimeBidAdapter.js b/modules/sublimeBidAdapter.js index 1f8cb59f442..e9f7cf19033 100644 --- a/modules/sublimeBidAdapter.js +++ b/modules/sublimeBidAdapter.js @@ -9,7 +9,7 @@ const DEFAULT_CURRENCY = 'EUR'; const DEFAULT_PROTOCOL = 'https'; const DEFAULT_TTL = 600; const SUBLIME_ANTENNA = 'antenna.ayads.co'; -const SUBLIME_VERSION = '0.5.2'; +const SUBLIME_VERSION = '0.6.0'; /** * Debug log message @@ -23,7 +23,8 @@ export function log(msg, obj) { // Default state export const state = { zoneId: '', - transactionId: '' + transactionId: '', + notifyId: '' }; /** @@ -47,8 +48,8 @@ export function sendEvent(eventName) { z: state.zoneId, e: eventName, src: 'pa', - puid: state.transactionId, - trId: state.transactionId, + puid: state.transactionId || state.notifyId, + trId: state.transactionId || state.notifyId, ver: SUBLIME_VERSION, }; @@ -101,6 +102,7 @@ function buildRequests(validBidRequests, bidderRequest) { setState({ transactionId: bid.transactionId, + notifyId: bid.params.notifyId, zoneId: bid.params.zoneId, debug: bid.params.debug || false, }); @@ -117,6 +119,7 @@ function buildRequests(validBidRequests, bidderRequest) { h: size[1], })), transactionId: bid.transactionId, + notifyId: bid.params.notifyId, zoneId: bid.params.zoneId, }; diff --git a/modules/sublimeBidAdapter.md b/modules/sublimeBidAdapter.md index e57f4a1fdb0..5cd1c95b682 100644 --- a/modules/sublimeBidAdapter.md +++ b/modules/sublimeBidAdapter.md @@ -9,7 +9,7 @@ Maintainer: pbjs@sublimeskinz.com # Description Connects to Sublime for bids. -Sublime bid adapter supports Skinz and M-Skinz formats. +Sublime bid adapter supports Skinz. # Nota Bene @@ -53,10 +53,13 @@ var adUnits = [{ bids: [{ bidder: 'sublime', params: { - zoneId: + zoneId: , + notifyId: } }] }]; ``` -Where you replace `` by your Sublime Zone id +Where you replace: +- `` by your Sublime Zone id; +- `` by your Sublime Notify id diff --git a/modules/synacormediaBidAdapter.js b/modules/synacormediaBidAdapter.js index 2ca2aeeae82..e0d017a6c51 100644 --- a/modules/synacormediaBidAdapter.js +++ b/modules/synacormediaBidAdapter.js @@ -1,12 +1,13 @@ 'use strict'; -import { getAdUnitSizes, logWarn } from '../src/utils.js'; +import { getAdUnitSizes, logWarn, deepSetValue } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import includes from 'core-js-pure/features/array/includes.js'; import {config} from '../src/config.js'; -const BID_HOST = 'https://prebid.technoratimedia.com'; +const BID_SCHEME = 'https://'; +const BID_DOMAIN = 'technoratimedia.com'; const USER_SYNC_HOST = 'https://ad-cdn.technoratimedia.com'; const VIDEO_PARAMS = [ 'minduration', 'maxduration', 'startdelay', 'placement', 'linearity', 'mimes', 'protocols', 'api' ]; const BLOCKED_AD_SIZES = [ @@ -71,44 +72,29 @@ export const spec = { pos = 0; } const videoOrBannerKey = this.isVideoBid(bid) ? 'video' : 'banner'; - getAdUnitSizes(bid) - .filter(size => BLOCKED_AD_SIZES.indexOf(size.join('x')) === -1) - .forEach((size, i) => { - if (!size || size.length != 2) { - return; - } - const size0 = size[0]; - const size1 = size[1]; - const imp = { - id: `${videoOrBannerKey.substring(0, 1)}${bid.bidId}-${size0}x${size1}`, - tagid: placementId - }; - if (bidFloor !== null && !isNaN(bidFloor)) { - imp.bidfloor = bidFloor; - } + const adSizes = getAdUnitSizes(bid) + .filter(size => BLOCKED_AD_SIZES.indexOf(size.join('x')) === -1); - const videoOrBannerValue = { - w: size0, - h: size1, - pos - }; - if (videoOrBannerKey === 'video') { - if (bid.mediaTypes.video) { - this.setValidVideoParams(bid.mediaTypes.video, bid.params.video); - } - if (bid.params.video) { - this.setValidVideoParams(bid.params.video, videoOrBannerValue); - } - } - imp[videoOrBannerKey] = videoOrBannerValue; - openRtbBidRequest.imp.push(imp); - }); + let imps = []; + if (videoOrBannerKey === 'banner') { + imps = this.buildBannerImpressions(adSizes, bid, placementId, pos, bidFloor, videoOrBannerKey); + } else if (videoOrBannerKey === 'video') { + imps = this.buildVideoImpressions(adSizes, bid, placementId, pos, bidFloor, videoOrBannerKey); + } + if (imps.length > 0) { + imps.forEach(i => openRtbBidRequest.imp.push(i)); + } }); + // CCPA + if (bidderRequest && bidderRequest.uspConsent) { + deepSetValue(openRtbBidRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + if (openRtbBidRequest.imp.length && seatId) { return { method: 'POST', - url: `${BID_HOST}/openrtb/bids/${seatId}?src=$$REPO_AND_VERSION$$`, + url: `${BID_SCHEME}${seatId}.${BID_DOMAIN}/openrtb/bids/${seatId}?src=$$REPO_AND_VERSION$$`, data: openRtbBidRequest, options: { contentType: 'application/json', @@ -118,12 +104,76 @@ export const spec = { } }, + buildBannerImpressions: function(adSizes, bid, placementId, pos, bidFloor, videoOrBannerKey) { + let format = []; + let imps = []; + adSizes.forEach((size, i) => { + if (!size || size.length !== 2) { + return; + } + + format.push({ + w: size[0], + h: size[1], + }); + }); + + if (format.length > 0) { + const imp = { + id: `${videoOrBannerKey.substring(0, 1)}${bid.bidId}`, + banner: { + format, + pos + }, + tagid: placementId, + }; + if (bidFloor !== null && !isNaN(bidFloor)) { + imp.bidfloor = bidFloor; + } + imps.push(imp); + } + return imps; + }, + + buildVideoImpressions: function(adSizes, bid, placementId, pos, bidFloor, videoOrBannerKey) { + let imps = []; + adSizes.forEach((size, i) => { + if (!size || size.length != 2) { + return; + } + const size0 = size[0]; + const size1 = size[1]; + const imp = { + id: `${videoOrBannerKey.substring(0, 1)}${bid.bidId}-${size0}x${size1}`, + tagid: placementId + }; + if (bidFloor !== null && !isNaN(bidFloor)) { + imp.bidfloor = bidFloor; + } + + const videoOrBannerValue = { + w: size0, + h: size1, + pos + }; + if (bid.mediaTypes.video) { + this.setValidVideoParams(bid.mediaTypes.video, bid.params.video); + } + if (bid.params.video) { + this.setValidVideoParams(bid.params.video, videoOrBannerValue); + } + imp[videoOrBannerKey] = videoOrBannerValue; + imps.push(imp); + }); + return imps; + }, + setValidVideoParams: function (sourceObj, destObj) { Object.keys(sourceObj) .filter(param => includes(VIDEO_PARAMS, param) && sourceObj[param] !== null && (!isNaN(parseInt(sourceObj[param], 10)) || !(sourceObj[param].length < 1))) .forEach(param => destObj[param] = Array.isArray(sourceObj[param]) ? sourceObj[param] : parseInt(sourceObj[param], 10)); }, - interpretResponse: function(serverResponse) { + interpretResponse: function(serverResponse, bidRequest) { const updateMacros = (bid, r) => { return r ? r.replace(/\${AUCTION_PRICE}/g, bid.price) : r; }; @@ -140,8 +190,33 @@ export const spec = { seatbid.bid.forEach(bid => { const creative = updateMacros(bid, bid.adm); const nurl = updateMacros(bid, bid.nurl); - const [, impType, impid, width, height] = bid.impid.match(/^([vb])(.*)-(.*)x(.*)$/); - const isVideo = impType == 'v'; + const [, impType, impid] = bid.impid.match(/^([vb])([\w\d]+)/); + let height = bid.h; + let width = bid.w; + const isVideo = impType === 'v'; + const isBanner = impType === 'b'; + if ((!height || !width) && bidRequest.data && bidRequest.data.imp && bidRequest.data.imp.length > 0) { + bidRequest.data.imp.forEach(req => { + if (bid.impid === req.id) { + if (isVideo) { + height = req.video.h; + width = req.video.w; + } else if (isBanner) { + let bannerHeight = 1; + let bannerWidth = 1; + if (req.banner.format && req.banner.format.length > 0) { + bannerHeight = req.banner.format[0].h; + bannerWidth = req.banner.format[0].w; + } + height = bannerHeight; + width = bannerWidth; + } else { + height = 1; + width = 1; + } + } + }); + } const bidObj = { requestId: impid, adId: bid.id.replace(/~/g, '-'), diff --git a/modules/synacormediaBidAdapter.md b/modules/synacormediaBidAdapter.md index 857cf15d240..fd71f07b3a3 100644 --- a/modules/synacormediaBidAdapter.md +++ b/modules/synacormediaBidAdapter.md @@ -42,8 +42,10 @@ https://track.technoratimedia.com/openrtb/tags?ID=%%PATTERN:hb_cache_id_synacorm code: 'test-div2', mediaTypes: { video: { - context: 'instream', - playerSize: [[300, 250]], + context: 'instream', + playerSize: [ + [300, 250] + ], } }, bids: [{ diff --git a/modules/teadsBidAdapter.js b/modules/teadsBidAdapter.js index 38c261745c7..08ae1854669 100644 --- a/modules/teadsBidAdapter.js +++ b/modules/teadsBidAdapter.js @@ -41,6 +41,9 @@ export const spec = { const bids = validBidRequests.map(buildRequestObject); const payload = { referrer: getReferrerInfo(bidderRequest), + pageReferrer: document.referrer, + networkBandwidth: getConnectionDownLink(window.navigator), + timeToFirstByte: getTimeToFirstByte(window), data: bids, deviceWidth: screen.width, hb_version: '$prebid.version$' @@ -99,6 +102,9 @@ export const spec = { creativeId: bid.creativeId, placementId: bid.placementId }; + if (bid.dealId) { + bidResponse.dealId = bid.dealId + } bidResponses.push(bidResponse); }); } @@ -114,6 +120,39 @@ function getReferrerInfo(bidderRequest) { return ref; } +function getConnectionDownLink(nav) { + return nav && nav.connection && nav.connection.downlink >= 0 ? nav.connection.downlink.toString() : ''; +} + +function getTimeToFirstByte(win) { + const performance = win.performance || win.webkitPerformance || win.msPerformance || win.mozPerformance; + + const ttfbWithTimingV2 = performance && + typeof performance.getEntriesByType === 'function' && + Object.prototype.toString.call(performance.getEntriesByType) === '[object Function]' && + performance.getEntriesByType('navigation')[0] && + performance.getEntriesByType('navigation')[0].responseStart && + performance.getEntriesByType('navigation')[0].requestStart && + performance.getEntriesByType('navigation')[0].responseStart >= 0 && + performance.getEntriesByType('navigation')[0].requestStart >= 0 && + Math.round( + performance.getEntriesByType('navigation')[0].responseStart - performance.getEntriesByType('navigation')[0].requestStart + ); + + if (ttfbWithTimingV2) { + return ttfbWithTimingV2.toString(); + } + + const ttfbWithTimingV1 = performance && + performance.timing.responseStart && + performance.timing.requestStart && + performance.timing.responseStart >= 0 && + performance.timing.requestStart >= 0 && + performance.timing.responseStart - performance.timing.requestStart; + + return ttfbWithTimingV1 ? ttfbWithTimingV1.toString() : ''; +} + function findGdprStatus(gdprApplies, gdprData, apiVersion) { let status = gdprStatus.GDPR_APPLIES_PUBLISHER if (gdprApplies) { diff --git a/modules/telariaBidAdapter.js b/modules/telariaBidAdapter.js index 74c97f34b74..acc20f6b183 100644 --- a/modules/telariaBidAdapter.js +++ b/modules/telariaBidAdapter.js @@ -284,6 +284,11 @@ function createBid(status, reqBid, response, width, height, bidderCode) { }); } + bid.meta = bid.meta || {}; + if (response && response.adomain && response.adomain.length > 0) { + bid.meta.advertiserDomains = response.adomain; + } + return bid; } diff --git a/modules/tribeosBidAdapter.js b/modules/tribeosBidAdapter.js index 201e71ad2d1..80361aa3fdb 100644 --- a/modules/tribeosBidAdapter.js +++ b/modules/tribeosBidAdapter.js @@ -5,7 +5,7 @@ import {BANNER} from '../src/mediaTypes.js'; var CONSTANTS = require('../src/constants.json'); const BIDDER_CODE = 'tribeos'; -const ENDPOINT_URL = 'https://bidder-api-us-east.tribeos.io/prebid/'; +const ENDPOINT_URL = 'https://bidder.tribeos.tech/prebid/'; const LOG_PREFIX = 'TRIBEOS: '; export const spec = { code: BIDDER_CODE, diff --git a/modules/tripleliftBidAdapter.js b/modules/tripleliftBidAdapter.js index 8b21f334233..b003de7785f 100644 --- a/modules/tripleliftBidAdapter.js +++ b/modules/tripleliftBidAdapter.js @@ -1,4 +1,4 @@ -import { BANNER } from '../src/mediaTypes.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import * as utils from '../src/utils.js'; import { config } from '../src/config.js'; @@ -11,9 +11,13 @@ let consentString = null; export const tripleliftAdapterSpec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER], - isBidRequestValid: function(bid) { - return (typeof bid.params.inventoryCode !== 'undefined'); + supportedMediaTypes: [BANNER, VIDEO], + isBidRequestValid: function (bid) { + if (bid.mediaTypes.video) { + let video = _getORTBVideo(bid); + if (!video.w || !video.h) return false; + } + return typeof bid.params.inventoryCode !== 'undefined'; }, buildRequests: function(bidRequests, bidderRequest) { @@ -107,15 +111,20 @@ function _getSyncType(syncOptions) { function _buildPostBody(bidRequests) { let data = {}; let { schain } = bidRequests[0]; - data.imp = bidRequests.map(function(bid, index) { - return { + const globalFpd = _getGlobalFpd(); + + data.imp = bidRequests.map(function(bidRequest, index) { + let imp = { id: index, - tagid: bid.params.inventoryCode, - floor: bid.params.floor, - banner: { - format: _sizes(bid.sizes) - } + tagid: bidRequest.params.inventoryCode, + floor: _getFloor(bidRequest) }; + if (bidRequest.mediaTypes.video) { + imp.video = _getORTBVideo(bidRequest); + } else if (bidRequest.mediaTypes.banner) { + imp.banner = { format: _sizes(bidRequest.sizes) }; + }; + return imp; }); let eids = [ @@ -130,14 +139,73 @@ function _buildPostBody(bidRequests) { }; } - if (schain) { - data.ext = { - schain - } + let ext = _getExt(schain, globalFpd); + + if (!utils.isEmpty(ext)) { + data.ext = ext; } return data; } +function _getORTBVideo(bidRequest) { + // give precedent to mediaTypes.video + let video = { ...bidRequest.params.video, ...bidRequest.mediaTypes.video }; + if (!video.w) video.w = video.playerSize[0][0]; + if (!video.h) video.h = video.playerSize[0][1]; + if (video.context === 'instream') video.placement = 1; + // clean up oRTB object + delete video.playerSize; + return video; +} + +function _getFloor (bid) { + let floor = null; + if (typeof bid.getFloor === 'function') { + const floorInfo = bid.getFloor({ + currency: 'USD', + mediaType: 'banner', + size: _sizes(bid.sizes) + }); + if (typeof floorInfo === 'object' && + floorInfo.currency === 'USD' && !isNaN(parseFloat(floorInfo.floor))) { + floor = parseFloat(floorInfo.floor); + } + } + return floor !== null ? floor : bid.params.floor; +} + +function _getGlobalFpd() { + let fpd = {}; + const fpdContext = Object.assign({}, config.getConfig('fpd.context')); + const fpdUser = Object.assign({}, config.getConfig('fpd.user')); + + _addEntries(fpd, fpdContext); + _addEntries(fpd, fpdUser); + + return fpd; +} + +function _addEntries(target, source) { + if (!utils.isEmpty(source)) { + Object.keys(source).forEach(key => { + if (source[key] != null) { + target[key] = source[key]; + } + }); + } +} + +function _getExt(schain, fpd) { + let ext = {}; + if (!utils.isEmpty(schain)) { + ext.schain = { ...schain }; + } + if (!utils.isEmpty(fpd)) { + ext.fpd = { ...fpd }; + } + return ext; +} + function getUnifiedIdEids(bidRequests) { return getEids(bidRequests, 'tdid', 'adserver.org', 'TDID'); } @@ -191,10 +259,11 @@ function _buildResponseObject(bidderRequest, bid) { let height = bid.height || 1; let dealId = bid.deal_id || ''; let creativeId = bid.crid || ''; + let breq = bidderRequest.bids[bid.imp_id]; if (bid.cpm != 0 && bid.ad) { bidResponse = { - requestId: bidderRequest.bids[bid.imp_id].bidId, + requestId: breq.bidId, cpm: bid.cpm, width: width, height: height, @@ -205,7 +274,17 @@ function _buildResponseObject(bidderRequest, bid) { currency: 'USD', ttl: 300, tl_source: bid.tl_source, + meta: {} }; + + if (breq.mediaTypes.video) { + bidResponse.vastXml = bid.ad; + bidResponse.mediaType = 'video'; + }; + + if (bid.advertiser_name) { + bidResponse.meta.advertiserName = bid.advertiser_name; + } }; return bidResponse; } diff --git a/modules/tripleliftBidAdapter.md b/modules/tripleliftBidAdapter.md index d5f88a2bece..03dcee3b980 100644 --- a/modules/tripleliftBidAdapter.md +++ b/modules/tripleliftBidAdapter.md @@ -58,5 +58,25 @@ var adUnits = [{ floor: 0 } }] +}, { + code: 'instream-div-1', + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'instream', + } + }, + bids: [ + { + bidder: 'triplelift', + params: { + inventoryCode: 'instream_test', + video: { + mimes: ['video/mp4'], + w: 640, + h: 480, + }, + } + }] }]; ``` diff --git a/modules/truereachBidAdapter.js b/modules/truereachBidAdapter.js new file mode 100755 index 00000000000..2de7edbc04d --- /dev/null +++ b/modules/truereachBidAdapter.js @@ -0,0 +1,128 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { BANNER } from '../src/mediaTypes.js'; + +const SUPPORTED_AD_TYPES = [BANNER]; +const BIDDER_CODE = 'truereach'; +const BIDDER_URL = 'https://ads.momagic.com/exchange/openrtb25/'; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: SUPPORTED_AD_TYPES, + + isBidRequestValid: function (bidRequest) { + return (bidRequest.params.site_id && bidRequest.params.bidfloor && + utils.deepAccess(bidRequest, 'mediaTypes.banner') && (utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes.length') > 0)); + }, + + buildRequests: function (validBidRequests, bidderRequest) { + if (validBidRequests.length === 0) { + return []; + } + + let queryParams = buildCommonQueryParamsFromBids(validBidRequests, bidderRequest); + + let siteId = utils.deepAccess(validBidRequests[0], 'params.site_id'); + + let url = BIDDER_URL + siteId + '?hb=1&transactionId=' + validBidRequests[0].transactionId; + + return { + method: 'POST', + url: url, + data: queryParams, + options: { withCredentials: true } + }; + }, + + interpretResponse: function ({ body: serverResponse }, serverRequest) { + const bidResponses = []; + + if ((!serverResponse || !serverResponse.id) || + (!serverResponse.seatbid || serverResponse.seatbid.length === 0 || !serverResponse.seatbid[0].bid || serverResponse.seatbid[0].bid.length === 0)) { + return bidResponses; + } + + let adUnits = serverResponse.seatbid[0].bid; + let bidderBid = adUnits[0]; + + let responseCPM = parseFloat(bidderBid.price); + if (responseCPM === 0) { + return bidResponses; + } + + let responseAd = bidderBid.adm; + + if (bidderBid.nurl) { + let responseNurl = ''; + responseAd += responseNurl; + } + + const bidResponse = { + requestId: bidderBid.impid, + cpm: responseCPM, + currency: serverResponse.cur || 'USD', + width: parseInt(bidderBid.w), + height: parseInt(bidderBid.h), + ad: decodeURIComponent(responseAd), + ttl: 180, + creativeId: bidderBid.crid, + netRevenue: false + }; + if (bidderBid.adomain && bidderBid.adomain.length) { + bidResponse.meta = { + advertiserDomains: bidderBid.adomain, + }; + } + + bidResponses.push(bidResponse); + + return bidResponses; + }, + +}; + +function buildCommonQueryParamsFromBids(validBidRequests, bidderRequest) { + let adW = 0; + let adH = 0; + let adSizes = Array.isArray(validBidRequests[0].params.sizes) ? validBidRequests[0].params.sizes : validBidRequests[0].sizes; + let sizeArrayLength = adSizes.length; + if (sizeArrayLength === 2 && typeof adSizes[0] === 'number' && typeof adSizes[1] === 'number') { + adW = adSizes[0]; + adH = adSizes[1]; + } else { + adW = adSizes[0][0]; + adH = adSizes[0][1]; + } + + let bidFloor = Number(utils.deepAccess(validBidRequests[0], 'params.bidfloor')); + + let domain = window.location.host; + let page = window.location.host + window.location.pathname + location.search + location.hash; + + let defaultParams = { + id: utils.getUniqueIdentifierStr(), + imp: [ + { + id: validBidRequests[0].bidId, + banner: { + w: adW, + h: adH + }, + bidfloor: bidFloor + } + ], + site: { + domain: domain, + page: page + }, + device: { + ua: window.navigator.userAgent + }, + tmax: config.getConfig('bidderTimeout') + }; + + return defaultParams; +} + +registerBidder(spec); diff --git a/modules/truereachBidAdapter.md b/modules/truereachBidAdapter.md new file mode 100644 index 00000000000..8a926565092 --- /dev/null +++ b/modules/truereachBidAdapter.md @@ -0,0 +1,44 @@ +# Overview + +``` +Module Name: TrueReach Bidder Adapter +Module Type: Bidder Adapter +Maintainer: mm.github@momagic.com +``` + +# Description + +Module that connects to TrueReach's demand sources + +# Test Parameters +``` + var adUnits = [{ + code: 'test-banner', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [{ + bidder: 'truereach', + params: { + site_id: '0142010a-8400-1b01-72cb-a553b9000009', + bidfloor: 0.1 + } + }] + }]; +``` + +# Bid Parameters + +`mediaTypes -> banner -> sizes` must be `defined`. + +Also, the following parameters are `required` to be set- + +| Name | Type | Description +| ---- | ---- | ----------- +| `site_id` | String | TrueReach provided site ID +| `bidfloor` | Number | Minimum price (CPM) in USD. Must be greater than 0. + +# Additional Details +[TrueReach Ads](http://doc.truereach.co.in/docs/prebid/js-bidder-adapter.html) diff --git a/modules/ucfunnelBidAdapter.js b/modules/ucfunnelBidAdapter.js index 505f3f89832..f9982edef36 100644 --- a/modules/ucfunnelBidAdapter.js +++ b/modules/ucfunnelBidAdapter.js @@ -1,6 +1,9 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js'; - +import { getStorageManager } from '../src/storageManager.js'; +import * as utils from '../src/utils.js'; +const storage = getStorageManager(); +const COOKIE_NAME = 'ucf_uid'; const VER = 'ADGENT_PREBID-2018011501'; const BIDDER_CODE = 'ucfunnel'; @@ -183,9 +186,6 @@ function getSupplyChain(schain) { function getRequestData(bid, bidderRequest) { const size = parseSizes(bid); - const loc = window.location; - const host = loc.host; - const page = loc.href; const language = navigator.language; const dnt = (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0; const userIdTdid = (bid.userId && bid.userId.tdid) ? bid.userId.tdid : ''; @@ -197,14 +197,38 @@ function getRequestData(bid, bidderRequest) { bl: language, je: 1, dnt: dnt, - host: host, - u: page, adid: bid.params.adid, tdid: userIdTdid, schain: supplyChain, fp: bid.params.bidfloor }; + try { + bidData.host = window.top.location.hostname; + bidData.u = window.top.location.href; + bidData.xr = 0; + } catch (e) { + bidData.host = window.location.hostname; + bidData.u = document.referrer || window.location.href; + bidData.xr = 1; + } + + if (window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0) { + bidData.ao = window.location.ancestorOrigins[window.location.ancestorOrigins.length - 1]; + } + + if (storage.cookiesAreEnabled()) { + let ucfUid = ''; + if (storage.getCookie(COOKIE_NAME) != undefined) { + ucfUid = storage.getCookie(COOKIE_NAME); + bidData.ucfUid = ucfUid; + } else { + ucfUid = utils.generateUUID(); + bidData.ucfUid = ucfUid; + storage.setCookie(COOKIE_NAME, ucfUid); + } + } + if (size != undefined && size.length == 2) { bidData.w = size[0]; bidData.h = size[1]; diff --git a/modules/undertoneBidAdapter.js b/modules/undertoneBidAdapter.js index 6ead453b622..743cb07b21e 100644 --- a/modules/undertoneBidAdapter.js +++ b/modules/undertoneBidAdapter.js @@ -2,8 +2,9 @@ * Adapter to send bids to Undertone */ -import { parseUrl } from '../src/utils.js'; +import { deepAccess, parseUrl } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; const BIDDER_CODE = 'undertone'; const URL = 'https://hb.undertone.com/hb'; @@ -73,6 +74,7 @@ function getBannerCoords(id) { export const spec = { code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: function(bid) { if (bid && bid.params && bid.params.publisherId) { bid.params.publisherId = parseInt(bid.params.publisherId); @@ -120,8 +122,20 @@ export const spec = { sizes: bidReq.sizes, params: bidReq.params }; + const videoMediaType = deepAccess(bidReq, 'mediaTypes.video'); + if (videoMediaType) { + bid.video = { + playerSize: deepAccess(bidReq, 'mediaTypes.video.playerSize') || null, + streamType: deepAccess(bidReq, 'mediaTypes.video.context') || null, + playbackMethod: deepAccess(bidReq, 'params.video.playbackMethod') || null, + maxDuration: deepAccess(bidReq, 'params.video.maxDuration') || null, + skippable: deepAccess(bidReq, 'params.video.skippable') || null + }; + bid.mediaType = 'video'; + } payload['x-ut-hb-params'].push(bid); }); + return { method: 'POST', url: reqUrl, @@ -144,9 +158,14 @@ export const spec = { creativeId: bidRes.adId, currency: bidRes.currency, netRevenue: bidRes.netRevenue, - ttl: bidRes.ttl || 360, - ad: bidRes.ad + ttl: bidRes.ttl || 360 }; + if (bidRes.mediaType && bidRes.mediaType === 'video') { + bid.vastXml = bidRes.ad; + bid.mediaType = bidRes.mediaType; + } else { + bid.ad = bidRes.ad + } bids.push(bid); } }); diff --git a/modules/userId/eids.js b/modules/userId/eids.js index 5ca9e40866b..4e4576dbb14 100644 --- a/modules/userId/eids.js +++ b/modules/userId/eids.js @@ -5,6 +5,12 @@ const USER_IDS_CONFIG = { // key-name : {config} + // intentIqId + 'intentIqId': { + source: 'intentiq.com', + atype: 1 + }, + // pubCommonId 'pubcid': { source: 'pubcid.org', @@ -24,14 +30,42 @@ const USER_IDS_CONFIG = { // id5Id 'id5id': { + getValue: function(data) { + return data.uid + }, source: 'id5-sync.com', - atype: 1 + atype: 1, + getEidExt: function(data) { + if (data.ext) { + return data.ext; + } + } }, // parrableId - 'parrableid': { + 'parrableId': { source: 'parrable.com', - atype: 1 + atype: 1, + getValue: function(parrableId) { + if (parrableId.eid) { + return parrableId.eid; + } + if (parrableId.ccpaOptout) { + // If the EID was suppressed due to a non consenting ccpa optout then + // we still wish to provide this as a reason to the adapters + return ''; + } + return null; + }, + getUidExt: function(parrableId) { + const extendedData = utils.pick(parrableId, [ + 'ibaOptout', + 'ccpaOptout' + ]); + if (Object.keys(extendedData).length) { + return extendedData; + } + } }, // identityLink @@ -62,13 +96,10 @@ const USER_IDS_CONFIG = { atype: 1 }, - // DigiTrust - 'digitrustid': { - getValue: function(data) { - return data.data.id; - }, - source: 'digitru.st', - atype: 1 + // lotamePanoramaId + lotamePanoramaId: { + source: 'crwdcntrl.net', + atype: 1, }, // criteo @@ -77,10 +108,48 @@ const USER_IDS_CONFIG = { atype: 1 }, + // merkleId + 'merkleId': { + source: 'merkleinc.com', + atype: 1 + }, + // NetId 'netId': { source: 'netid.de', atype: 1 + }, + + // sharedid + 'sharedid': { + source: 'sharedid.org', + atype: 1, + getValue: function(data) { + return data.id; + }, + getUidExt: function(data) { + return (data && data.third) ? { + third: data.third + } : undefined; + } + }, + + // zeotapIdPlus + 'IDP': { + source: 'zeotap.com', + atype: 1 + }, + + // haloId + 'haloId': { + source: 'audigent.com', + atype: 1 + }, + + // quantcastId + 'quantcastId': { + source: 'quantcast.com', + atype: 1 } }; @@ -121,9 +190,13 @@ export function createEidsArray(bidRequestUserId) { let eids = []; for (const subModuleKey in bidRequestUserId) { if (bidRequestUserId.hasOwnProperty(subModuleKey)) { - const eid = createEidObject(bidRequestUserId[subModuleKey], subModuleKey); - if (eid) { - eids.push(eid); + if (subModuleKey === 'pubProvidedId') { + eids = eids.concat(bidRequestUserId['pubProvidedId']); + } else { + const eid = createEidObject(bidRequestUserId[subModuleKey], subModuleKey); + if (eid) { + eids.push(eid); + } } } } diff --git a/modules/userId/eids.md b/modules/userId/eids.md index baface1ab6f..7dc149cd47a 100644 --- a/modules/userId/eids.md +++ b/modules/userId/eids.md @@ -1,7 +1,8 @@ ## Example of eids array generated by UserId Module. + ``` userIdAsEids = [ - { + { source: 'pubcid.org', uids: [{ id: 'some-random-id-value', @@ -25,6 +26,9 @@ userIdAsEids = [ uids: [{ id: 'some-random-id-value', atype: 1 + }, + ext: { + linkType: 2 }] }, @@ -56,7 +60,7 @@ userIdAsEids = [ }, { - source: 'britepool.com', + source: 'merkleinc.com', uids: [{ id: 'some-random-id-value', atype: 1 @@ -64,7 +68,7 @@ userIdAsEids = [ }, { - source: 'digitru.st', + source: 'britepool.com', uids: [{ id: 'some-random-id-value', atype: 1 @@ -85,6 +89,37 @@ userIdAsEids = [ id: 'some-random-id-value', atype: 1 }] + }, + { + source: 'sharedid.org', + uids: [{ + id: 'some-random-id-value', + atype: 1, + ext: { + third: 'some-random-id-value' + } + }] + }, + { + source: 'zeotap.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, + { + source: 'audigent.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, + { + source: 'quantcast.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] } ] -``` \ No newline at end of file +``` diff --git a/modules/userId/index.js b/modules/userId/index.js index f18888c398e..14f7ad3599b 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -124,6 +124,10 @@ const COOKIE = 'cookie'; const LOCAL_STORAGE = 'html5'; const DEFAULT_SYNC_DELAY = 500; const NO_AUCTION_DELAY = 0; +const CONSENT_DATA_COOKIE_STORAGE_CONFIG = { + name: '_pbjs_userid_consent_data', + expires: 30 // 30 days expiration, which should match how often consent is refreshed by CMPs +}; export const coreStorage = getCoreStorageManager('userid'); /** @type {string[]} */ @@ -159,17 +163,23 @@ export function setSubmoduleRegistry(submodules) { } /** - * @param {SubmoduleStorage} storage + * @param {SubmoduleContainer} submodule * @param {(Object|string)} value */ -function setStoredValue(storage, value) { +export function setStoredValue(submodule, value) { + /** + * @type {SubmoduleStorage} + */ + const storage = submodule.config.storage; + const domainOverride = (typeof submodule.submodule.domainOverride === 'function') ? submodule.submodule.domainOverride() : null; + try { const valueStr = utils.isPlainObject(value) ? JSON.stringify(value) : value; const expiresStr = (new Date(Date.now() + (storage.expires * (60 * 60 * 24 * 1000)))).toUTCString(); if (storage.type === COOKIE) { - coreStorage.setCookie(storage.name, valueStr, expiresStr, 'Lax'); + coreStorage.setCookie(storage.name, valueStr, expiresStr, 'Lax', domainOverride); if (typeof storage.refreshInSeconds === 'number') { - coreStorage.setCookie(`${storage.name}_last`, new Date().toUTCString(), expiresStr); + coreStorage.setCookie(`${storage.name}_last`, new Date().toUTCString(), expiresStr, 'Lax', domainOverride); } } else if (storage.type === LOCAL_STORAGE) { coreStorage.setDataInLocalStorage(`${storage.name}_exp`, expiresStr); @@ -215,6 +225,69 @@ function getStoredValue(storage, key = undefined) { return storedValue; } +/** + * makes an object that can be stored with only the keys we need to check. + * excluding the vendorConsents object since the consentString is enough to know + * if consent has changed without needing to have all the details in an object + * @param consentData + * @returns {{apiVersion: number, gdprApplies: boolean, consentString: string}} + */ +function makeStoredConsentDataHash(consentData) { + const storedConsentData = { + consentString: '', + gdprApplies: false, + apiVersion: 0 + }; + + if (consentData) { + storedConsentData.consentString = consentData.consentString; + storedConsentData.gdprApplies = consentData.gdprApplies; + storedConsentData.apiVersion = consentData.apiVersion; + } + return utils.cyrb53Hash(JSON.stringify(storedConsentData)); +} + +/** + * puts the current consent data into cookie storage + * @param consentData + */ +export function setStoredConsentData(consentData) { + try { + const expiresStr = (new Date(Date.now() + (CONSENT_DATA_COOKIE_STORAGE_CONFIG.expires * (60 * 60 * 24 * 1000)))).toUTCString(); + coreStorage.setCookie(CONSENT_DATA_COOKIE_STORAGE_CONFIG.name, makeStoredConsentDataHash(consentData), expiresStr, 'Lax'); + } catch (error) { + utils.logError(error); + } +} + +/** + * get the stored consent data from local storage, if any + * @returns {string} + */ +function getStoredConsentData() { + try { + return coreStorage.getCookie(CONSENT_DATA_COOKIE_STORAGE_CONFIG.name); + } catch (e) { + utils.logError(e); + } +} + +/** + * test if the consent object stored locally matches the current consent data. + * if there is nothing in storage, return true and we'll do an actual comparison next time. + * this way, we don't force a refresh for every user when this code rolls out + * @param storedConsentData + * @param consentData + * @returns {boolean} + */ +function storedConsentDataMatchesConsentData(storedConsentData, consentData) { + return ( + typeof storedConsentData === 'undefined' || + storedConsentData === null || + storedConsentData === makeStoredConsentDataHash(consentData) + ); +} + /** * test if consent module is present, applies, and is valid for local storage or cookies (purpose 1) * @param {ConsentData} consentData @@ -246,12 +319,12 @@ function processSubmoduleCallbacks(submodules, cb) { // if valid, id data should be saved to cookie/html storage if (idObj) { if (submodule.config.storage) { - setStoredValue(submodule.config.storage, idObj); + setStoredValue(submodule, idObj); } // cache decoded value (this is copied to every adUnit bid) submodule.idObj = submodule.submodule.decode(idObj); } else { - utils.logError(`${MODULE_NAME}: ${submodule.submodule.name} - request id responded with an empty value`); + utils.logInfo(`${MODULE_NAME}: ${submodule.submodule.name} - request id responded with an empty value`); } done(); }); @@ -302,7 +375,7 @@ function addIdDataToAdUnitBids(adUnits, submodules) { } /** - * This is a common function that will initalize subModules if not already done and it will also execute subModule callbacks + * This is a common function that will initialize subModules if not already done and it will also execute subModule callbacks */ function initializeSubmodulesAndExecuteCallbacks(continueAuction) { let delayed = false; @@ -396,7 +469,7 @@ function getUserIdsAsEids() { * This hook returns updated list of submodules which are allowed to do get user id based on TCF 2 enforcement rules configured */ export const validateGdprEnforcement = hook('sync', function (submodules, consentData) { - return submodules; + return {userIdModules: submodules, hasValidated: consentData && consentData.hasValidated}; }, 'validateGdprEnforcement'); /** @@ -405,9 +478,13 @@ export const validateGdprEnforcement = hook('sync', function (submodules, consen * @returns {SubmoduleContainer[]} initialized submodules */ function initSubmodules(submodules, consentData) { + // we always want the latest consentData stored, even if we don't execute any submodules + const storedConsentData = getStoredConsentData(); + setStoredConsentData(consentData); + // gdpr consent with purpose one is required, otherwise exit immediately - let userIdModules = validateGdprEnforcement(submodules, consentData); - if (!hasGDPRConsent(consentData)) { + let {userIdModules, hasValidated} = validateGdprEnforcement(submodules, consentData); + if (!hasValidated && !hasGDPRConsent(consentData)) { utils.logWarn(`${MODULE_NAME} - gdpr permission not valid for local storage or cookies, exit module`); return []; } @@ -426,12 +503,8 @@ function initSubmodules(submodules, consentData) { refreshNeeded = storedDate && (Date.now() - storedDate.getTime() > submodule.config.storage.refreshInSeconds * 1000); } - if (CONSTANTS.SUBMODULES_THAT_ALWAYS_REFRESH_ID[submodule.config.name] === true) { - refreshNeeded = true; - } - - if (!storedId || refreshNeeded) { - // No previously saved id. Request one from submodule. + if (!storedId || refreshNeeded || !storedConsentDataMatchesConsentData(storedConsentData, consentData)) { + // No id previously saved, or a refresh is needed, or consent has changed. Request a new id from the submodule. response = submodule.submodule.getId(submodule.config.params, consentData, storedId); } else if (typeof submodule.submodule.extendId === 'function') { // If the id exists already, give submodule a chance to decide additional actions that need to be taken @@ -441,7 +514,7 @@ function initSubmodules(submodules, consentData) { if (utils.isPlainObject(response)) { if (response.id) { // A getId/extendId result assumed to be valid user id data, which should be saved to users local storage or cookies - setStoredValue(submodule.config.storage, response.id); + setStoredValue(submodule, response.id); storedId = response.id; } @@ -453,7 +526,7 @@ function initSubmodules(submodules, consentData) { if (storedId) { // cache decoded value (this is copied to every adUnit bid) - submodule.idObj = submodule.submodule.decode(storedId, submodule.config); + submodule.idObj = submodule.submodule.decode(storedId, submodule.config.params); } } else if (submodule.config.value) { // cache decoded value (this is copied to every adUnit bid) @@ -462,7 +535,7 @@ function initSubmodules(submodules, consentData) { const response = submodule.submodule.getId(submodule.config.params, consentData, undefined); if (utils.isPlainObject(response)) { if (typeof response.callback === 'function') { submodule.callback = response.callback; } - if (response.id) { submodule.idObj = submodule.submodule.decode(response.id, submodule.config); } + if (response.id) { submodule.idObj = submodule.submodule.decode(response.id, submodule.config.params); } } } carry.push(submodule); @@ -567,15 +640,15 @@ export function init(config) { utils.logInfo(`${MODULE_NAME} - opt-out cookie found, exit module`); return; } - // _pubcid_optout is checked for compatiblility with pubCommonId + // _pubcid_optout is checked for compatibility with pubCommonId if (validStorageTypes.indexOf(LOCAL_STORAGE) !== -1 && (coreStorage.getDataFromLocalStorage('_pbjs_id_optout') || coreStorage.getDataFromLocalStorage('_pubcid_optout'))) { utils.logInfo(`${MODULE_NAME} - opt-out localStorage found, exit module`); return; } // listen for config userSyncs to be set config.getConfig(conf => { - // Note: support for both 'userSync' and 'usersync' will be deprecated with Prebid.js 3.0 - const userSync = conf.userSync || conf.usersync; + // Note: support for 'usersync' was dropped as part of Prebid.js 4.0 + const userSync = conf.userSync; if (userSync && userSync.userIds) { configRegistry = userSync.userIds; syncDelay = utils.isNumber(userSync.syncDelay) ? userSync.syncDelay : DEFAULT_SYNC_DELAY; diff --git a/modules/userId/userId.md b/modules/userId/userId.md index e6da02a6811..a9ab6ccc483 100644 --- a/modules/userId/userId.md +++ b/modules/userId/userId.md @@ -25,12 +25,13 @@ pbjs.setConfig({ }, { name: "id5Id", params: { - partner: 173 //Set your real ID5 partner ID here for production, please ask for one at http://id5.io/prebid + partner: 173, // Set your real ID5 partner ID here for production, please ask for one at https://id5.io/universal-id + pd: "some-pd-string" // See https://wiki.id5.io/x/BIAZ for details }, storage: { type: "cookie", - name: "id5id", - expires: 5, // Expiration of cookies in days + name: "id5id.1st", + expires: 90, // Expiration of cookies in days refreshInSeconds: 8*3600 // User Id cache lifetime in seconds, defaulting to 'expires' }, }, { @@ -38,16 +39,11 @@ pbjs.setConfig({ params: { // Replace partner with comma-separated (if more than one) Parrable Partner Client ID(s) for Parrable-aware bid adapters in use partner: "30182847-e426-4ff9-b2b5-9ca1324ea09b" - }, - storage: { - type: 'cookie', - name: '_parrable_eid', - expires: 365 } }, { name: 'identityLink', params: { - pid: '999' // Set your real identityLink placement ID here + pid: '999' // Set your real identityLink placement ID here }, storage: { type: 'cookie', @@ -57,13 +53,23 @@ pbjs.setConfig({ }, { name: 'liveIntentId', params: { - publisherId: '7798696' // Set an identifier of a publisher know to your systems + publisherId: '7798696' // Set an identifier of a publisher know to your systems }, storage: { type: 'cookie', name: '_li_pbid', expires: 60 } + }, { + name: 'sharedId', + params: { + syncTime: 60 // in seconds, default is 24 hours + }, + storage: { + type: 'cookie', + name: 'sharedid', + expires: 28 + } }], syncDelay: 5000, auctionDelay: 1000 @@ -74,7 +80,7 @@ pbjs.setConfig({ Example showing `localStorage` for user id data for some submodules ``` pbjs.setConfig({ - usersync: { + userSync: { userIds: [{ name: "unifiedId", params: { @@ -96,7 +102,7 @@ pbjs.setConfig({ }, { name: 'identityLink', params: { - pid: '999' // Set your real identityLink placement ID here + pid: '999' // Set your real identityLink placement ID here }, storage: { type: 'html5', @@ -104,15 +110,37 @@ pbjs.setConfig({ expires: 30 } }, { - name: 'liveIntentId', - params: { - publisherId: '7798696' // Set an identifier of a publisher know to your systems - }, + name: 'liveIntentId', + params: { + publisherId: '7798696' // Set an identifier of a publisher know to your systems + }, + storage: { + type: 'html5', + name: '_li_pbid', + expires: 60 + } + }, { + name: 'sharedId', + params: { + syncTime: 60 // in seconds, default is 24 hours + }, storage: { - type: 'html5', - name: '_li_pbid', - expires: 60 + type: 'html5', + name: 'sharedid', + expires: 28 } + }, { + name: 'id5Id', + params: { + partner: 173, // Set your real ID5 partner ID here for production, please ask for one at https://id5.io/universal-id + pd: 'some-pd-string' // See https://wiki.id5.io/x/BIAZ for details + }, + storage: { + type: 'html5', + name: 'id5id.1st', + expires: 90, // Expiration of cookies in days + refreshInSeconds: 8*3600 // User Id cache lifetime in seconds, defaulting to 'expires' + }, }], syncDelay: 5000 } @@ -122,7 +150,7 @@ pbjs.setConfig({ Example showing how to configure a `value` object to pass directly to bid adapters ``` pbjs.setConfig({ - usersync: { + userSync: { userIds: [{ name: "pubCommonId", value: { diff --git a/modules/userIdTargeting.md b/modules/userIdTargeting.md index f99fd5308b3..340c1b6abf2 100644 --- a/modules/userIdTargeting.md +++ b/modules/userIdTargeting.md @@ -8,7 +8,7 @@ pbjs.setConfig({ // your existing userIds config - usersync: { + userSync: { userIds: [{...}, ...] }, diff --git a/modules/valueimpressionBidAdapter.js b/modules/valueimpressionBidAdapter.js deleted file mode 100644 index 41bb6e6cacc..00000000000 --- a/modules/valueimpressionBidAdapter.js +++ /dev/null @@ -1,152 +0,0 @@ -import * as utils from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; -const BIDDER_CODE = 'valueimpression'; -const ENDPOINT = 'https://adapter.valueimpression.com/bid'; -const USER_SYNC_URL = 'https://adapter.valueimpression.com/usersync'; - -export const spec = { - code: BIDDER_CODE, - supportedMediaTypes: ['banner', 'video'], - aliases: ['vi'], - isBidRequestValid: function (bid) { - if (!bid.params) { - return false; - } - if (!bid.params.siteId) { - return false; - } - if (!utils.deepAccess(bid, 'mediaTypes.banner') && !utils.deepAccess(bid, 'mediaTypes.video')) { - return false; - } - if (utils.deepAccess(bid, 'mediaTypes.banner')) { // Valueimpression does not support multi type bids, favor banner over video - if (!utils.deepAccess(bid, 'mediaTypes.banner.sizes')) { - // sizes at the banner is required. - return false; - } - } else if (utils.deepAccess(bid, 'mediaTypes.video')) { - if (!utils.deepAccess(bid, 'mediaTypes.video.playerSize')) { - // playerSize is required for instream adUnits. - return false; - } - } - return true; - }, - - buildRequests: function (validBidRequests, bidderRequest) { - const payload = {}; - payload.device = {}; - payload.device.ua = navigator.userAgent; - payload.device.height = window.innerHeight; - payload.device.width = window.innerWidth; - payload.device.dnt = _getDoNotTrack(); - payload.device.language = navigator.language; - - payload.site = {}; - payload.site.id = validBidRequests[0].params.siteId; - payload.site.page = window.location.href; - payload.site.referrer = document.referrer; - payload.site.hostname = window.location.hostname; - - // Apply GDPR parameters to request. - payload.gdpr = {}; - if (bidderRequest && bidderRequest.gdprConsent) { - payload.gdpr.gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 'true' : 'false'; - if (bidderRequest.gdprConsent.consentString) { - payload.gdpr.consentString = bidderRequest.gdprConsent.consentString; - } - } - if (validBidRequests[0].schain) { - payload.schain = JSON.stringify(validBidRequests[0].schain) - } - if (bidderRequest && bidderRequest.uspConsent) { - payload.us_privacy = bidderRequest.uspConsent; - } - - payload.bids = validBidRequests; - - return { - method: 'POST', - url: ENDPOINT, - data: payload, - withCredentials: true, - bidderRequests: validBidRequests - }; - }, - interpretResponse: function (serverResponse, bidRequest) { - const serverBody = serverResponse.body; - const serverBids = serverBody.bids; - // check overall response - if (!serverBody || typeof serverBody !== 'object') { - return []; - } - if (!serverBids || typeof serverBids !== 'object') { - return []; - } - - const bidResponses = []; - serverBids.forEach(bid => { - const bidResponse = { - requestId: bid.requestId, - cpm: bid.cpm, - width: bid.width, - height: bid.height, - creativeId: bid.creativeId, - dealId: bid.dealId, - currency: bid.currency, - netRevenue: bid.netRevenue, - ttl: bid.ttl, - mediaType: bid.mediaType - }; - if (bid.vastXml) { - bidResponse.vastXml = utils.replaceAuctionPrice(bid.vastXml, bid.cpm); - } else { - bidResponse.ad = utils.replaceAuctionPrice(bid.ad, bid.cpm); - } - bidResponses.push(bidResponse); - }); - return bidResponses; - }, - getUserSyncs: function (syncOptions, serverResponses) { - const syncs = []; - try { - if (syncOptions.iframeEnabled) { - syncs.push({ - type: 'iframe', - url: USER_SYNC_URL - }); - } - if (syncOptions.pixelEnabled && serverResponses.length > 0) { - serverResponses[0].body.pixel.forEach(px => { - syncs.push({ - type: px.type, - url: px.url - }); - }); - } - } catch (e) { } - return syncs; - }, - - onTimeout: function (timeoutData) { - }, - - onBidWon: function (bid) { - }, - - onSetTargeting: function (bid) { - } -}; - -function _getDoNotTrack() { - if (window.doNotTrack || navigator.doNotTrack || navigator.msDoNotTrack) { - if (window.doNotTrack == '1' || navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') { - return 1; - } else { - return 0; - } - } else { - return 0; - } -} - -registerBidder(spec); diff --git a/modules/valueimpressionBidAdapter.md b/modules/valueimpressionBidAdapter.md deleted file mode 100644 index 11400f23834..00000000000 --- a/modules/valueimpressionBidAdapter.md +++ /dev/null @@ -1,56 +0,0 @@ -# Overview - -``` -Module Name: Valueimpression Bidder Adapter -Module Type: Bidder Adapter -Maintainer: thuyhq@83.com.vn -``` - -# Description - -Module that connects to Valueimpression's exchange for bids. -Valueimpression Bidder adapter supports Banner and Video ads. - -# Test Parameters -``` -var adUnits = [ - { - code: 'test-div', - mediaTypes: { - banner: { - sizes: [[300, 250], [300,600]] - } - }, - bids: [ - { - bidder: 'valueimpression', - params: { - siteId: 'vi-site-id', // siteId provided by Valueimpression - } - } - ] - } -]; -``` - -# Video Test Parameters -``` -var videoAdUnit = { - code: 'test-div', - sizes: [[640, 480]], - mediaTypes: { - video: { - playerSize: [[640, 480]], - context: 'instream' - }, - }, - bids: [ - { - bidder: 'valueimpression', - params: { - siteId: 'vi-site-id', // siteId provided by Valueimpression - } - } - ] -}; -``` \ No newline at end of file diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index d974c0e1eb7..4b3b1767cec 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -1,36 +1,81 @@ import * as utils from '../src/utils.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {BANNER} from '../src/mediaTypes.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { getStorageManager } from '../src/storageManager.js'; -export const URL = 'https://prebid.cootlogix.com'; +const GLVID = 744; +const DEFAULT_SUB_DOMAIN = 'prebid'; const BIDDER_CODE = 'vidazoo'; +const BIDDER_VERSION = '1.0.0'; const CURRENCY = 'USD'; const TTL_SECONDS = 60 * 5; -const INTERNAL_SYNC_TYPE = { - IFRAME: 'iframe', - IMAGE: 'img' -}; -const EXTERNAL_SYNC_TYPE = { - IFRAME: 'iframe', - IMAGE: 'image' +const DEAL_ID_EXPIRY = 1000 * 60 * 15; +const UNIQUE_DEAL_ID_EXPIRY = 1000 * 60 * 15; +const SESSION_ID_KEY = 'vidSid'; +export const SUPPORTED_ID_SYSTEMS = { + 'britepoolid': 1, + 'criteoId': 1, + 'digitrustid': 1, + 'id5id': 1, + 'idl_env': 1, + 'lipb': 1, + 'netId': 1, + 'parrableId': 1, + 'pubcid': 1, + 'tdid': 1, }; +const storage = getStorageManager(GLVID); + +export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { + return `https://${subDomain}.cootlogix.com`; +} + +export function extractCID(params) { + return params.cId || params.CID || params.cID || params.CId || params.cid || params.ciD || params.Cid || params.CiD; +} + +export function extractPID(params) { + return params.pId || params.PID || params.pID || params.PId || params.pid || params.piD || params.Pid || params.PiD; +} + +export function extractSubDomain(params) { + return params.subDomain || params.SubDomain || params.Subdomain || params.subdomain || params.SUBDOMAIN || params.subDOMAIN; +} function isBidRequestValid(bid) { const params = bid.params || {}; - return !!(params.cId && params.pId); + return !!(extractCID(params) && extractPID(params)); } function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { - const {params, bidId} = bid; - const {bidFloor, cId, pId, ext} = params; + const { params, bidId, userId, adUnitCode } = bid; + const { bidFloor, ext } = params; + const hashUrl = hashCode(topWindowUrl); + const dealId = getNextDealId(hashUrl); + const uniqueDealId = getUniqueDealId(hashUrl); + const sId = getVidazooSessionId(); + const cId = extractCID(params); + const pId = extractPID(params); + const subDomain = extractSubDomain(params); + let data = { url: encodeURIComponent(topWindowUrl), cb: Date.now(), bidFloor: bidFloor, bidId: bidId, + adUnitCode: adUnitCode, publisherId: pId, + sessionId: sId, sizes: sizes, + dealId: dealId, + uniqueDealId: uniqueDealId, + bidderVersion: BIDDER_VERSION, + prebidVersion: '$prebid.version$', + res: `${screen.width}x${screen.height}` }; + + appendUserIdsToRequestPayload(data, userId); + if (bidderRequest.gdprConsent) { if (bidderRequest.gdprConsent.consentString) { data.gdprConsent = bidderRequest.gdprConsent.consentString; @@ -39,9 +84,13 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { data.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; } } + if (bidderRequest.uspConsent) { + data.usPrivacy = bidderRequest.uspConsent + } + const dto = { method: 'POST', - url: `${URL}/prebid/multi/${cId}`, + url: `${createDomain(subDomain)}/prebid/multi/${cId}`, data: data }; @@ -52,6 +101,32 @@ function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { return dto; } +function appendUserIdsToRequestPayload(payloadRef, userIds) { + let key; + utils._each(userIds, (userId, idSystemProviderName) => { + if (SUPPORTED_ID_SYSTEMS[idSystemProviderName]) { + key = `uid.${idSystemProviderName}`; + + switch (idSystemProviderName) { + case 'digitrustid': + payloadRef[key] = utils.deepAccess(userId, 'data.id'); + break; + case 'lipb': + payloadRef[key] = userId.lipbid; + break; + case 'parrableId': + payloadRef[key] = userId.eid; + break; + case 'id5id': + payloadRef[key] = userId.uid; + break; + default: + payloadRef[key] = userId; + } + } + }); +} + function buildRequests(validBidRequests, bidderRequest) { const topWindowUrl = bidderRequest.refererInfo.referer; const requests = []; @@ -67,14 +142,14 @@ function interpretResponse(serverResponse, request) { if (!serverResponse || !serverResponse.body) { return []; } - const {bidId} = request.data; - const {results} = serverResponse.body; + const { bidId } = request.data; + const { results } = serverResponse.body; let output = []; try { results.forEach(result => { - const {creativeId, ad, price, exp, width, height, currency} = result; + const { creativeId, ad, price, exp, width, height, currency } = result; if (!ad || !price) { return; } @@ -96,43 +171,102 @@ function interpretResponse(serverResponse, request) { } } -function getUserSyncs(syncOptions, responses) { - const {iframeEnabled, pixelEnabled} = syncOptions; - +function getUserSyncs(syncOptions, responses, gdprConsent = {}, uspConsent = '') { + let syncs = []; + const { iframeEnabled, pixelEnabled } = syncOptions; + const { gdprApplies, consentString = '' } = gdprConsent; + const params = `?gdpr=${gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(consentString || '')}&us_privacy=${encodeURIComponent(uspConsent || '')}` if (iframeEnabled) { - return [{ + syncs.push({ type: 'iframe', - url: 'https://static.cootlogix.com/basev/sync/user_sync.html' - }]; + url: `https://prebid.cootlogix.com/api/sync/iframe/${params}` + }); } - if (pixelEnabled) { - const lookup = {}; - const syncs = []; - responses.forEach(response => { - const {body} = response; - const results = body ? body.results || [] : []; - results.forEach(result => { - (result.cookies || []).forEach(cookie => { - if (cookie.type === INTERNAL_SYNC_TYPE.IMAGE) { - if (pixelEnabled && !lookup[cookie.src]) { - syncs.push({ - type: EXTERNAL_SYNC_TYPE.IMAGE, - url: cookie.src - }); - } - } - }); - }); + syncs.push({ + type: 'image', + url: `https://prebid.cootlogix.com/api/sync/image/${params}` }); - return syncs; } + return syncs; +} + +export function hashCode(s, prefix = '_') { + const l = s.length; + let h = 0 + let i = 0; + if (l > 0) { + while (i < l) { h = (h << 5) - h + s.charCodeAt(i++) | 0; } + } + return prefix + h; +} + +export function getNextDealId(key, expiry = DEAL_ID_EXPIRY) { + try { + const data = getStorageItem(key); + let currentValue = 0; + let timestamp; + + if (data && data.value && Date.now() - data.created < expiry) { + currentValue = data.value; + timestamp = data.created; + } + + const nextValue = currentValue + 1; + setStorageItem(key, nextValue, timestamp); + return nextValue; + } catch (e) { + return 0; + } +} + +export function getUniqueDealId(key, expiry = UNIQUE_DEAL_ID_EXPIRY) { + const storageKey = `u_${key}`; + const now = Date.now(); + const data = getStorageItem(storageKey); + let uniqueId; + + if (!data || !data.value || now - data.created > expiry) { + uniqueId = `${key}_${now.toString()}`; + setStorageItem(storageKey, uniqueId); + } else { + uniqueId = data.value; + } + + return uniqueId; +} + +export function getVidazooSessionId() { + return getStorageItem(SESSION_ID_KEY) || ''; +} + +export function getStorageItem(key) { + try { + return tryParseJSON(storage.getDataFromLocalStorage(key)); + } catch (e) { } + + return null; +} - return []; +export function setStorageItem(key, value, timestamp) { + try { + const created = timestamp || Date.now(); + const data = JSON.stringify({ value, created }); + storage.setDataInLocalStorage(key, data); + } catch (e) { } +} + +export function tryParseJSON(value) { + try { + return JSON.parse(value); + } catch (e) { + return value; + } } export const spec = { code: BIDDER_CODE, + version: BIDDER_VERSION, supportedMediaTypes: [BANNER], isBidRequestValid, buildRequests, diff --git a/modules/videofyBidAdapter.js b/modules/videofyBidAdapter.js new file mode 100644 index 00000000000..11bc21303fd --- /dev/null +++ b/modules/videofyBidAdapter.js @@ -0,0 +1,300 @@ +import { VIDEO } from '../src/mediaTypes.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; +import * as utils from '../src/utils.js'; + +const BIDDER_CODE = 'videofy'; +const TTL = 600; + +function avRenderer(bid) { + bid.renderer.push(function() { + let eventCallback = bid && bid.renderer && bid.renderer.handleVideoEvent ? bid.renderer.handleVideoEvent : null; + window.aniviewRenderer.renderAd({ + id: bid.adUnitCode + '_' + bid.adId, + debug: window.location.href.indexOf('pbjsDebug') >= 0, + placement: bid.adUnitCode, + width: bid.width, + height: bid.height, + vastUrl: bid.vastUrl, + vastXml: bid.vastXml, + config: bid.params[0].rendererConfig, + eventsCallback: eventCallback, + bid: bid + }); + }); +} + +function newRenderer(bidRequest) { + const renderer = Renderer.install({ + url: 'https://player.srv-mars.com/script/6.1/prebidRenderer.js', + config: {}, + loaded: false, + }); + + try { + renderer.setRender(avRenderer); + } catch (err) { + } + + return renderer; +} + +function isBidRequestValid(bid) { + if (!bid.params || !bid.params.AV_PUBLISHERID || !bid.params.AV_CHANNELID) { return false; } + + return true; +} +let irc = 0; +function buildRequests(validBidRequests, bidderRequest) { + let bidRequests = []; + + for (let i = 0; i < validBidRequests.length; i++) { + let bidRequest = validBidRequests[i]; + var sizes = [[640, 480]]; + + if (bidRequest.mediaTypes && bidRequest.mediaTypes.video && bidRequest.mediaTypes.video.playerSize) { + sizes = bidRequest.mediaTypes.video.playerSize; + } else { + if (bidRequest.sizes) { + sizes = bidRequest.sizes; + } + } + if (sizes.length === 2 && typeof sizes[0] === 'number') { + sizes = [[sizes[0], sizes[1]]]; + } + + for (let j = 0; j < sizes.length; j++) { + let size = sizes[j]; + let playerWidth; + let playerHeight; + + if (size && size.length == 2) { + playerWidth = size[0]; + playerHeight = size[1]; + } else { + playerWidth = 640; + playerHeight = 480; + } + + let s2sParams = {}; + + for (var attrname in bidRequest.params) { + if (bidRequest.params.hasOwnProperty(attrname) && attrname.indexOf('AV_') == 0) { + s2sParams[attrname] = bidRequest.params[attrname]; + } + }; + + if (s2sParams.AV_APPPKGNAME && !s2sParams.AV_URL) { s2sParams.AV_URL = s2sParams.AV_APPPKGNAME; } + if (!s2sParams.AV_IDFA && !s2sParams.AV_URL) { + if (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { + s2sParams.AV_URL = bidderRequest.refererInfo.referer; + } else { + s2sParams.AV_URL = window.location.href; + } + } + if (s2sParams.AV_IDFA && !s2sParams.AV_AID) { s2sParams.AV_AID = s2sParams.AV_IDFA; } + if (s2sParams.AV_AID && !s2sParams.AV_IDFA) { s2sParams.AV_IDFA = s2sParams.AV_AID; } + + s2sParams.cb = Math.floor(Math.random() * 999999999); + s2sParams.AV_WIDTH = playerWidth; + s2sParams.AV_HEIGHT = playerHeight; + s2sParams.bidWidth = playerWidth; + s2sParams.bidHeight = playerHeight; + s2sParams.bidId = bidRequest.bidId; + s2sParams.pbjs = 1; + s2sParams.tgt = 10; + s2sParams.s2s = '1'; + s2sParams.irc = irc; + irc++; + s2sParams.wpm = 1; + + if (bidderRequest && bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.gdprApplies) { + s2sParams.AV_GDPR = 1; + s2sParams.AV_CONSENT = bidderRequest.gdprConsent.consentString; + } + } + if (bidderRequest && bidderRequest.uspConsent) { + s2sParams.AV_CCPA = bidderRequest.uspConsent; + } + + let serverDomain = (bidRequest.params && bidRequest.params.serverDomain) ? bidRequest.params.serverDomain : 'servx.srv-mars.com'; + let servingUrl = 'https://' + serverDomain + '/api/adserver/vast3/'; + + bidRequests.push({ + method: 'GET', + url: servingUrl, + data: s2sParams, + bidRequest + }); + } + } + + return bidRequests; +} +function getCpmData(xml) { + let ret = {cpm: 0, currency: 'USD'}; + if (xml) { + let ext = xml.getElementsByTagName('Extensions'); + if (ext && ext.length > 0) { + ext = ext[0].getElementsByTagName('Extension'); + if (ext && ext.length > 0) { + for (var i = 0; i < ext.length; i++) { + if (ext[i].getAttribute('type') == 'ANIVIEW') { + let price = ext[i].getElementsByTagName('Cpm'); + if (price && price.length == 1) { + ret.cpm = price[0].textContent; + } + break; + } + } + } + } + } + return ret; +} +function interpretResponse(serverResponse, bidRequest) { + let bidResponses = []; + if (serverResponse && serverResponse.body) { + if (serverResponse.error) { + return bidResponses; + } else { + try { + let bidResponse = {}; + if (bidRequest && bidRequest.data && bidRequest.data.bidId && bidRequest.data.bidId !== '') { + let xmlStr = serverResponse.body; + let xml = new window.DOMParser().parseFromString(xmlStr, 'text/xml'); + if (xml && xml.getElementsByTagName('parsererror').length == 0) { + let cpmData = getCpmData(xml); + if (cpmData && cpmData.cpm > 0) { + bidResponse.requestId = bidRequest.data.bidId; + bidResponse.bidderCode = BIDDER_CODE; + bidResponse.ad = ''; + bidResponse.cpm = cpmData.cpm; + bidResponse.width = bidRequest.data.AV_WIDTH; + bidResponse.height = bidRequest.data.AV_HEIGHT; + bidResponse.ttl = TTL; + bidResponse.creativeId = xml.getElementsByTagName('Ad') && xml.getElementsByTagName('Ad')[0] && xml.getElementsByTagName('Ad')[0].getAttribute('id') ? xml.getElementsByTagName('Ad')[0].getAttribute('id') : 'creativeId'; + bidResponse.currency = cpmData.currency; + bidResponse.netRevenue = true; + var blob = new Blob([xmlStr], { + type: 'application/xml' + }); + bidResponse.vastUrl = window.URL.createObjectURL(blob); + bidResponse.vastXml = xmlStr; + bidResponse.mediaType = VIDEO; + if (bidRequest.bidRequest && bidRequest.bidRequest.mediaTypes && bidRequest.bidRequest.mediaTypes.video && bidRequest.bidRequest.mediaTypes.video.context === 'outstream') { bidResponse.renderer = newRenderer(bidRequest); } + + bidResponses.push(bidResponse); + } + } else {} + } else {} + } catch (e) {} + } + } else {} + + return bidResponses; +} + +function getSyncData(xml, options) { + let ret = []; + if (xml) { + let ext = xml.getElementsByTagName('Extensions'); + if (ext && ext.length > 0) { + ext = ext[0].getElementsByTagName('Extension'); + if (ext && ext.length > 0) { + for (var i = 0; i < ext.length; i++) { + if (ext[i].getAttribute('type') == 'ANIVIEW') { + let syncs = ext[i].getElementsByTagName('AdServingSync'); + if (syncs && syncs.length == 1) { + try { + let data = JSON.parse(syncs[0].textContent); + if (data && data.trackers && data.trackers.length) { + data = data.trackers; + for (var j = 0; j < data.length; j++) { + if (typeof data[j] === 'object' && typeof data[j].url === 'string' && data[j].e === 'inventory') { + if (data[j].t == 1 && options.pixelEnabled) { + ret.push({url: data[j].url, type: 'image'}); + } else { + if (data[j].t == 3 && options.iframeEnabled) { + ret.push({url: data[j].url, type: 'iframe'}); + } + } + } + } + } + } catch (e) {} + } + break; + } + } + } + } + } + return ret; +} + +function getUserSyncs(syncOptions, serverResponses) { + if (serverResponses && serverResponses[0] && serverResponses[0].body) { + if (serverResponses.error) { + return []; + } else { + try { + let xmlStr = serverResponses[0].body; + let xml = new window.DOMParser().parseFromString(xmlStr, 'text/xml'); + if (xml && xml.getElementsByTagName('parsererror').length == 0) { + let syncData = getSyncData(xml, syncOptions); + return syncData; + } + } catch (e) {} + } + } +} + +function onBidWon(bid) { + sendbeacon(bid, 17); +} + +function onTimeout(bid) { + sendbeacon(bid, 19); +} + +function onSetTargeting(bid) { + sendbeacon(bid, 20); +} + +function sendbeacon(bid, type) { + const bidCopy = { + bidder: bid.bidder, + cpm: bid.cpm, + originalCpm: bid.originalCpm, + currency: bid.currency, + originalCurrency: bid.originalCurrency, + timeToRespond: bid.timeToRespond, + statusMessage: bid.statusMessage, + width: bid.width, + height: bid.height, + size: bid.size, + params: bid.params, + status: bid.status, + adserverTargeting: bid.adserverTargeting, + ttl: bid.ttl + }; + const bidString = JSON.stringify(bidCopy); + const encodedBuf = window.btoa(bidString); + utils.triggerPixel('https://beacon.videofy.io/notification/rtb/beacon/?bt=' + type + '&bid=hcwqso&hb_j=' + encodedBuf, null); +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [VIDEO], + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs, + onBidWon, + onTimeout, + onSetTargeting +}; + +registerBidder(spec); diff --git a/modules/videofyBidAdapter.md b/modules/videofyBidAdapter.md new file mode 100644 index 00000000000..b50eaf5672e --- /dev/null +++ b/modules/videofyBidAdapter.md @@ -0,0 +1,36 @@ +# Overview + +``` +Module Name: Videofy Bidder Adapter +Module Type: Bidder Adapter +Maintainer: support1@videofy.ai +``` + +# Description + +Connects to Videofy for bids. + +Videofy bid adapter supports Video ads currently. + +# Sample Ad Unit: For Publishers +```javascript +var videoAdUnit = [ +{ + code: 'video1', + mediaTypes: { + video: { + playerSize: [[640, 480]], + context: 'outstream' + }, + }, + bids: [{ + bidder: 'videofy', + params: { + AV_PUBLISHERID: '55b78633181f4603178b4568', + AV_CHANNELID: '5d19dfca4b6236688c0a2fc4' + } + }] +}]; +``` + +``` diff --git a/modules/visxBidAdapter.js b/modules/visxBidAdapter.js index e76b6035cd3..725482d07c3 100644 --- a/modules/visxBidAdapter.js +++ b/modules/visxBidAdapter.js @@ -100,8 +100,8 @@ export const spec = { if (payloadUserId.tdid) { payload.tdid = payloadUserId.tdid; } - if (payloadUserId.id5id) { - payload.id5 = payloadUserId.id5id; + if (payloadUserId.id5id && payloadUserId.id5id.uid) { + payload.id5 = payloadUserId.id5id.uid; } if (payloadUserId.digitrustid && payloadUserId.digitrustid.data && payloadUserId.digitrustid.data.id) { payload.dtid = payloadUserId.digitrustid.data.id; @@ -203,7 +203,6 @@ function _addBidResponse(serverBid, bidsMap, currency, bidResponses, bidsWithout const bid = slot.bids.shift(); bidResponses.push({ requestId: bid.bidId, - bidderCode: spec.code, cpm: serverBid.price, width: serverBid.w, height: serverBid.h, diff --git a/modules/waardexBidAdapter.js b/modules/waardexBidAdapter.js new file mode 100644 index 00000000000..b9114d4f1bf --- /dev/null +++ b/modules/waardexBidAdapter.js @@ -0,0 +1,217 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; + +const domain = 'hb.justbidit.xyz'; +const httpsPort = 8843; +const path = '/prebid'; + +const ENDPOINT = `https://${domain}:${httpsPort}${path}`; + +const BIDDER_CODE = 'waardex'; + +/** + * @param {Array} requestSizes + * + * @returns {Array} + * */ +function transformSizes(requestSizes) { + let sizes = []; + if ( + Array.isArray(requestSizes) && + !Array.isArray(requestSizes[0]) + ) { + sizes[0] = { + width: parseInt(requestSizes[0], 10) || 0, + height: parseInt(requestSizes[1], 10) || 0, + }; + } else if ( + Array.isArray(requestSizes) && + Array.isArray(requestSizes[0]) + ) { + sizes = requestSizes.map(item => { + return { + width: parseInt(item[0], 10) || 0, + height: parseInt(item[1], 10) || 0, + } + }); + } + return sizes; +} + +/** + * @param {Object} banner + * @param {Array} banner.sizes + * + * @returns {Object} + * */ +function createBannerObject(banner) { + return { + sizes: transformSizes(banner.sizes), + }; +} + +/** + * @param {Array} validBidRequests + * + * @returns {Object} + * */ +function buildBidRequests(validBidRequests) { + return validBidRequests.map((validBidRequest) => { + const params = validBidRequest.params; + + const item = { + bidId: validBidRequest.bidId, + bidfloor: parseFloat(params.bidfloor) || 0, + position: parseInt(params.position) || 1, + instl: parseInt(params.instl) || 0, + }; + if (validBidRequest.mediaTypes[BANNER]) { + item[BANNER] = createBannerObject(validBidRequest.mediaTypes[BANNER]); + } + return item; + }); +} + +/** + * @param {Object} bidderRequest + * @param {String} bidderRequest.userAgent + * @param {String} bidderRequest.refererInfo + * @param {String} bidderRequest.uspConsent + * @param {Object} bidderRequest.gdprConsent + * @param {String} bidderRequest.gdprConsent.consentString + * @param {String} bidderRequest.gdprConsent.gdprApplies + * + * @returns {Object} - { + * ua: string, + * language: string, + * [referer]: string, + * [us_privacy]: string, + * [consent_string]: string, + * [consent_required]: string, + * [coppa]: boolean, + * } + * */ +function getCommonBidsData(bidderRequest) { + const payload = { + ua: navigator.userAgent || '', + language: navigator.language && navigator.language.indexOf('-') !== -1 ? navigator.language.split('-')[0] : '', + + }; + if (bidderRequest && bidderRequest.refererInfo) { + payload.referer = encodeURIComponent(bidderRequest.refererInfo.referer); + } + if (bidderRequest && bidderRequest.uspConsent) { + payload.us_privacy = bidderRequest.uspConsent; + } + if (bidderRequest && bidderRequest.gdprConsent) { + payload.gdpr_consent = { + consent_string: bidderRequest.gdprConsent.consentString, + consent_required: bidderRequest.gdprConsent.gdprApplies, + } + } + payload.coppa = !!config.getConfig('coppa'); + + return payload; +} + +/** + * this function checks either bid response is valid or noе + * + * @param {Object} bid + * @param {string} bid.requestId + * @param {number} bid.cpm + * @param {string} bid.creativeId + * @param {number} bid.ttl + * @param {string} bid.currency + * @param {number} bid.width + * @param {number} bid.height + * @param {string} bid.ad + * + * @returns {boolean} + * */ +function isBidValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) { + return false; + } + + return Boolean(bid.width && bid.height && bid.ad); +} + +/** + * @param {Object} serverBid + * + * @returns {Object|null} + * */ +function createBid(serverBid) { + const bid = { + requestId: serverBid.id, + cpm: serverBid.price, + currency: 'USD', + width: serverBid.w, + height: serverBid.h, + creativeId: serverBid.crid, + netRevenue: true, + ttl: 3000, + ad: serverBid.adm, + dealId: serverBid.dealid, + meta: { + cid: serverBid.cid, + adomain: serverBid.adomain, + mediaType: serverBid.ext.mediaType + }, + }; + + return isBidValid(bid) ? bid : null; +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER], + + isBidRequestValid: (bid) => Boolean(bid.bidId && bid.params && +bid.params.zoneId), + + /** + * @param {Object[]} validBidRequests - array of valid bid requests + * @param {Object} bidderRequest - an array of valid bid requests + * + * */ + buildRequests(validBidRequests, bidderRequest) { + const payload = getCommonBidsData(bidderRequest); + payload.bidRequests = buildBidRequests(validBidRequests); + + let zoneId = ''; + if (validBidRequests[0] && validBidRequests[0].params && +validBidRequests[0].params.zoneId) { + zoneId = +validBidRequests[0].params.zoneId; + } + + const url = `${ENDPOINT}?pubId=${zoneId}`; + + return { + method: 'POST', + url, + data: payload + }; + }, + + /** + * Unpack the response from the server into a list of bids. + */ + interpretResponse(serverResponse, bidRequest) { + const bids = []; + serverResponse = serverResponse.body; + + if (serverResponse.seatbid && serverResponse.seatbid[0]) { + const oneSeatBid = serverResponse.seatbid[0]; + oneSeatBid.bid.forEach(serverBid => { + const bid = createBid(serverBid); + if (bid) { + bids.push(bid); + } + }); + } + return bids; + }, +} + +registerBidder(spec); diff --git a/modules/waardexBidAdapter.md b/modules/waardexBidAdapter.md new file mode 100644 index 00000000000..44ee720d31a --- /dev/null +++ b/modules/waardexBidAdapter.md @@ -0,0 +1,60 @@ +# Overview + +``` +Module Name: Waardex Bid Adapter +Module Type: Bidder Adapter +Maintainer: info@prebid.org +``` + +# Description + +Connects to Waardex exchange for bids. + +Waardex bid adapter supports Banner. + +# Test Parameters + +``` + +var sizes = [ + [300, 250] +]; +var PREBID_TIMEOUT = 5000; +var FAILSAFE_TIMEOUT = 5000; + +var adUnits = [{ + code: '/19968336/header-bid-tag-0', + mediaTypes: { + banner: { + sizes: sizes, + }, + }, + bids: [{ + bidder: 'waardex', + params: { + placementId: 13144370, + position: 1, // add position openrtb + bidfloor: 0.5, + instl: 0, // 1 - full screen + pubId: 1, + } + }] +},{ + code: '/19968336/header-bid-tag-1', + mediaTypes: { + banner: { + sizes: sizes, + }, + }, + bids: [{ + bidder: 'waardex', + params: { + placementId: 333333333333, + position: 1, // add position openrtb + bidfloor: 0.5, + instl: 0, // 1 - full screen + pubId: 1, + } + }] +}]; +``` diff --git a/modules/welectBidAdapter.js b/modules/welectBidAdapter.js new file mode 100644 index 00000000000..f9fc57a4834 --- /dev/null +++ b/modules/welectBidAdapter.js @@ -0,0 +1,92 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'welect'; +const DEFAULT_DOMAIN = 'www.welect.de'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['wlt'], + gvlid: 282, + supportedMediaTypes: ['video'], + + // 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 ( + utils.deepAccess(bid, 'mediaTypes.video.context') === 'instream' && + !!bid.params.placementId + ); + }, + /** + * 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) { + return validBidRequests.map((bidRequest) => { + let rawSizes = + utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize') || + bidRequest.sizes; + let size = rawSizes[0]; + + let domain = bidRequest.params.domain || DEFAULT_DOMAIN; + + let url = `https://${domain}/api/v2/preflight/by_alias/${bidRequest.params.placementId}`; + + let gdprConsent = null; + + if (bidRequest && bidRequest.gdprConsent) { + gdprConsent = { + gdpr_consent: { + gdprApplies: bidRequest.gdprConsent.gdprApplies, + tcString: bidRequest.gdprConsent.gdprConsent, + }, + }; + } + + const data = { + width: size[0], + height: size[1], + bid_id: bidRequest.bidId, + ...gdprConsent, + }; + + return { + method: 'POST', + url: url, + data: data, + options: { + contentType: 'application/json', + withCredentials: false, + crossOrigin: true, + }, + }; + }); + }, + /** + * 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, bidRequest) { + const responseBody = serverResponse.body; + + if (typeof responseBody !== 'object' || responseBody.available !== true) { + return []; + } + + const bidResponses = []; + const bidResponse = responseBody.bidResponse; + bidResponses.push(bidResponse); + return bidResponses; + }, +}; +registerBidder(spec); diff --git a/modules/welectBidAdapter.md b/modules/welectBidAdapter.md new file mode 100644 index 00000000000..7f72a0bd949 --- /dev/null +++ b/modules/welectBidAdapter.md @@ -0,0 +1,30 @@ +# Overview + +``` +Module Name: Welect Bidder Adapter +Module Type: Welect Adapter +Maintainer: nick.duitz@9elements.com +``` + +# Description + +Module that connects to Welect's demand sources + +# Test Parameters +``` +var adUnits = [ + { + bidder: 'welect', + params: { + placementId: 'exampleId', + domain: 'www.welect.de' + }, + sizes: [[640, 360]], + mediaTypes: { + video: { + context: 'instream' + } + }, + }; +]; +``` \ No newline at end of file diff --git a/modules/wipesBidAdapter.js b/modules/wipesBidAdapter.js index 5a2c860130f..f381bcb68a0 100644 --- a/modules/wipesBidAdapter.js +++ b/modules/wipesBidAdapter.js @@ -38,7 +38,7 @@ function buildRequests(validBidRequests, bidderRequest) { function interpretResponse(serverResponse, bidRequest) { const bidResponses = []; const response = serverResponse.body; - const cpm = response.cpm * 1000 || 0; + const cpm = response.cpm || 0; if (cpm !== 0) { const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue; const bidResponse = { diff --git a/modules/xhbBidAdapter.js b/modules/xhbBidAdapter.js index 55e5495f505..9363eb97ddc 100644 --- a/modules/xhbBidAdapter.js +++ b/modules/xhbBidAdapter.js @@ -126,7 +126,7 @@ export const spec = { if (syncOptions.iframeEnabled) { return [{ type: 'iframe', - url: 'https://acdn.adnxs.com/ib/static/usersync/v3/async_usersync.html' + url: 'https://acdn.adnxs.com/dmp/async_usersync.html' }]; } } diff --git a/modules/yieldlabBidAdapter.js b/modules/yieldlabBidAdapter.js index 6cfa0c1a548..b252c0db2ee 100644 --- a/modules/yieldlabBidAdapter.js +++ b/modules/yieldlabBidAdapter.js @@ -37,17 +37,31 @@ export const spec = { utils._each(validBidRequests, function (bid) { adslotIds.push(bid.params.adslotId) if (bid.params.targeting) { - query.t = createQueryString(bid.params.targeting) + query.t = createTargetingString(bid.params.targeting) } if (bid.userIdAsEids && Array.isArray(bid.userIdAsEids)) { query.ids = createUserIdString(bid.userIdAsEids) } + if (bid.params.customParams && utils.isPlainObject(bid.params.customParams)) { + for (let prop in bid.params.customParams) { + query[prop] = bid.params.customParams[prop] + } + } + if (bid.schain && utils.isPlainObject(bid.schain) && Array.isArray(bid.schain.nodes)) { + query.schain = createSchainString(bid.schain) + } }) - if (bidderRequest && bidderRequest.gdprConsent) { - query.gdpr = (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true - if (query.gdpr) { - query.consent = bidderRequest.gdprConsent.consentString + if (bidderRequest) { + if (bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { + query.pubref = bidderRequest.refererInfo.referer + } + + if (bidderRequest.gdprConsent) { + query.gdpr = (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true + if (query.gdpr) { + query.consent = bidderRequest.gdprConsent.consentString + } } } @@ -57,7 +71,8 @@ export const spec = { return { method: 'GET', url: `${ENDPOINT}/yp/${adslots}?${queryString}`, - validBidRequests: validBidRequests + validBidRequests: validBidRequests, + queryParams: query } }, @@ -69,6 +84,7 @@ export const spec = { interpretResponse: function (serverResponse, originalBidRequest) { const bidResponses = [] const timestamp = Date.now() + const reqParams = originalBidRequest.queryParams originalBidRequest.validBidRequests.forEach(function (bidRequest) { if (!serverResponse.body) { @@ -84,6 +100,8 @@ export const spec = { const customsize = bidRequest.params.adSize !== undefined ? parseSize(bidRequest.params.adSize) : primarysize const extId = bidRequest.params.extId !== undefined ? '&id=' + bidRequest.params.extId : '' const adType = matchedBid.adtype !== undefined ? matchedBid.adtype : '' + const gdprApplies = reqParams.gdpr ? '&gdpr=' + reqParams.gdpr : '' + const gdprConsent = reqParams.consent ? '&consent=' + reqParams.consent : '' const bidResponse = { requestId: bidRequest.bidId, @@ -96,7 +114,7 @@ export const spec = { netRevenue: false, ttl: BID_RESPONSE_TTL_SEC, referrer: '', - ad: `` + ad: `` } if (isVideo(bidRequest, adType)) { @@ -106,7 +124,7 @@ export const spec = { bidResponse.height = playersize[1] } bidResponse.mediaType = VIDEO - bidResponse.vastUrl = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/${customsize[0]}x${customsize[1]}?ts=${timestamp}${extId}` + bidResponse.vastUrl = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/${customsize[0]}x${customsize[1]}?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}` if (isOutstream(bidRequest)) { const renderer = Renderer.install({ @@ -187,12 +205,58 @@ function createQueryString (obj) { let str = [] for (var p in obj) { if (obj.hasOwnProperty(p)) { - str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p])) + let val = obj[p] + if (p !== 'schain') { + str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)) + } else { + str.push(p + '=' + val) + } } } return str.join('&') } +/** + * Creates an unencoded targeting string out of an object with key-values + * @param {Object} obj + * @returns {String} + */ +function createTargetingString (obj) { + let str = [] + for (var p in obj) { + if (obj.hasOwnProperty(p)) { + let key = p + let val = obj[p] + str.push(key + '=' + val) + } + } + return str.join('&') +} + +/** + * Creates a string out of a schain object + * @param {Object} schain + * @returns {String} + */ +function createSchainString (schain) { + const ver = schain.ver || '' + const complete = schain.complete || '' + const keys = ['asi', 'sid', 'hp', 'rid', 'name', 'domain', 'ext'] + const nodesString = schain.nodes.reduce((acc, node) => { + return acc += `!${keys.map(key => node[key] ? encodeURIComponentWithBangIncluded(node[key]) : '').join(',')}` + }, '') + return `${ver},${complete}${nodesString}` +} + +/** + * Encodes URI Component with exlamation mark included. Needed for schain object. + * @param {String} str + * @returns {String} + */ +function encodeURIComponentWithBangIncluded(str) { + return encodeURIComponent(str).replace(/!/g, '%21') +} + /** * Handles an outstream response after the library is loaded * @param {Object} bid diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js index 304cf45e844..08dc3189eda 100644 --- a/modules/yieldmoBidAdapter.js +++ b/modules/yieldmoBidAdapter.js @@ -16,7 +16,7 @@ export const spec = { * @param {object} bid, bid to validate * @return boolean, true if valid, otherwise false */ - isBidRequestValid: function(bid) { + isBidRequestValid: function (bid) { return !!(bid && bid.adUnitCode && bid.bidId); }, /** @@ -25,38 +25,32 @@ 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, bidderRequest) { + buildRequests: function (bidRequests, bidderRequest) { let serverRequest = { + pbav: '$prebid.version$', p: [], page_url: bidderRequest.refererInfo.referer, bust: new Date().getTime().toString(), pr: bidderRequest.refererInfo.referer, scrd: localWindow.devicePixelRatio || 0, dnt: getDNT(), - e: getEnvironment(), description: getPageDescription(), title: localWindow.document.title || '', w: localWindow.innerWidth, h: localWindow.innerHeight, - userConsent: encodeURIComponent( - JSON.stringify({ - // case of undefined, stringify will remove param - gdprApplies: - bidderRequest && bidderRequest.gdprConsent - ? bidderRequest.gdprConsent.gdprApplies - : '', - cmp: - bidderRequest && bidderRequest.gdprConsent - ? bidderRequest.gdprConsent.consentString - : '', - }) - ), - us_privacy: - bidderRequest && bidderRequest.uspConsent - ? encodeURIComponent(bidderRequest.uspConsent) - : '', + userConsent: JSON.stringify({ + // case of undefined, stringify will remove param + gdprApplies: utils.deepAccess(bidderRequest, 'gdprConsent.gdprApplies') || '', + cmp: utils.deepAccess(bidderRequest, 'gdprConsent.consentString') || '' + }), + us_privacy: utils.deepAccess(bidderRequest, 'uspConsent') || '' }; + const mtp = window.navigator.maxTouchPoints; + if (mtp) { + serverRequest.mtp = mtp; + } + bidRequests.forEach(request => { serverRequest.p.push(addPlacement(request)); const pubcid = getId(request, 'pubcid'); @@ -76,12 +70,11 @@ export const spec = { serverRequest.cri_prebid = criteoId; } if (request.schain) { - serverRequest.schain = encodeURIComponent( - JSON.stringify(request.schain) - ); + serverRequest.schain = + JSON.stringify(request.schain); } }); - serverRequest.p = encodeURIComponent('[' + serverRequest.p.toString() + ']'); + serverRequest.p = '[' + serverRequest.p.toString() + ']'; return { method: 'GET', url: SERVER_ENDPOINT, @@ -93,7 +86,7 @@ export const spec = { * @param serverResponse successful response from Ad Server * @return {Bid[]} an array of bids */ - interpretResponse: function(serverResponse) { + interpretResponse: function (serverResponse) { let bids = []; let data = serverResponse.body; if (data.length > 0) { @@ -105,7 +98,7 @@ export const spec = { } return bids; }, - getUserSyncs: function() { + getUserSyncs: function () { return []; } }; @@ -177,154 +170,6 @@ function getPageDescription() { } } -/*************************************** - * Detect Environment Helper Functions - ***************************************/ - -/** - * Represents a method for loading Yieldmo ads. Environments affect - * which formats can be loaded into the page - * Environments: - * CodeOnPage: 0, // div directly on publisher's page - * Amp: 1, // google Accelerate Mobile Pages ampproject.org - * Mraid = 2, // native loaded through the MRAID spec, without Yieldmo's SDK https://www.iab.net/media/file/IAB_MRAID_v2_FINAL.pdf - * Dfp: 4, // google doubleclick for publishers https://www.doubleclickbygoogle.com/ - * DfpInAmp: 5, // AMP page containing a DFP iframe - * SafeFrame: 10, - * DfpSafeFrame: 11,Sandboxed: 16, // An iframe that can't get to the top window. - * SuperSandboxed: 89, // An iframe without allow-same-origin - * Unknown: 90, // A default sandboxed implementation delivered by EnvironmentDispatch when all positive environment checks fail - */ - -/** - * Detects what environment we're in - * @returns Environment kind - */ -function getEnvironment() { - if (isSuperSandboxedIframe()) { - return 89; - } else if (isDfpInAmp()) { - return 5; - } else if (isDfp()) { - return 4; - } else if (isAmp()) { - return 1; - } else if (isDFPSafeFrame()) { - return 11; - } else if (isSafeFrame()) { - return 10; - } else if (isMraid()) { - return 2; - } else if (isCodeOnPage()) { - return 0; - } else if (isSandboxedIframe()) { - return 16; - } else { - return 90; - } -} - -/** - * @returns true if we are running on the top window at dispatch time - */ -function isCodeOnPage() { - return window === window.parent; -} - -/** - * @returns true if the environment is both DFP and AMP - */ -function isDfpInAmp() { - return isDfp() && isAmp(); -} - -/** - * @returns true if the window is in an iframe whose id and parent element id match DFP - */ -function isDfp() { - try { - const frameElement = window.frameElement; - const parentElement = window.frameElement.parentNode; - if (frameElement && parentElement) { - return ( - frameElement.id.indexOf('google_ads_iframe') > -1 && - parentElement.id.indexOf('google_ads_iframe') > -1 - ); - } - return false; - } catch (e) { - return false; - } -} - -/** - * @returns true if there is an AMP context object - */ -function isAmp() { - try { - const ampContext = window.context || window.parent.context; - if (ampContext && ampContext.pageViewId) { - return ampContext; - } - return false; - } catch (e) { - return false; - } -} - -/** - * @returns true if the environment is a SafeFrame. - */ -function isSafeFrame() { - return window.$sf && window.$sf.ext; -} - -/** - * @returns true if the environment is a dfp safe frame. - */ -function isDFPSafeFrame() { - if (window.location && window.location.href) { - const href = window.location.href; - return ( - isSafeFrame() && - href.indexOf('google') !== -1 && - href.indexOf('safeframe') !== -1 - ); - } - return false; -} - -/** - * Return true if we are in an iframe and can't access the top window. - */ -function isSandboxedIframe() { - return window.top !== window && !window.frameElement; -} - -/** - * Return true if we cannot document.write to a child iframe (this implies no allow-same-origin) - */ -function isSuperSandboxedIframe() { - const sacrificialIframe = window.document.createElement('iframe'); - try { - sacrificialIframe.setAttribute('style', 'display:none'); - window.document.body.appendChild(sacrificialIframe); - sacrificialIframe.contentWindow._testVar = true; - window.document.body.removeChild(sacrificialIframe); - return false; - } catch (e) { - window.document.body.removeChild(sacrificialIframe); - return true; - } -} - -/** - * @returns true if the window has the attribute identifying MRAID - */ -function isMraid() { - return !!window.mraid; -} - /** * Gets an id from the userId object if it exists * @param {*} request @@ -332,14 +177,5 @@ function isMraid() { * @returns an id if there is one, or undefined */ function getId(request, idType) { - let id; - if ( - request && - request.userId && - request.userId[idType] && - typeof request.userId === 'object' - ) { - id = request.userId[idType]; - } - return id; + return (typeof utils.deepAccess(request, 'userId') === 'object') ? request.userId[idType] : undefined; } diff --git a/modules/yieldoneAnalyticsAdapter.js b/modules/yieldoneAnalyticsAdapter.js index b3f89610b72..542c0917708 100644 --- a/modules/yieldoneAnalyticsAdapter.js +++ b/modules/yieldoneAnalyticsAdapter.js @@ -13,6 +13,10 @@ const defaultUrl = 'https://pool.tsukiji.iponweb.net/hba'; const requestedBidders = {}; const requestedBids = {}; const referrers = {}; +const ignoredEvents = {}; +ignoredEvents[CONSTANTS.EVENTS.BID_ADJUSTMENT] = true; +ignoredEvents[CONSTANTS.EVENTS.BIDDER_DONE] = true; +ignoredEvents[CONSTANTS.EVENTS.AUCTION_END] = true; let currentAuctionId = ''; let url = defaultUrl; @@ -108,7 +112,9 @@ const yieldoneAnalytics = Object.assign(adapter({analyticsType}), { return res; }); } - eventsStorage[currentAuctionId].events.push({eventType, params}); + if (!ignoredEvents[eventType]) { + eventsStorage[currentAuctionId].events.push({eventType, params}); + } if ( eventType === CONSTANTS.EVENTS.AUCTION_END || eventType === CONSTANTS.EVENTS.BID_WON @@ -117,24 +123,24 @@ const yieldoneAnalytics = Object.assign(adapter({analyticsType}), { auctionManager.getAdUnitCodes(), auctionManager.getBidsReceived() ); - if (yieldoneAnalytics.eventsStorage[currentAuctionId]) { + if (yieldoneAnalytics.eventsStorage[currentAuctionId] && yieldoneAnalytics.eventsStorage[currentAuctionId].events.length) { yieldoneAnalytics.eventsStorage[currentAuctionId].page = {url: referrers[currentAuctionId]}; yieldoneAnalytics.eventsStorage[currentAuctionId].pubId = pubId; yieldoneAnalytics.eventsStorage[currentAuctionId].wrapper_version = '$prebid.version$'; - yieldoneAnalytics.eventsStorage[currentAuctionId].events.forEach((it) => { - const adUnitNameMap = makeAdUnitNameMap(); - if (adUnitNameMap) { + const adUnitNameMap = makeAdUnitNameMap(); + if (adUnitNameMap) { + yieldoneAnalytics.eventsStorage[currentAuctionId].events.forEach((it) => { addAdUnitName(it.params, adUnitNameMap); - } - }); + }); + } } yieldoneAnalytics.sendStat(yieldoneAnalytics.eventsStorage[currentAuctionId], currentAuctionId); } } } }, - sendStat(events, auctionId) { - if (!events) return; + sendStat(data, auctionId) { + if (!data || !data.events || !data.events.length) return; delete yieldoneAnalytics.eventsStorage[auctionId]; ajax( url, @@ -142,7 +148,7 @@ const yieldoneAnalytics = Object.assign(adapter({analyticsType}), { success: function() {}, error: function() {} }, - JSON.stringify(events), + JSON.stringify(data), { method: 'POST' } diff --git a/modules/yieldoneBidAdapter.js b/modules/yieldoneBidAdapter.js index 59240878426..574967db291 100644 --- a/modules/yieldoneBidAdapter.js +++ b/modules/yieldoneBidAdapter.js @@ -8,6 +8,7 @@ const BIDDER_CODE = 'yieldone'; const ENDPOINT_URL = 'https://y.one.impact-ad.jp/h_bid'; const USER_SYNC_URL = 'https://y.one.impact-ad.jp/push_sync'; const VIDEO_PLAYER_URL = 'https://img.ak.impact-ad.jp/ic/pone/ivt/firstview/js/dac-video-prebid.min.js'; +const CMER_PLAYER_URL = 'https://an.cmertv.com/hb/renderer/cmertv-video-yone-prebid.min.js'; const VIEWABLE_PERCENTAGE_URL = 'https://img.ak.impact-ad.jp/ic/pone/ivt/firstview/js/prebid-adformat-config.js'; export const spec = { @@ -136,7 +137,11 @@ export const spec = { } else if (response.adm) { bidResponse.mediaType = VIDEO; bidResponse.vastXml = response.adm; - bidResponse.renderer = newRenderer(response); + if (renderId === 'cmer') { + bidResponse.renderer = newCmerRenderer(response); + } else { + bidResponse.renderer = newRenderer(response); + } } bidResponses.push(bidResponse); @@ -175,4 +180,26 @@ function outstreamRender(bid) { }); } +function newCmerRenderer(response) { + const renderer = Renderer.install({ + id: response.uid, + url: CMER_PLAYER_URL, + loaded: false, + }); + + try { + renderer.setRender(cmerRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on newRenderer', err); + } + + return renderer; +} + +function cmerRender(bid) { + bid.renderer.push(() => { + window.CMERYONEPREBID.renderPrebid(bid); + }); +} + registerBidder(spec); diff --git a/modules/yuktamediaAnalyticsAdapter.js b/modules/yuktamediaAnalyticsAdapter.js index b346a26c843..caca3bf3341 100644 --- a/modules/yuktamediaAnalyticsAdapter.js +++ b/modules/yuktamediaAnalyticsAdapter.js @@ -3,134 +3,256 @@ import adapter from '../src/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import CONSTANTS from '../src/constants.json'; import * as utils from '../src/utils.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { getRefererInfo } from '../src/refererDetection.js'; -const emptyUrl = ''; -const analyticsType = 'endpoint'; -const yuktamediaAnalyticsVersion = 'v2.0.0'; +const storage = getStorageManager(); +const yuktamediaAnalyticsVersion = 'v3.1.0'; let initOptions; -let auctionTimestamp; -let events = { - bids: [] + +const events = { + auctions: {} +}; +const localStoragePrefix = 'yuktamediaAnalytics_'; +const utmTags = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']; +const location = utils.getWindowLocation(); +const referer = getRefererInfo().referer; +const _pageInfo = { + userAgent: window.navigator.userAgent, + timezoneOffset: new Date().getTimezoneOffset(), + language: window.navigator.language, + screenWidth: window.screen.width, + screenHeight: window.screen.height, + pageViewId: utils.generateUUID(), + host: location.host, + path: location.pathname, + search: location.search, + hash: location.hash, + referer: referer, + refererDomain: utils.parseUrl(referer).host, + yuktamediaAnalyticsVersion: yuktamediaAnalyticsVersion, + prebidVersion: $$PREBID_GLOBAL$$.version }; -var yuktamediaAnalyticsAdapter = Object.assign(adapter( - { - emptyUrl, - analyticsType - }), { - track({ eventType, args }) { - if (typeof args !== 'undefined') { - if (eventType === CONSTANTS.EVENTS.BID_TIMEOUT) { - args.forEach(item => { mapBidResponse(item, 'timeout'); }); - } else if (eventType === CONSTANTS.EVENTS.AUCTION_INIT) { - events.auctionInit = args; - auctionTimestamp = args.timestamp; - } else if (eventType === CONSTANTS.EVENTS.BID_REQUESTED) { - mapBidRequests(args).forEach(item => { events.bids.push(item) }); - } else if (eventType === CONSTANTS.EVENTS.BID_RESPONSE) { - mapBidResponse(args, 'response'); - } else if (eventType === CONSTANTS.EVENTS.BID_WON) { - send({ - bidWon: mapBidResponse(args, 'win') - }, 'won'); - } +function getParameterByName(param) { + let vars = {}; + window.location.href.replace(location.hash, '').replace( + /[?&]+([^=&]+)=?([^&]*)?/gi, + function (m, key, value) { + vars[key] = value !== undefined ? value : ''; } + ); + return vars[param] ? vars[param] : ''; +} - if (eventType === CONSTANTS.EVENTS.AUCTION_END) { - send(events, 'auctionEnd'); - } - } -}); +function isNavigatorSendBeaconSupported() { + return ('navigator' in window) && ('sendBeacon' in window.navigator); +} -function mapBidRequests(params) { - let arr = []; - if (typeof params.bids !== 'undefined' && params.bids.length) { - params.bids.forEach(function (bid) { - arr.push({ - bidderCode: bid.bidder, - bidId: bid.bidId, - adUnitCode: bid.adUnitCode, - requestId: bid.bidderRequestId, - auctionId: bid.auctionId, - transactionId: bid.transactionId, - sizes: utils.parseSizesInput(bid.mediaTypes.banner.sizes).toString(), - renderStatus: 1, - requestTimestamp: params.auctionStart - }); - }); +function updateSessionId() { + if (isSessionIdTimeoutExpired()) { + let newSessionId = utils.generateUUID(); + storage.setDataInLocalStorage(localStoragePrefix.concat('session_id'), newSessionId); } - return arr; + initOptions.sessionId = getSessionId(); + updateSessionIdTimeout(); } -function mapBidResponse(bidResponse, status) { - if (status !== 'win') { - let bid = events.bids.filter(o => o.bidId == bidResponse.bidId || o.bidId == bidResponse.requestId)[0]; - Object.assign(bid, { - bidderCode: bidResponse.bidder, - bidId: status == 'timeout' ? bidResponse.bidId : bidResponse.requestId, - adUnitCode: bidResponse.adUnitCode, - auctionId: bidResponse.auctionId, - creativeId: bidResponse.creativeId, - transactionId: bidResponse.transactionId, - currency: bidResponse.currency, - cpm: bidResponse.cpm, - netRevenue: bidResponse.netRevenue, - mediaType: bidResponse.mediaType, - statusMessage: bidResponse.statusMessage, - status: bidResponse.status, - renderStatus: status == 'timeout' ? 3 : 2, - timeToRespond: bidResponse.timeToRespond, - requestTimestamp: bidResponse.requestTimestamp, - responseTimestamp: bidResponse.responseTimestamp - }); - } else if (status == 'win') { - return { - bidderCode: bidResponse.bidder, - bidId: bidResponse.requestId, - adUnitCode: bidResponse.adUnitCode, - auctionId: bidResponse.auctionId, - creativeId: bidResponse.creativeId, - transactionId: bidResponse.transactionId, - currency: bidResponse.currency, - cpm: bidResponse.cpm, - netRevenue: bidResponse.netRevenue, - renderedSize: bidResponse.size, - mediaType: bidResponse.mediaType, - statusMessage: bidResponse.statusMessage, - status: bidResponse.status, - renderStatus: 4, - timeToRespond: bidResponse.timeToRespond, - requestTimestamp: bidResponse.requestTimestamp, - responseTimestamp: bidResponse.responseTimestamp - } - } +function updateSessionIdTimeout() { + storage.setDataInLocalStorage(localStoragePrefix.concat('session_timeout'), Date.now()); } -function send(data, status) { - let location = utils.getWindowLocation(); - if (typeof data !== 'undefined' && typeof data.auctionInit !== 'undefined') { - data.auctionInit = Object.assign({ host: location.host, path: location.pathname, search: location.search }, data.auctionInit); - } - data.initOptions = initOptions; +function isSessionIdTimeoutExpired() { + let cpmSessionTimestamp = storage.getDataFromLocalStorage(localStoragePrefix.concat('session_timeout')); + return Date.now() - cpmSessionTimestamp > 3600000; +} + +function getSessionId() { + return storage.getDataFromLocalStorage(localStoragePrefix.concat('session_id')) ? storage.getDataFromLocalStorage(localStoragePrefix.concat('session_id')) : ''; +} + +function isUtmTimeoutExpired() { + let utmTimestamp = storage.getDataFromLocalStorage(localStoragePrefix.concat('utm_timeout')); + return (Date.now() - utmTimestamp) > 3600000; +} - let yuktamediaAnalyticsRequestUrl = utils.buildUrl({ +function send(data, status) { + data.initOptions = Object.assign(_pageInfo, initOptions); + const yuktamediaAnalyticsRequestUrl = utils.buildUrl({ protocol: 'https', hostname: 'analytics-prebid.yuktamedia.com', - pathname: status == 'auctionEnd' ? '/api/bids' : '/api/bid/won', - search: { - auctionTimestamp: auctionTimestamp, - yuktamediaAnalyticsVersion: yuktamediaAnalyticsVersion, - prebidVersion: $$PREBID_GLOBAL$$.version - } + pathname: '/api/bids' }); - - ajax(yuktamediaAnalyticsRequestUrl, undefined, JSON.stringify(data), { method: 'POST', contentType: 'text/plain' }); + if (isNavigatorSendBeaconSupported()) { + window.navigator.sendBeacon(yuktamediaAnalyticsRequestUrl, JSON.stringify(data)); + } else { + ajax(yuktamediaAnalyticsRequestUrl, undefined, JSON.stringify(data), { method: 'POST', contentType: 'text/plain' }); + } } +var yuktamediaAnalyticsAdapter = Object.assign(adapter({ analyticsType: 'endpoint' }), { + track({ eventType, args }) { + if (typeof args !== 'undefined') { + switch (eventType) { + case CONSTANTS.EVENTS.AUCTION_INIT: + utils.logInfo(localStoragePrefix + 'AUCTION_INIT:', JSON.stringify(args)); + if (typeof args.auctionId !== 'undefined' && args.auctionId.length) { + events.auctions[args.auctionId] = { bids: {} }; + } + break; + case CONSTANTS.EVENTS.BID_REQUESTED: + utils.logInfo(localStoragePrefix + 'BID_REQUESTED:', JSON.stringify(args)); + if (typeof args.auctionId !== 'undefined' && args.auctionId.length) { + if (typeof events.auctions[args.auctionId] === 'undefined') { + events.auctions[args.auctionId] = { bids: {} }; + } + events.auctions[args.auctionId]['timeStamp'] = args.start; + args.bids.forEach(function (bidRequest) { + events.auctions[args.auctionId]['bids'][bidRequest.bidId] = { + bidder: bidRequest.bidder, + adUnit: bidRequest.adUnitCode, + sizes: utils.parseSizesInput(bidRequest.sizes).toString(), + isBid: false, + won: false, + timeout: false, + renderStatus: 'bid-requested', + bidId: bidRequest.bidId, + auctionId: args.auctionId + } + if (typeof initOptions.enableUserIdCollection !== 'undefined' && initOptions.enableUserIdCollection && typeof bidRequest['userId'] !== 'undefined') { + for (let [userIdProvider, userId] in Object.entries(bidRequest['userId'])) { + userIdProvider = typeof userIdProvider !== 'string' ? JSON.stringify(userIdProvider) : userIdProvider; + userId = typeof userId !== 'string' ? JSON.stringify(userId) : userId; + events.auctions[args.auctionId]['bids'][bidRequest.bidId]['userID-'.concat(userIdProvider)] = userId; + } + } + }); + } + break; + case CONSTANTS.EVENTS.BID_RESPONSE: + utils.logInfo(localStoragePrefix + 'BID_RESPONSE:', JSON.stringify(args)); + if (typeof args.auctionId !== 'undefined' && args.auctionId.length) { + if (typeof events.auctions[args.auctionId] === 'undefined') { + events.auctions[args.auctionId] = { bids: {} }; + } else if (Object.keys(events.auctions[args.auctionId]['bids']).length) { + let bidResponse = events.auctions[args.auctionId]['bids'][args.requestId]; + bidResponse.isBid = args.getStatusCode() === CONSTANTS.STATUS.GOOD; + bidResponse.cpm = args.cpm; + bidResponse.currency = args.currency; + bidResponse.netRevenue = args.netRevenue; + bidResponse.dealId = typeof args.dealId !== 'undefined' ? args.dealId : ''; + bidResponse.mediaType = args.mediaType; + if (bidResponse.mediaType === 'native') { + bidResponse.nativeTitle = typeof args['native']['title'] !== 'undefined' ? args['native']['title'] : ''; + bidResponse.nativeSponsoredBy = typeof args['native']['sponsoredBy'] !== 'undefined' ? args['native']['sponsoredBy'] : ''; + } + bidResponse.timeToRespond = args.timeToRespond; + bidResponse.requestTimestamp = args.requestTimestamp; + bidResponse.responseTimestamp = args.responseTimestamp; + bidResponse.bidForSize = args.size; + for (const [adserverTargetingKey, adserverTargetingValue] of Object.entries(args.adserverTargeting)) { + if (['body', 'icon', 'image', 'linkurl', 'host', 'path'].every((ele) => !adserverTargetingKey.includes(ele))) { + bidResponse['adserverTargeting-' + adserverTargetingKey] = adserverTargetingValue; + } + } + bidResponse.renderStatus = 'bid-response-received'; + } + } + break; + case CONSTANTS.EVENTS.NO_BID: + utils.logInfo(localStoragePrefix + 'NO_BID:', JSON.stringify(args)); + if (typeof args.auctionId !== 'undefined' && args.auctionId.length) { + if (typeof events.auctions[args.auctionId] === 'undefined') { + events.auctions[args.auctionId] = { bids: {} }; + } else if (Object.keys(events.auctions[args.auctionId]['bids']).length) { + const noBid = events.auctions[args.auctionId]['bids'][args.bidId]; + noBid.renderStatus = 'no-bid'; + } + } + break; + case CONSTANTS.EVENTS.BID_WON: + utils.logInfo(localStoragePrefix + 'BID_WON:', JSON.stringify(args)); + if (typeof initOptions.enableSession !== 'undefined' && initOptions.enableSession) { + updateSessionId(); + } + if (typeof args.auctionId !== 'undefined' && args.auctionId.length) { + if (typeof events.auctions[args.auctionId] === 'undefined') { + events.auctions[args.auctionId] = { bids: {} }; + } else if (Object.keys(events.auctions[args.auctionId]['bids']).length) { + const wonBid = events.auctions[args.auctionId]['bids'][args.requestId]; + wonBid.won = true; + wonBid.renderStatus = 'bid-won'; + send({ 'bids': [wonBid] }, 'won'); + } + } + break; + case CONSTANTS.EVENTS.BID_TIMEOUT: + utils.logInfo(localStoragePrefix + 'BID_TIMEOUT:', JSON.stringify(args)); + if (args.length) { + args.forEach(timeout => { + if (typeof timeout !== 'undefined' && typeof timeout.auctionId !== 'undefined' && timeout.auctionId.length) { + if (typeof events.auctions[args.auctionId] === 'undefined') { + events.auctions[args.auctionId] = { bids: {} }; + } else if (Object.keys(events.auctions[args.auctionId]['bids']).length) { + const timeoutBid = events.auctions[timeout.auctionId].bids[timeout.bidId]; + timeoutBid.timeout = true; + timeoutBid.renderStatus = 'bid-timedout'; + } + } + }); + } + break; + case CONSTANTS.EVENTS.AUCTION_END: + utils.logInfo(localStoragePrefix + 'AUCTION_END:', JSON.stringify(args)); + if (typeof initOptions.enableSession !== 'undefined' && initOptions.enableSession) { + updateSessionId(); + } + if (typeof args.auctionId !== 'undefined' && args.auctionId.length) { + const bids = Object.values(events.auctions[args.auctionId]['bids']); + send({ 'bids': bids }, 'auctionEnd'); + } + break; + } + } + } +}); + +yuktamediaAnalyticsAdapter.buildUtmTagData = function (options) { + let utmTagData = {}; + let utmTagsDetected = false; + if (typeof options.enableUTMCollection !== 'undefined' && options.enableUTMCollection) { + utmTags.forEach(function (utmTagKey) { + let utmTagValue = getParameterByName(utmTagKey); + if (utmTagValue !== '') { + utmTagsDetected = true; + } + utmTagData[utmTagKey] = utmTagValue; + }); + utmTags.forEach(function (utmTagKey) { + if (utmTagsDetected) { + storage.setDataInLocalStorage(localStoragePrefix.concat(utmTagKey), utmTagData[utmTagKey]); + storage.setDataInLocalStorage(localStoragePrefix.concat('utm_timeout'), Date.now()); + } else { + if (!isUtmTimeoutExpired()) { + utmTagData[utmTagKey] = storage.getDataFromLocalStorage(localStoragePrefix.concat(utmTagKey)) ? storage.getDataFromLocalStorage(localStoragePrefix.concat(utmTagKey)) : ''; + storage.setDataInLocalStorage(localStoragePrefix.concat('utm_timeout'), Date.now()); + } + } + }); + } + return utmTagData; +}; + yuktamediaAnalyticsAdapter.originEnableAnalytics = yuktamediaAnalyticsAdapter.enableAnalytics; yuktamediaAnalyticsAdapter.enableAnalytics = function (config) { - initOptions = config.options; + if (config && config.options) { + if (typeof config.options.pubId === 'undefined' || typeof config.options.pubKey === 'undefined') { + utils.logError('Need pubId and pubKey to log auction results. Please contact a YuktaMedia representative if you do not know your pubId and pubKey.'); + return; + } + } + initOptions = Object.assign({}, config.options, this.buildUtmTagData(config.options)); yuktamediaAnalyticsAdapter.originEnableAnalytics(config); }; diff --git a/modules/yuktamediaAnalyticsAdapter.md b/modules/yuktamediaAnalyticsAdapter.md index a21675b6b1d..af47985c834 100644 --- a/modules/yuktamediaAnalyticsAdapter.md +++ b/modules/yuktamediaAnalyticsAdapter.md @@ -1,5 +1,5 @@ # Overview -Module Name: YuktaMedia Analytics Adapter +Module Name: YuktaOne Analytics by YuktaMedia Module Type: Analytics Adapter @@ -15,8 +15,11 @@ Analytics adapter for prebid provided by YuktaMedia. Contact info@yuktamedia.com { provider: 'yuktamedia', options : { - pubId : 50357 //id provided by YuktaMedia LLP - pubKey: 'xxx' //key provided by YuktaMedia LLP + pubId : 50357, // id provided by YuktaMedia LLP + pubKey: 'xxx', // key provided by YuktaMedia LLP + enableUTMCollection: true, // set true if want to collect utm info + enableSession: true, // set true if want to collect information by sessions + enableUserIdCollection: true // set true if want to collect user ID module info } } ``` diff --git a/modules/zedoBidAdapter.js b/modules/zedoBidAdapter.js new file mode 100644 index 00000000000..e75b9c82065 --- /dev/null +++ b/modules/zedoBidAdapter.js @@ -0,0 +1,342 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import find from 'core-js-pure/features/array/find'; +import { Renderer } from '../src/Renderer.js'; +import { getRefererInfo } from '../src/refererDetection.js'; + +const BIDDER_CODE = 'zedo'; +const SECURE_URL = 'https://saxp.zedo.com/asw/fmh.json'; +const DIM_TYPE = { + '7': 'display', + '9': 'display', + '14': 'display', + '70': 'SBR', + '83': 'CurtainRaiser', + '85': 'Inarticle', + '86': 'pswipeup', + '88': 'Inview', + '100': 'display', + '101': 'display', + '102': 'display', + '103': 'display' + // '85': 'pre-mid-post-roll', +}; +const SECURE_EVENT_PIXEL_URL = 'tt1.zedo.com/log/p.gif'; + +export const spec = { + code: BIDDER_CODE, + aliases: [], + supportedMediaTypes: [BANNER, VIDEO], + + /** + * 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 && bid.params.channelCode && bid.params.dimId); + }, + + /** + * 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) { + let data = { + placements: [] + }; + bidRequests.map(bidRequest => { + let channelCode = parseInt(bidRequest.params.channelCode); + let network = parseInt(channelCode / 1000000); + let channel = channelCode % 1000000; + let dim = getSizes(bidRequest.sizes); + let placement = { + id: bidRequest.bidId, + network: network, + channel: channel, + publisher: bidRequest.params.pubId ? bidRequest.params.pubId : 0, + width: dim[0], + height: dim[1], + dimension: bidRequest.params.dimId, + version: '$prebid.version$', + keyword: '', + transactionId: bidRequest.transactionId + } + if (bidderRequest && bidderRequest.gdprConsent) { + if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { + data.gdpr = Number(bidderRequest.gdprConsent.gdprApplies); + } + data.gdpr_consent = bidderRequest.gdprConsent.consentString; + } + // Add CCPA consent string + if (bidderRequest && bidderRequest.uspConsent) { + data.usp = bidderRequest.uspConsent; + } + + let dimType = DIM_TYPE[String(bidRequest.params.dimId)] + if (dimType) { + placement['renderers'] = [{ + 'name': dimType + }] + } else { // default to display + placement['renderers'] = [{ + 'name': 'display' + }] + } + data['placements'].push(placement); + }); + // adding schain object + if (bidRequests[0].schain) { + data['supplyChain'] = getSupplyChain(bidRequests[0].schain); + } + return { + method: 'GET', + url: SECURE_URL, + data: 'g=' + JSON.stringify(data) + } + }, + + /** + * 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, request) { + serverResponse = serverResponse.body; + const bids = []; + if (!serverResponse || serverResponse.error) { + let errorMessage = `in response for ${request.bidderCode} adapter`; + if (serverResponse && serverResponse.error) { errorMessage += `: ${serverResponse.error}`; } + utils.logError(errorMessage); + return bids; + } + + if (serverResponse.ad) { + serverResponse.ad.forEach(ad => { + const creativeBid = getCreative(ad); + if (creativeBid) { + if (parseInt(creativeBid.cpm) !== 0) { + const bid = newBid(ad, creativeBid, request); + bid.mediaType = parseMediaType(creativeBid); + bids.push(bid); + } + } + }); + } + return bids; + }, + + getUserSyncs: function (syncOptions, responses, gdprConsent) { + if (syncOptions.iframeEnabled) { + let url = 'https://tt3.zedo.com/rs/us/fcs.html'; + if (gdprConsent && typeof gdprConsent.consentString === 'string') { + // add 'gdpr' only if 'gdprApplies' is defined + if (typeof gdprConsent.gdprApplies === 'boolean') { + url += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + url += `?gdpr_consent=${gdprConsent.consentString}`; + } + } + return [{ + type: 'iframe', + url: url + }]; + } + }, + + onTimeout: function (timeoutData) { + try { + logEvent('117', timeoutData); + } catch (e) { + utils.logError(e); + } + }, + + onBidWon: function (bid) { + try { + logEvent('116', [bid]); + } catch (e) { + utils.logError(e); + } + } + +}; + +function getSupplyChain (supplyChain) { + return { + complete: supplyChain.complete, + nodes: supplyChain.nodes + } +}; + +function getCreative(ad) { + return ad && ad.creatives && ad.creatives.length && find(ad.creatives, creative => creative.adId); +}; +/** + * Unpack the Server's Bid into a Prebid-compatible one. + * @param serverBid + * @param rtbBid + * @param bidderRequest + * @return Bid + */ +function newBid(serverBid, creativeBid, bidderRequest) { + const bid = { + requestId: serverBid.slotId, + creativeId: creativeBid.adId, + network: serverBid.network, + adType: creativeBid.creativeDetails.type, + dealId: 99999999, + currency: 'USD', + netRevenue: true, + ttl: 300 + }; + + if (creativeBid.creativeDetails.type === 'VAST') { + Object.assign(bid, { + width: creativeBid.width, + height: creativeBid.height, + vastXml: creativeBid.creativeDetails.adContent, + cpm: parseInt(creativeBid.bidCpm) / 1000000, + ttl: 3600 + }); + const rendererOptions = utils.deepAccess( + bidderRequest, + 'renderer.options' + ); + let rendererUrl = 'https://ss3.zedo.com/gecko/beta/fmpbgt.min.js'; + Object.assign(bid, { + adResponse: serverBid, + renderer: getRenderer(bid.adUnitCode, serverBid.slotId, rendererUrl, rendererOptions) + }); + } else { + Object.assign(bid, { + width: creativeBid.width, + height: creativeBid.height, + cpm: parseInt(creativeBid.bidCpm) / 1000000, + ad: creativeBid.creativeDetails.adContent, + }); + } + + return bid; +} +/* Turn bid request sizes into compatible format */ +function getSizes(requestSizes) { + let width = 0; + let height = 0; + if (utils.isArray(requestSizes) && requestSizes.length === 2 && + !utils.isArray(requestSizes[0])) { + width = parseInt(requestSizes[0], 10); + height = parseInt(requestSizes[1], 10); + } else if (typeof requestSizes === 'object') { + for (let i = 0; i < requestSizes.length; i++) { + let size = requestSizes[i]; + width = parseInt(size[0], 10); + height = parseInt(size[1], 10); + break; + } + } + return [width, height]; +} + +function getRenderer(adUnitCode, rendererId, rendererUrl, rendererOptions = {}) { + const renderer = Renderer.install({ + id: rendererId, + url: rendererUrl, + config: rendererOptions, + loaded: false, + }); + + try { + renderer.setRender(videoRenderer); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on renderer', err); + } + + renderer.setEventHandlers({ + impression: () => utils.logMessage('ZEDO video impression'), + loaded: () => utils.logMessage('ZEDO video loaded'), + ended: () => { + utils.logMessage('ZEDO renderer video ended'); + document.querySelector(`#${adUnitCode}`).style.display = 'none'; + } + }); + return renderer; +} + +function videoRenderer(bid) { + // push to render queue + const refererInfo = getRefererInfo(); + let referrer = ''; + if (refererInfo) { + referrer = refererInfo.referer; + } + bid.renderer.push(() => { + let channelCode = utils.deepAccess(bid, 'params.0.channelCode') || 0; + let dimId = utils.deepAccess(bid, 'params.0.dimId') || 0; + let publisher = utils.deepAccess(bid, 'params.0.pubId') || 0; + let options = utils.deepAccess(bid, 'params.0.options') || {}; + let channel = (channelCode > 0) ? (channelCode - (bid.network * 1000000)) : 0; + + var rndr = new window.ZdPBTag(bid.adUnitCode, bid.network, bid.width, bid.height, bid.adType, bid.vastXml, channel, dimId, + (encodeURI(referrer) || ''), options); + rndr.renderAd(publisher); + }); +} + +function parseMediaType(creativeBid) { + const adType = creativeBid.creativeDetails.type; + if (adType === 'VAST') { + return VIDEO; + } else { + return BANNER; + } +} + +function logEvent(eid, data) { + let getParams = { + protocol: 'https', + hostname: SECURE_EVENT_PIXEL_URL, + search: getLoggingData(eid, data) + }; + let eventUrl = utils.buildUrl(getParams).replace(/&/g, ';'); + utils.triggerPixel(eventUrl); +} + +function getLoggingData(eid, data) { + data = (utils.isArray(data) && data) || []; + + let params = {}; + let channel, network, dim, publisher, adunitCode, timeToRespond, cpm; + data.map((adunit) => { + adunitCode = adunit.adUnitCode; + channel = utils.deepAccess(adunit, 'params.0.channelCode') || 0; + network = channel > 0 ? parseInt(channel / 1000000) : 0; + dim = utils.deepAccess(adunit, 'params.0.dimId') * 256 || 0; + publisher = utils.deepAccess(adunit, 'params.0.pubId') || 0; + timeToRespond = adunit.timeout ? adunit.timeout : adunit.timeToRespond; + cpm = adunit.cpm; + }); + let referrer = ''; + const refererInfo = getRefererInfo(); + if (refererInfo) { + referrer = refererInfo.referer; + } + params.n = network; + params.c = channel; + params.s = publisher; + params.x = dim; + params.ai = encodeURI('Prebid^zedo^' + adunitCode + '^' + cpm + '^' + timeToRespond); + params.pu = encodeURI(referrer) || ''; + params.eid = eid; + params.e = 'e'; + params.z = Math.random(); + + return params; +} + +registerBidder(spec); diff --git a/modules/zedoBidAdapter.md b/modules/zedoBidAdapter.md index e0f9101deaa..2f31e8aed9b 100644 --- a/modules/zedoBidAdapter.md +++ b/modules/zedoBidAdapter.md @@ -18,22 +18,23 @@ ZEDO has its own renderer and will render the video unit if not defined in the c # display ``` - var adUnits = [ - { - code: 'banner-ad-div', - sizes: [[300, 250], [728, 90]], - bids: [ - { - bidder: 'zedo', - params: { - channelCode: 2264004118, // required - dimId: 9, // required - pubId: 1 // optional - } + var adUnits = [{ + code: 'div-gpt-ad-1460505748561-0', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]], } - ] - } - ]; + }, + // Replace this object to test a new Adapter! + bids: [{ + bidder: 'zedo', + params: { + channelCode: 2264004735, //REQUIRED + dimId:9 //REQUIRED + } + }] + + }]; ``` # video ``` @@ -54,7 +55,7 @@ ZEDO has its own renderer and will render the video unit if not defined in the c bidder: 'zedo', params: { - channelCode: 2264004593, // required + channelCode: 2264004735, // required dimId: 85, // required pubId: 1 // optional } diff --git a/modules/zeotapIdPlusIdSystem.js b/modules/zeotapIdPlusIdSystem.js new file mode 100644 index 00000000000..ea1173cd61e --- /dev/null +++ b/modules/zeotapIdPlusIdSystem.js @@ -0,0 +1,52 @@ +/** + * This module adds Zeotap to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/zeotapIdPlusIdSystem + * @requires module:modules/userId + */ +import * as utils from '../src/utils.js' +import {submodule} from '../src/hook.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const ZEOTAP_COOKIE_NAME = 'IDP'; +export const storage = getStorageManager(); + +function readCookie() { + return storage.cookiesAreEnabled ? storage.getCookie(ZEOTAP_COOKIE_NAME) : null; +} + +function readFromLocalStorage() { + return storage.localStorageIsEnabled ? storage.getDataFromLocalStorage(ZEOTAP_COOKIE_NAME) : null; +} + +/** @type {Submodule} */ +export const zeotapIdPlusSubmodule = { + /** + * used to link submodule with config + * @type {string} + */ + name: 'zeotapIdPlus', + /** + * decode the stored id value for passing to bid requests + * @function + * @param { Object | string | undefined } value + * @return { Object | string | undefined } + */ + decode(value) { + const id = value ? utils.isStr(value) ? value : utils.isPlainObject(value) ? value.id : undefined : undefined; + return id ? { + 'IDP': JSON.parse(atob(id)) + } : undefined; + }, + /** + * performs action to obtain id and return a value in the callback's response argument + * @function + * @param {SubmoduleParams} configParams + * @return {{id: string | undefined} | undefined} + */ + getId() { + const id = readCookie() || readFromLocalStorage(); + return id ? { id } : undefined; + } +}; +submodule('userId', zeotapIdPlusSubmodule); diff --git a/package-lock.json b/package-lock.json index 146fb49c435..1784b885be9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,47 +1,48 @@ { "name": "prebid.js", - "version": "3.18.0-pre", + "version": "4.8.0-pre", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", "dev": true, "requires": { - "@babel/highlight": "^7.8.3" + "@babel/highlight": "^7.10.4" } }, "@babel/compat-data": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.6.tgz", - "integrity": "sha512-CurCIKPTkS25Mb8mz267vU95vy+TyUpnctEX2lV33xWNmHAfjruztgiPBbXZRh3xZZy1CYvGx6XfxyTVS+sk7Q==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.10.5.tgz", + "integrity": "sha512-mPVoWNzIpYJHbWje0if7Ck36bpbtTvIxOi9+6WSK9wjGEXearAqlwBoTQvVjsAY2VIwgcs8V940geY3okzRCEw==", "dev": true, "requires": { - "browserslist": "^4.8.5", + "browserslist": "^4.12.0", "invariant": "^2.2.4", "semver": "^5.5.0" } }, "@babel/core": { - "version": "7.8.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.7.tgz", - "integrity": "sha512-rBlqF3Yko9cynC5CCFy6+K/w2N+Sq/ff2BPy+Krp7rHlABIr5epbA7OxVeKoMHB39LZOp1UY5SuLjy6uWi35yA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.7", - "@babel/helpers": "^7.8.4", - "@babel/parser": "^7.8.7", - "@babel/template": "^7.8.6", - "@babel/traverse": "^7.8.6", - "@babel/types": "^7.8.7", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.5.tgz", + "integrity": "sha512-O34LQooYVDXPl7QWCdW9p4NR+QlzOr7xShPPJz8GsuCU3/8ua/wqTr7gmnxXv+WBESiGU/G5s16i6tUvHkNb+w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.5", + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helpers": "^7.10.4", + "@babel/parser": "^7.10.5", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.5", + "@babel/types": "^7.10.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", - "json5": "^2.1.0", - "lodash": "^4.17.13", + "json5": "^2.1.2", + "lodash": "^4.17.19", "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" @@ -65,341 +66,380 @@ } }, "@babel/generator": { - "version": "7.8.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.8.tgz", - "integrity": "sha512-HKyUVu69cZoclptr8t8U5b6sx6zoWjh8jiUhnuj3MpZuKT2dJ8zPTuiy31luq32swhI0SpwItCIlU8XW7BZeJg==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.5.tgz", + "integrity": "sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig==", "dev": true, "requires": { - "@babel/types": "^7.8.7", + "@babel/types": "^7.10.5", "jsesc": "^2.5.1", - "lodash": "^4.17.13", "source-map": "^0.5.0" } }, "@babel/helper-annotate-as-pure": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz", - "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@babel/types": "^7.10.4" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz", - "integrity": "sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.8.3", - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-call-delegate": { - "version": "7.8.7", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.7.tgz", - "integrity": "sha512-doAA5LAKhsFCR0LAFIf+r2RSMmC+m8f/oQ+URnUET/rWeEzC0yTRmAGyWkD4sSu3xwbS7MYQ2u+xlt1V5R56KQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.7" + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/helper-compilation-targets": { - "version": "7.8.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz", - "integrity": "sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz", + "integrity": "sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.8.6", - "browserslist": "^4.9.1", + "@babel/compat-data": "^7.10.4", + "browserslist": "^4.12.0", "invariant": "^2.2.4", "levenary": "^1.1.1", "semver": "^5.5.0" } }, + "@babel/helper-create-class-features-plugin": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz", + "integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.10.5", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4" + } + }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.8.8", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz", - "integrity": "sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", + "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.8.3", - "@babel/helper-regex": "^7.8.3", + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-regex": "^7.10.4", "regexpu-core": "^4.7.0" } }, "@babel/helper-define-map": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz", - "integrity": "sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.8.3", - "@babel/types": "^7.8.3", - "lodash": "^4.17.13" + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" } }, "@babel/helper-explode-assignable-expression": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz", - "integrity": "sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz", + "integrity": "sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==", "dev": true, "requires": { - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/helper-function-name": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", - "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/helper-get-function-arity": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", - "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@babel/types": "^7.10.4" } }, "@babel/helper-hoist-variables": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz", - "integrity": "sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@babel/types": "^7.10.4" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", - "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.5.tgz", + "integrity": "sha512-HiqJpYD5+WopCXIAbQDG0zye5XYVvcO9w/DHp5GsaGkRUaamLj2bEtu6i8rnGGprAhHM3qidCMgp71HF4endhA==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@babel/types": "^7.10.5" } }, "@babel/helper-module-imports": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", - "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@babel/types": "^7.10.4" } }, "@babel/helper-module-transforms": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.6.tgz", - "integrity": "sha512-RDnGJSR5EFBJjG3deY0NiL0K9TO8SXxS9n/MPsbPK/s9LbQymuLNtlzvDiNS7IpecuL45cMeLVkA+HfmlrnkRg==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.5.tgz", + "integrity": "sha512-4P+CWMJ6/j1W915ITJaUkadLObmCRRSC234uctJfn/vHrsLNxsR8dwlcXv9ZhJWzl77awf+mWXSZEKt5t0OnlA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.6", - "@babel/helper-simple-access": "^7.8.3", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/template": "^7.8.6", - "@babel/types": "^7.8.6", - "lodash": "^4.17.13" + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" } }, "@babel/helper-optimise-call-expression": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", - "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@babel/types": "^7.10.4" } }, "@babel/helper-plugin-utils": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", - "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", "dev": true }, "@babel/helper-regex": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz", - "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", + "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", "dev": true, "requires": { - "lodash": "^4.17.13" + "lodash": "^4.17.19" } }, "@babel/helper-remap-async-to-generator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz", - "integrity": "sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz", + "integrity": "sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.8.3", - "@babel/helper-wrap-function": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/helper-replace-supers": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", - "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", + "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.8.3", - "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.8.6", - "@babel/types": "^7.8.6" + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/helper-simple-access": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", - "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", + "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", "dev": true, "requires": { - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/helper-split-export-declaration": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", - "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz", + "integrity": "sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==", "dev": true, "requires": { - "@babel/types": "^7.8.3" + "@babel/types": "^7.10.4" } }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, "@babel/helper-wrap-function": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz", - "integrity": "sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", + "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3" + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/helpers": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz", - "integrity": "sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", + "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", "dev": true, "requires": { - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.8.4", - "@babel/types": "^7.8.3" + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/highlight": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", - "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", "dev": true, "requires": { + "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", - "esutils": "^2.0.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.8.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.8.tgz", - "integrity": "sha512-mO5GWzBPsPf6865iIbzNE0AvkKF3NE+2S3eRUpE+FE07BOAkXh6G+GW/Pj01hhXjve1WScbaIO4UlY1JKeqCcA==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.5.tgz", + "integrity": "sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ==", "dev": true }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz", - "integrity": "sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", + "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-remap-async-to-generator": "^7.8.3", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4", "@babel/plugin-syntax-async-generators": "^7.8.0" } }, + "@babel/plugin-proposal-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz", + "integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz", - "integrity": "sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz", + "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-dynamic-import": "^7.8.0" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz", - "integrity": "sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz", + "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.0" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz", + "integrity": "sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" } }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz", + "integrity": "sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.4.tgz", + "integrity": "sha512-6vh4SqRuLLarjgeOf4EaROJAHjvu9Gl+/346PbDH9yWbJyfnJ/ah3jmYKYtswEyCoWZiidvVHjHshd4WgjB9BA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.10.4" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", + "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz", - "integrity": "sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.4.tgz", + "integrity": "sha512-ZIhQIEeavTgouyMSdZRap4VPPHqJJ3NEs2cuHs5p0erH+iz6khB0qfgU8g7UuJkG88+fBMy23ZiU+nuHvekJeQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-optional-chaining": "^7.8.0" } }, + "@babel/plugin-proposal-private-methods": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz", + "integrity": "sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.8.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz", - "integrity": "sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz", + "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.8.8", - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-syntax-async-generators": { @@ -411,6 +451,15 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz", + "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, "@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", @@ -438,6 +487,15 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, "@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", @@ -466,429 +524,456 @@ } }, "@babel/plugin-syntax-top-level-await": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz", - "integrity": "sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz", + "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz", - "integrity": "sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz", + "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz", - "integrity": "sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", + "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-remap-async-to-generator": "^7.8.3" + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz", - "integrity": "sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz", + "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz", - "integrity": "sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.5.tgz", + "integrity": "sha512-6Ycw3hjpQti0qssQcA6AMSFDHeNJ++R6dIMnpRqUjFeBBTmTDPa8zgF90OVfTvAo11mXZTlVUViY1g8ffrURLg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "lodash": "^4.17.13" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-classes": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.6.tgz", - "integrity": "sha512-k9r8qRay/R6v5aWZkrEclEhKO6mc1CCQr2dLsVHBmOQiMpN6I2bpjX3vgnldUWeEI1GHVNByULVxZ4BdP4Hmdg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.8.3", - "@babel/helper-define-map": "^7.8.3", - "@babel/helper-function-name": "^7.8.3", - "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.6", - "@babel/helper-split-export-declaration": "^7.8.3", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz", + "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz", - "integrity": "sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz", + "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-destructuring": { - "version": "7.8.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz", - "integrity": "sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz", + "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz", - "integrity": "sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", + "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz", - "integrity": "sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz", + "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz", - "integrity": "sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", + "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-for-of": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.6.tgz", - "integrity": "sha512-M0pw4/1/KI5WAxPsdcUL/w2LJ7o89YHN3yLkzNjg7Yl15GlVGgzHyCU+FMeAxevHGsLVmUqbirlUIKTafPmzdw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz", + "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-function-name": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz", - "integrity": "sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz", + "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-literals": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz", - "integrity": "sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz", + "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz", - "integrity": "sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz", + "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz", - "integrity": "sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz", + "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "babel-plugin-dynamic-import-node": "^2.3.0" + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz", - "integrity": "sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", + "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-simple-access": "^7.8.3", - "babel-plugin-dynamic-import-node": "^2.3.0" + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz", - "integrity": "sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz", + "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.8.3", - "@babel/helper-module-transforms": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "babel-plugin-dynamic-import-node": "^2.3.0" + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz", - "integrity": "sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz", + "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz", - "integrity": "sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", + "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.8.3" + "@babel/helper-create-regexp-features-plugin": "^7.10.4" } }, "@babel/plugin-transform-new-target": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz", - "integrity": "sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz", + "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-object-super": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz", - "integrity": "sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz", + "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4" } }, "@babel/plugin-transform-parameters": { - "version": "7.8.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.8.tgz", - "integrity": "sha512-hC4Ld/Ulpf1psQciWWwdnUspQoQco2bMzSrwU6TmzRlvoYQe4rQFy9vnCZDTlVeCQj0JPfL+1RX0V8hCJvkgBA==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", + "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", "dev": true, "requires": { - "@babel/helper-call-delegate": "^7.8.7", - "@babel/helper-get-function-arity": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-property-literals": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz", - "integrity": "sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz", + "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-regenerator": { - "version": "7.8.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz", - "integrity": "sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz", + "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==", "dev": true, "requires": { "regenerator-transform": "^0.14.2" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz", - "integrity": "sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz", + "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz", - "integrity": "sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz", + "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz", - "integrity": "sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.4.tgz", + "integrity": "sha512-1e/51G/Ni+7uH5gktbWv+eCED9pP8ZpRhZB3jOaI3mmzfvJTWHkuyYTv0Z5PYtyM+Tr2Ccr9kUdQxn60fI5WuQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz", - "integrity": "sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz", + "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/helper-regex": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-regex": "^7.10.4" } }, "@babel/plugin-transform-template-literals": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz", - "integrity": "sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz", + "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz", - "integrity": "sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz", + "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz", + "integrity": "sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz", - "integrity": "sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz", + "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" } }, "@babel/preset-env": { - "version": "7.8.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.7.tgz", - "integrity": "sha512-BYftCVOdAYJk5ASsznKAUl53EMhfBbr8CJ1X+AJLfGPscQkwJFiaV/Wn9DPH/7fzm2v6iRYJKYHSqyynTGw0nw==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.8.6", - "@babel/helper-compilation-targets": "^7.8.7", - "@babel/helper-module-imports": "^7.8.3", - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-proposal-async-generator-functions": "^7.8.3", - "@babel/plugin-proposal-dynamic-import": "^7.8.3", - "@babel/plugin-proposal-json-strings": "^7.8.3", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-proposal-object-rest-spread": "^7.8.3", - "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", - "@babel/plugin-proposal-optional-chaining": "^7.8.3", - "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.10.4.tgz", + "integrity": "sha512-tcmuQ6vupfMZPrLrc38d0sF2OjLT3/bZ0dry5HchNCQbrokoQi4reXqclvkkAT5b+gWc23meVWpve5P/7+w/zw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.10.4", + "@babel/helper-compilation-targets": "^7.10.4", + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-proposal-async-generator-functions": "^7.10.4", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-proposal-dynamic-import": "^7.10.4", + "@babel/plugin-proposal-json-strings": "^7.10.4", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", + "@babel/plugin-proposal-numeric-separator": "^7.10.4", + "@babel/plugin-proposal-object-rest-spread": "^7.10.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.10.4", + "@babel/plugin-proposal-optional-chaining": "^7.10.4", + "@babel/plugin-proposal-private-methods": "^7.10.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.10.4", "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.10.4", "@babel/plugin-syntax-dynamic-import": "^7.8.0", "@babel/plugin-syntax-json-strings": "^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.0", "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.8.3", - "@babel/plugin-transform-arrow-functions": "^7.8.3", - "@babel/plugin-transform-async-to-generator": "^7.8.3", - "@babel/plugin-transform-block-scoped-functions": "^7.8.3", - "@babel/plugin-transform-block-scoping": "^7.8.3", - "@babel/plugin-transform-classes": "^7.8.6", - "@babel/plugin-transform-computed-properties": "^7.8.3", - "@babel/plugin-transform-destructuring": "^7.8.3", - "@babel/plugin-transform-dotall-regex": "^7.8.3", - "@babel/plugin-transform-duplicate-keys": "^7.8.3", - "@babel/plugin-transform-exponentiation-operator": "^7.8.3", - "@babel/plugin-transform-for-of": "^7.8.6", - "@babel/plugin-transform-function-name": "^7.8.3", - "@babel/plugin-transform-literals": "^7.8.3", - "@babel/plugin-transform-member-expression-literals": "^7.8.3", - "@babel/plugin-transform-modules-amd": "^7.8.3", - "@babel/plugin-transform-modules-commonjs": "^7.8.3", - "@babel/plugin-transform-modules-systemjs": "^7.8.3", - "@babel/plugin-transform-modules-umd": "^7.8.3", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", - "@babel/plugin-transform-new-target": "^7.8.3", - "@babel/plugin-transform-object-super": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.8.7", - "@babel/plugin-transform-property-literals": "^7.8.3", - "@babel/plugin-transform-regenerator": "^7.8.7", - "@babel/plugin-transform-reserved-words": "^7.8.3", - "@babel/plugin-transform-shorthand-properties": "^7.8.3", - "@babel/plugin-transform-spread": "^7.8.3", - "@babel/plugin-transform-sticky-regex": "^7.8.3", - "@babel/plugin-transform-template-literals": "^7.8.3", - "@babel/plugin-transform-typeof-symbol": "^7.8.4", - "@babel/plugin-transform-unicode-regex": "^7.8.3", - "@babel/types": "^7.8.7", - "browserslist": "^4.8.5", + "@babel/plugin-syntax-top-level-await": "^7.10.4", + "@babel/plugin-transform-arrow-functions": "^7.10.4", + "@babel/plugin-transform-async-to-generator": "^7.10.4", + "@babel/plugin-transform-block-scoped-functions": "^7.10.4", + "@babel/plugin-transform-block-scoping": "^7.10.4", + "@babel/plugin-transform-classes": "^7.10.4", + "@babel/plugin-transform-computed-properties": "^7.10.4", + "@babel/plugin-transform-destructuring": "^7.10.4", + "@babel/plugin-transform-dotall-regex": "^7.10.4", + "@babel/plugin-transform-duplicate-keys": "^7.10.4", + "@babel/plugin-transform-exponentiation-operator": "^7.10.4", + "@babel/plugin-transform-for-of": "^7.10.4", + "@babel/plugin-transform-function-name": "^7.10.4", + "@babel/plugin-transform-literals": "^7.10.4", + "@babel/plugin-transform-member-expression-literals": "^7.10.4", + "@babel/plugin-transform-modules-amd": "^7.10.4", + "@babel/plugin-transform-modules-commonjs": "^7.10.4", + "@babel/plugin-transform-modules-systemjs": "^7.10.4", + "@babel/plugin-transform-modules-umd": "^7.10.4", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4", + "@babel/plugin-transform-new-target": "^7.10.4", + "@babel/plugin-transform-object-super": "^7.10.4", + "@babel/plugin-transform-parameters": "^7.10.4", + "@babel/plugin-transform-property-literals": "^7.10.4", + "@babel/plugin-transform-regenerator": "^7.10.4", + "@babel/plugin-transform-reserved-words": "^7.10.4", + "@babel/plugin-transform-shorthand-properties": "^7.10.4", + "@babel/plugin-transform-spread": "^7.10.4", + "@babel/plugin-transform-sticky-regex": "^7.10.4", + "@babel/plugin-transform-template-literals": "^7.10.4", + "@babel/plugin-transform-typeof-symbol": "^7.10.4", + "@babel/plugin-transform-unicode-escapes": "^7.10.4", + "@babel/plugin-transform-unicode-regex": "^7.10.4", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.10.4", + "browserslist": "^4.12.0", "core-js-compat": "^3.6.2", "invariant": "^2.2.2", "levenary": "^1.1.1", "semver": "^5.5.0" } }, + "@babel/preset-modules": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.3.tgz", + "integrity": "sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, "@babel/runtime": { - "version": "7.8.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.7.tgz", - "integrity": "sha512-+AATMUFppJDw6aiR5NVPHqIQBlV/Pj8wY/EZH+lmvRdUo9xBaz/rF3alAwFJQavvKfeOlPE7oaaDHVbcySbCsg==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.5.tgz", + "integrity": "sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" }, "dependencies": { "regenerator-runtime": { - "version": "0.13.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", - "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", "dev": true } } }, "@babel/template": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", - "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", "dev": true, "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6" + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" } }, "@babel/traverse": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", - "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.5.tgz", + "integrity": "sha512-yc/fyv2gUjPqzTz0WHeRJH2pv7jA9kA7mBX2tXl/x5iOE81uaVPuGPtaYk7wmkx4b67mQ7NqI8rmT2pF47KYKQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.6", - "@babel/helper-function-name": "^7.8.3", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6", + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.10.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/parser": "^7.10.5", + "@babel/types": "^7.10.5", "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.13" + "lodash": "^4.17.19" }, "dependencies": { "debug": { @@ -909,13 +994,13 @@ } }, "@babel/types": { - "version": "7.8.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.7.tgz", - "integrity": "sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw==", + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.5.tgz", + "integrity": "sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", "to-fast-properties": "^2.0.0" } }, @@ -980,6 +1065,12 @@ } } }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true + }, "@jest/console": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", @@ -1035,18 +1126,171 @@ "strip-ansi": "^5.0.0" }, "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + } + }, + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -1055,6 +1299,16 @@ "requires": { "ansi-regex": "^4.1.0" } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } } } }, @@ -1068,6 +1322,28 @@ "@jest/transform": "^24.9.0", "@jest/types": "^24.9.0", "jest-mock": "^24.9.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } } }, "@jest/fake-timers": { @@ -1079,44 +1355,250 @@ "@jest/types": "^24.9.0", "jest-message-util": "^24.9.0", "jest-mock": "^24.9.0" - } - }, - "@jest/reporters": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", - "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.2", - "istanbul-lib-instrument": "^3.0.1", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.1", - "istanbul-reports": "^2.2.6", - "jest-haste-map": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "node-notifier": "^5.4.2", - "slash": "^2.0.0", - "source-map": "^0.6.0", - "string-length": "^2.0.0" }, "dependencies": { - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "source-map": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "@jest/reporters": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", @@ -1152,6 +1634,28 @@ "@jest/console": "^24.9.0", "@jest/types": "^24.9.0", "@types/istanbul-lib-coverage": "^2.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } } }, "@jest/test-sequencer": { @@ -1190,6 +1694,131 @@ "write-file-atomic": "2.4.1" }, "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -1201,18 +1830,94 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } } } }, "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.1.0.tgz", + "integrity": "sha512-GXigDDsp6ZlNMhXQDeuy/iYCDsRIHJabWtDzvnn36+aqFfG14JmFV0e/iXxY4SP9vbXSiPNOWdehU5MeqrYHBQ==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jsdevtools/coverage-istanbul-loader": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jsdevtools/coverage-istanbul-loader/-/coverage-istanbul-loader-3.0.5.tgz", + "integrity": "sha512-EUCPEkaRPvmHjWAAZkWMT7JDzpw7FKB00WTISaiXsbNOd5hCHg77XLA8sLYLFDo1zepYLo2w7GstN8YBqRXZfA==", + "dev": true, + "requires": { + "convert-source-map": "^1.7.0", + "istanbul-lib-instrument": "^4.0.3", + "loader-utils": "^2.0.0", + "merge-source-map": "^1.1.0", + "schema-utils": "^2.7.0" } }, "@kiosked/ulid": { @@ -1221,15 +1926,15 @@ "integrity": "sha512-ZKt2KIgGHDaGfKt6FjYvCpDvBXZRRoE8b+wDOlAV76aXKpq6ITiSUnPYevR4y55NKDnwCvwOrjWe+aVOCAK8kQ==" }, "@sindresorhus/is": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", - "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-3.0.0.tgz", + "integrity": "sha512-kqA5I6Yun7PBHk8WN9BBP1c7FfN2SrD05GuVSEYPqDb4nerv7HqYfgBfMIKmT/EuejURkJKLZuLyGKGs6WEG9w==", "dev": true }, "@sinonjs/commons": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz", - "integrity": "sha512-Debi3Baff1Qu1Unc3mjJ96MgpbwTn43S1+9yJ0llWygPwDNu2aaWBD6yc9y/Z8XDRNhx7U+u2UDg2OGQXkclUQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -1261,10 +1966,19 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "@szmarczak/http-timer": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", + "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.0" + } + }, "@types/babel__core": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.6.tgz", - "integrity": "sha512-tTnhWszAqvXnhW7m5jQU9PomXSiKXk2sFxpahXvI20SZKu9ylPi8WtIxueZ6ehDWikPT0jeFujMj3X4ZHuf3Tg==", + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.9.tgz", + "integrity": "sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -1294,18 +2008,42 @@ } }, "@types/babel__traverse": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.9.tgz", - "integrity": "sha512-jEFQ8L1tuvPjOI8lnpaf73oCJe+aoxL6ygqSy6c8LcW98zaC+4mzWuQIRCEvKeCOu+lbqdXcg4Uqmm1S8AP1tw==", + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.13.tgz", + "integrity": "sha512-i+zS7t6/s9cdQvbqKDARrcbrPvtJGlbYsMkazo03nTAK3RX9FNrLllXys22uiTGJapPOTZTQ35nHh4ISph4SLQ==", "dev": true, "requires": { "@babel/types": "^7.3.0" } }, + "@types/cacheable-request": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", + "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/http-cache-semantics": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", + "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==", + "dev": true + }, "@types/istanbul-lib-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", "dev": true }, "@types/istanbul-lib-report": { @@ -1318,15 +2056,60 @@ } }, "@types/istanbul-reports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", - "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "*", "@types/istanbul-lib-report": "*" } }, + "@types/json-schema": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", + "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/keyv": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", + "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "14.0.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.24.tgz", + "integrity": "sha512-btt/oNOiDWcSuI721MdL8VQGnjsKjlTMdrKyTcLCKeQp/n4AAMFJ961wMbp+09y8WuGPClDEv07RIItdXKIXAA==", + "dev": true + }, + "@types/puppeteer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-3.0.1.tgz", + "integrity": "sha512-t03eNKCvWJXhQ8wkc5C6GYuSqMEdKLOX0GLMGtks25YZr38wKZlKTwGM/BoAPVtdysX7Bb9tdwrDS1+NrW3RRA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -1334,9 +2117,9 @@ "dev": true }, "@types/yargs": { - "version": "13.0.8", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz", - "integrity": "sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA==", + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz", + "integrity": "sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -1348,9194 +2131,12696 @@ "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", "dev": true }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "@types/yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", "dev": true, + "optional": true, "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "abab": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", - "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==" - }, - "abbrev": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "@types/node": "*" } }, - "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true - }, - "acorn-dynamic-import": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", - "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", + "@wdio/browserstack-service": { + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/@wdio/browserstack-service/-/browserstack-service-6.1.15.tgz", + "integrity": "sha512-q8qLa44wGSB3tIuZ0yquvAZqr2W7vEwupWiOd1ct0CSYgd4yX/nLd8oypqJCc8jU1ZwNAhu+V3/6hszvwx+HbA==", "dev": true, "requires": { - "acorn": "^4.0.3" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", - "dev": true - } + "@wdio/logger": "6.0.16", + "browserstack-local": "^1.4.5", + "got": "^11.0.2" } }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "@wdio/cli": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-6.3.4.tgz", + "integrity": "sha512-eXA4rR6DwhNtXx1Hxknwgl7jGt/q4ZErCB8aOX9rowEoPOxwPQStd6yJcqI2QE8+AC1S72PKC4w+0WImL+M6Bw==", "dev": true, "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" + "@wdio/config": "6.1.14", + "@wdio/logger": "6.0.16", + "@wdio/utils": "6.3.0", + "async-exit-hook": "^2.0.1", + "chalk": "^4.0.0", + "chokidar": "^3.0.0", + "cli-spinners": "^2.1.0", + "ejs": "^3.0.1", + "fs-extra": "^9.0.0", + "inquirer": "^7.0.0", + "lodash.flattendeep": "^4.4.0", + "lodash.pickby": "^4.6.0", + "lodash.union": "^4.6.0", + "mkdirp": "^1.0.4", + "recursive-readdir": "^2.2.2", + "webdriverio": "6.3.4", + "yargs": "^15.0.1", + "yarn-install": "^1.0.0" }, "dependencies": { - "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", - "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } } } }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "@wdio/concise-reporter": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@wdio/concise-reporter/-/concise-reporter-6.3.0.tgz", + "integrity": "sha512-H7yILps+dKK1k4XoVE5HOVMpTHN321SFmjjMgtq1zfiC6Dph7Unl4ODmnyVLD5Kk3ycQ31PfOBr0QPyKnLUFiQ==", "dev": true, "requires": { - "acorn": "^3.0.4" + "@wdio/reporter": "6.3.0", + "chalk": "^4.0.0", + "pretty-ms": "^7.0.0" }, "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", - "dev": true - }, - "after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", - "dev": true - }, - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "@wdio/config": { + "version": "6.1.14", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-6.1.14.tgz", + "integrity": "sha512-MXHMHwtkAblfnIxONs9aW//T9Fq5XIw3oH+tztcBRvNTTAIXmwHd+4sOjAwjpCdBSGs0C4kM/aTpGfwDZVURvQ==", "dev": true, "requires": { - "es6-promisify": "^5.0.0" + "@wdio/logger": "6.0.16", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" } }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "@wdio/local-runner": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-6.3.4.tgz", + "integrity": "sha512-rKEhFXiNH6H2G86JTgy2cgtEFoNBZ50gRy+P1LEhc7Ko/dAYqYMC+Sy8lnbsDzxz6IZVlbubgs+y7GRREayqoQ==", "dev": true, "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "@wdio/logger": "6.0.16", + "@wdio/repl": "6.3.0", + "@wdio/runner": "6.3.4", + "async-exit-hook": "^2.0.1", + "stream-buffers": "^3.0.2" } }, - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "@wdio/logger": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-6.0.16.tgz", + "integrity": "sha512-VbH5UnQIG/3sSMV+Y38+rOdwyK9mVA9vuL7iOngoTafHwUjL1MObfN/Cex84L4mGxIgfxCu6GV48iUmSuQ7sqA==", "dev": true, "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" }, "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" } } } }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, - "ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", - "dev": true, - "requires": { - "ansi-wrap": "^0.1.0" - } - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", - "dev": true - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "@wdio/mocha-framework": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-6.3.0.tgz", + "integrity": "sha512-3lLvzhDYWwOYmiJAjr2fm/nENq6g6uUOtkIeEQFp1kDyBQkDsH1PXGdFklQbRiQT8mAqOPhx1kvXrCA/XpWl7g==", "dev": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "@wdio/logger": "6.0.16", + "@wdio/utils": "6.3.0", + "expect-webdriverio": "^1.1.5", + "mocha": "^8.0.1" }, "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "append-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "chokidar": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.3.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mocha": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.0.1.tgz", + "integrity": "sha512-vefaXfdYI8+Yo8nPZQQi0QO2o+5q9UIMX1jZ1XMmK3+4+CQjc7+B0hPdUeglXiTlr8IHMVRo63IhO9Mzt6fxOg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.3.1", + "debug": "3.2.6", + "diff": "4.0.2", + "escape-string-regexp": "1.0.5", + "find-up": "4.1.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "ms": "2.1.2", + "object.assign": "4.1.0", + "promise.allsettled": "1.0.2", + "serialize-javascript": "3.0.0", + "strip-json-comments": "3.0.1", + "supports-color": "7.1.0", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.0.0", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.7" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "@wdio/protocols": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-6.3.0.tgz", + "integrity": "sha512-1GKzfyCTLW5WkFd3W7NLACih+zNWU7c8kFurbCQXDK1ko1obqJEs7ZjBr85q5XqMWburdks5rDjyml2iEB2LBg==", + "dev": true + }, + "@wdio/repl": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-6.3.0.tgz", + "integrity": "sha512-FT3flKOqNdZNG1uYl+QpOfdZIgKAWhLfoQ0s+wL0crLeDNIFvvM2qSDhRBRDYV7a0IFyBi8Z975WBn0dlH03Ig==", "dev": true, "requires": { - "buffer-equal": "^1.0.0" + "@wdio/utils": "6.3.0" } }, - "append-transform": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", - "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "@wdio/reporter": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-6.3.0.tgz", + "integrity": "sha512-vbwjJvSKZUtsWtQMhuVqT7ZP6RIFAH4+ienjNwW30QPDi38OujZgxC2ZqRoZKsxck6cfTgkxrXfNaxHN0/LHKg==", "dev": true, "requires": { - "default-require-extensions": "^1.0.0" + "fs-extra": "^9.0.0" } }, - "archiver": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-2.1.1.tgz", - "integrity": "sha1-/2YrSnggFJSj7lRNOjP+dJZQnrw=", + "@wdio/runner": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-6.3.4.tgz", + "integrity": "sha512-+iOXfTODsSVf9LFBFKAEZqvPzfIClwFCKu7GGFZ7lrOF1svMNzT/0UY0ETsCBZe61Gr8xiI0wbCEly+0DbEh6w==", "dev": true, "requires": { - "archiver-utils": "^1.3.0", - "async": "^2.0.0", - "buffer-crc32": "^0.2.1", - "glob": "^7.0.0", - "lodash": "^4.8.0", - "readable-stream": "^2.0.0", - "tar-stream": "^1.5.0", - "zip-stream": "^1.2.0" - }, - "dependencies": { - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - } + "@wdio/config": "6.1.14", + "@wdio/logger": "6.0.16", + "@wdio/utils": "6.3.0", + "deepmerge": "^4.0.0", + "gaze": "^1.1.2", + "webdriver": "6.3.0", + "webdriverio": "6.3.4" } }, - "archiver-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", - "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", + "@wdio/spec-reporter": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-6.3.0.tgz", + "integrity": "sha512-JGZAMcqiOloOw6xcIT5O8GORVaww6kslgH5kZGydVQyoNBj1ZKoLdEjqq2jklJsge1xsscdYdW9u9kMHwm25iA==", "dev": true, "requires": { - "glob": "^7.0.0", - "graceful-fs": "^4.1.0", - "lazystream": "^1.0.0", - "lodash": "^4.8.0", - "normalize-path": "^2.0.0", - "readable-stream": "^2.0.0" + "@wdio/reporter": "6.3.0", + "chalk": "^4.0.0", + "easy-table": "^1.1.1", + "pretty-ms": "^7.0.0" }, "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "remove-trailing-separator": "^1.0.1" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" } } } }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "@wdio/sync": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-6.3.3.tgz", + "integrity": "sha512-WNq+hhkgk9LluKLP2nQ/9+EH8HNQnROFFHvYuznxb1aKj/zhZvqWuQPpmMWhPMBSTpkdbdLCYerZWKcamYOcJQ==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "@types/puppeteer": "^3.0.1", + "@wdio/logger": "6.0.16", + "fibers": "^4.0.1" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-filter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "@wdio/utils": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-6.3.0.tgz", + "integrity": "sha512-PbeC5fpieamgSAHf7S58MAyraGU1qKxnHdfGMG+ZIWiIo73oo4j/57CcH6ZawQ3YC1wEc/5q+VXg7N5hvqhJOQ==", "dev": true, "requires": { - "make-iterator": "^1.0.0" + "@wdio/logger": "6.0.16" } }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", "dev": true, "requires": { - "make-iterator": "^1.0.0" + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" } }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "abab": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==" + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "dev": true }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", - "dev": true - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", - "dev": true - }, - "array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", - "dev": true, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "is-string": "^1.0.5" + "mime-types": "~2.1.24", + "negotiator": "0.6.2" } }, - "array-initial": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", + "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", "dev": true, "requires": { - "array-slice": "^1.0.0", - "is-number": "^4.0.0" + "acorn": "^4.0.3" }, "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", "dev": true } } }, - "array-last": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", "dev": true, "requires": { - "is-number": "^4.0.0" + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" }, "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", "dev": true } } }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true - }, - "array-sort": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "default-compare": "^1.0.0", - "get-value": "^2.0.6", - "kind-of": "^5.0.2" + "acorn": "^3.0.4" }, "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", "dev": true } } }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", "dev": true }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", "dev": true }, - "array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "arraybuffer.slice": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", "dev": true }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "safer-buffer": "~2.1.0" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + }, + "dependencies": { + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + } } }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } + "ajv-keywords": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.1.tgz", + "integrity": "sha512-KWcq3xN8fDjSB+IMoh2VaXVhRI0BBGxoYp3rx7Pkb6z0cFjYR9Q9l4yZqqals0/zsioCmocC5H6UvsGD4MoIBA==", + "dev": true }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" }, "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "inherits": "2.0.1" + "is-buffer": "^1.1.5" } } } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + } }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", "dev": true }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, - "async-done": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^2.0.0", - "stream-exhaust": "^1.0.1" + "color-convert": "^1.9.0" } }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", "dev": true }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } }, - "async-settle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", "dev": true, "requires": { - "async-done": "^1.2.2" + "buffer-equal": "^1.0.0" } }, - "asynckit": { + "append-transform": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", - "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", "dev": true, "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } + "default-require-extensions": "^1.0.0" } }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", + "archiver": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-4.0.2.tgz", + "integrity": "sha512-B9IZjlGwaxF33UN4oPbfBkyA4V1SxNLeIhR1qY8sRXSsbdUkEHrrOvwlYFPx+8uQeCe9M+FG6KgO+imDmQ79CQ==", "dev": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" + "archiver-utils": "^2.1.0", + "async": "^3.2.0", + "buffer-crc32": "^0.2.1", + "glob": "^7.1.6", + "readable-stream": "^3.6.0", + "tar-stream": "^2.1.2", + "zip-stream": "^3.0.1" }, "dependencies": { - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", "dev": true } } }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "dev": true, "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" }, "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } } } }, - "babel-helper-bindify-decorators": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz", - "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "babel-helper-explode-assignable-expression": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "sprintf-js": "~1.0.2" } }, - "babel-helper-builder-react-jsx": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", - "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "esutils": "^2.0.2" - } + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", "dev": true, "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "make-iterator": "^1.0.0" } }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "dev": true, - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "make-iterator": "^1.0.0" } }, - "babel-helper-explode-class": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz", - "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=", - "dev": true, - "requires": { - "babel-helper-bindify-decorators": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", - "dev": true, - "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "dev": true }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "dev": true }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", + "dev": true }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" } }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", "dev": true, "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } } }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } } }, - "babel-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", - "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true + }, + "array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", "dev": true, "requires": { - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/babel__core": "^7.1.0", - "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.9.0", - "chalk": "^2.4.2", - "slash": "^2.0.0" + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" }, "dependencies": { - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } }, - "babel-loader": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", - "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", "dev": true, "requires": { - "find-cache-dir": "^2.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1", - "pify": "^4.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" } }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "array.prototype.map": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz", + "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.4" } }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "safer-buffer": "~2.1.0" } }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", - "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "requires": { - "object.assign": "^4.1.0" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, - "babel-plugin-istanbul": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", - "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.3.0", - "test-exclude": "^5.2.3" - } - }, - "babel-plugin-jest-hoist": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", - "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", - "dev": true, - "requires": { - "@types/babel__traverse": "^7.0.6" + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } } }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", - "dev": true - }, - "babel-plugin-syntax-async-generators": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", - "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=", + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, - "babel-plugin-syntax-class-constructor-call": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz", - "integrity": "sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY=", + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, - "babel-plugin-syntax-class-properties": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", - "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, - "babel-plugin-syntax-decorators": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", - "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, - "babel-plugin-syntax-do-expressions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz", - "integrity": "sha1-V0d1YTmqJtOQ0JQQsDdEugfkeW0=", + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", "dev": true }, - "babel-plugin-syntax-dynamic-import": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", - "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=", - "dev": true + "async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + } }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, - "babel-plugin-syntax-export-extensions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz", - "integrity": "sha1-cKFITw+QiaToStRLrDU8lbmxJyE=", + "async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", "dev": true }, - "babel-plugin-syntax-flow": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", - "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=", + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "dev": true }, - "babel-plugin-syntax-function-bind": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz", - "integrity": "sha1-SMSV8Xe98xqYHnMvVa3AvdJgH0Y=", - "dev": true + "async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "dev": true, + "requires": { + "async-done": "^1.2.2" + } }, - "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", - "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "babel-plugin-system-import-transformer": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-system-import-transformer/-/babel-plugin-system-import-transformer-3.1.0.tgz", - "integrity": "sha1-038Mro5h7zkGAggzHZMbXmMNfF8=", + "available-typed-arrays": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", + "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", "dev": true, "requires": { - "babel-plugin-syntax-dynamic-import": "^6.18.0" + "array-filter": "^1.0.0" } }, - "babel-plugin-transform-async-generator-functions": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz", - "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=", - "dev": true, - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-generators": "^6.5.0", - "babel-runtime": "^6.22.0" - } + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "dev": true, - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-functions": "^6.8.0", - "babel-runtime": "^6.22.0" - } + "aws4": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", + "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", + "dev": true }, - "babel-plugin-transform-class-constructor-call": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz", - "integrity": "sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk=", + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "babel-plugin-syntax-class-constructor-call": "^6.18.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } } }, - "babel-plugin-transform-class-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", - "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", + "babel-core": { + "version": "6.26.3", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", + "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-plugin-syntax-class-properties": "^6.8.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-plugin-transform-decorators": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz", - "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=", - "dev": true, - "requires": { - "babel-helper-explode-class": "^6.24.1", - "babel-plugin-syntax-decorators": "^6.13.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-decorators-legacy": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz", - "integrity": "sha512-jYHwjzRXRelYQ1uGm353zNzf3QmtdCfvJbuYTZ4gKveK7M9H1fs3a5AKdY1JUDl0z97E30ukORW1dzhWvsabtA==", - "dev": true, - "requires": { - "babel-plugin-syntax-decorators": "^6.1.18", - "babel-runtime": "^6.2.0", - "babel-template": "^6.3.0" - } - }, - "babel-plugin-transform-do-expressions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz", - "integrity": "sha1-KMyvkoEtlJws0SgfaQyP3EaK6bs=", - "dev": true, - "requires": { - "babel-plugin-syntax-do-expressions": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + }, + "dependencies": { + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + } } }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", "dev": true, "requires": { + "babel-messages": "^6.23.0", "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + } } }, - "babel-plugin-transform-es2015-classes": { + "babel-helper-bindify-decorators": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz", + "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=", "dev": true, "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", "babel-traverse": "^6.24.1", "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-computed-properties": { + "babel-helper-builder-binary-assignment-operator-visitor": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", "dev": true, "requires": { + "babel-helper-explode-assignable-expression": "^6.24.1", "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "babel-helper-builder-react-jsx": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", + "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "esutils": "^2.0.2" } }, - "babel-plugin-transform-es2015-duplicate-keys": { + "babel-helper-call-delegate": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", "dev": true, "requires": { + "babel-helper-hoist-variables": "^6.24.1", "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" } }, - "babel-plugin-transform-es2015-function-name": { + "babel-helper-explode-assignable-expression": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "babel-helper-explode-class": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz", + "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "babel-helper-bindify-decorators": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-modules-amd": { + "babel-helper-function-name": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", "dev": true, "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", "dev": true, "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-modules-systemjs": { + "babel-helper-hoist-variables": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", "dev": true, "requires": { - "babel-helper-hoist-variables": "^6.24.1", "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-modules-umd": { + "babel-helper-optimise-call-expression": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", "dev": true, "requires": { - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", "dev": true, "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" } }, - "babel-plugin-transform-es2015-parameters": { + "babel-helper-remap-async-to-generator": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", "dev": true, "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", + "babel-helper-function-name": "^6.24.1", "babel-runtime": "^6.22.0", "babel-template": "^6.24.1", "babel-traverse": "^6.24.1", "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-shorthand-properties": { + "babel-helper-replace-supers": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", "dev": true, "requires": { + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", "babel-types": "^6.24.1" } }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-es2015-sticky-regex": { + "babel-helpers": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", "dev": true, "requires": { - "babel-helper-regex": "^6.24.1", "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" + "babel-template": "^6.24.1" } }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "babel-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.9.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } } }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "babel-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", "dev": true, "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "regexpu-core": "^2.0.0" + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" }, "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "dev": true, "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" + "minimist": "^1.2.0" } }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", - "dev": true + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { - "jsesc": "~0.5.0" + "minimist": "^1.2.5" } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true } } }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", - "dev": true, - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", - "babel-plugin-syntax-exponentiation-operator": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-export-extensions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz", - "integrity": "sha1-U3OLR+deghhYnuqUbLvTkQm75lM=", + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "dev": true, "requires": { - "babel-plugin-syntax-export-extensions": "^6.8.0", "babel-runtime": "^6.22.0" } }, - "babel-plugin-transform-flow-strip-types": { + "babel-plugin-check-es2015-constants": { "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", - "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", "dev": true, "requires": { - "babel-plugin-syntax-flow": "^6.18.0", "babel-runtime": "^6.22.0" } }, - "babel-plugin-transform-function-bind": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz", - "integrity": "sha1-xvuOlqwpajELjPjqQBRiQH3fapc=", + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", "dev": true, "requires": { - "babel-plugin-syntax-function-bind": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-transform-object-assign": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-assign/-/babel-plugin-transform-object-assign-6.22.0.tgz", - "integrity": "sha1-+Z0vZvGgsNSY40bFNZaEdAyqILo=", - "requires": { - "babel-runtime": "^6.22.0" + "object.assign": "^4.1.0" } }, - "babel-plugin-transform-object-rest-spread": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", - "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "babel-plugin-istanbul": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", "dev": true, "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, - "babel-plugin-transform-react-display-name": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", - "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", + "babel-plugin-jest-hoist": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "@types/babel__traverse": "^7.0.6" } }, - "babel-plugin-transform-react-jsx": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", - "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", - "dev": true, - "requires": { - "babel-helper-builder-react-jsx": "^6.24.1", - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" - } + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "dev": true }, - "babel-plugin-transform-react-jsx-self": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", - "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", - "dev": true, - "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" - } + "babel-plugin-syntax-async-generators": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", + "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=", + "dev": true }, - "babel-plugin-transform-react-jsx-source": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", - "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", - "dev": true, - "requires": { - "babel-plugin-syntax-jsx": "^6.8.0", - "babel-runtime": "^6.22.0" - } + "babel-plugin-syntax-class-constructor-call": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz", + "integrity": "sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY=", + "dev": true }, - "babel-plugin-transform-regenerator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "babel-plugin-syntax-class-properties": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", + "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", + "dev": true + }, + "babel-plugin-syntax-decorators": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", + "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", + "dev": true + }, + "babel-plugin-syntax-do-expressions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz", + "integrity": "sha1-V0d1YTmqJtOQ0JQQsDdEugfkeW0=", + "dev": true + }, + "babel-plugin-syntax-dynamic-import": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", + "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=", + "dev": true + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "dev": true + }, + "babel-plugin-syntax-export-extensions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz", + "integrity": "sha1-cKFITw+QiaToStRLrDU8lbmxJyE=", + "dev": true + }, + "babel-plugin-syntax-flow": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", + "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=", + "dev": true + }, + "babel-plugin-syntax-function-bind": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz", + "integrity": "sha1-SMSV8Xe98xqYHnMvVa3AvdJgH0Y=", + "dev": true + }, + "babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", + "dev": true + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "dev": true + }, + "babel-plugin-system-import-transformer": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-system-import-transformer/-/babel-plugin-system-import-transformer-3.1.0.tgz", + "integrity": "sha1-038Mro5h7zkGAggzHZMbXmMNfF8=", "dev": true, "requires": { - "regenerator-transform": "^0.10.0" - }, - "dependencies": { - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "dev": true, - "requires": { - "babel-runtime": "^6.18.0", - "babel-types": "^6.19.0", - "private": "^0.1.6" - } - } + "babel-plugin-syntax-dynamic-import": "^6.18.0" } }, - "babel-plugin-transform-strict-mode": { + "babel-plugin-transform-async-generator-functions": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz", + "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "babel-helper-remap-async-to-generator": "^6.24.1", + "babel-plugin-syntax-async-generators": "^6.5.0", + "babel-runtime": "^6.22.0" } }, - "babel-preset-env": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", - "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", "dev": true, "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-syntax-trailing-function-commas": "^6.22.0", - "babel-plugin-transform-async-to-generator": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.23.0", - "babel-plugin-transform-es2015-classes": "^6.23.0", - "babel-plugin-transform-es2015-computed-properties": "^6.22.0", - "babel-plugin-transform-es2015-destructuring": "^6.23.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", - "babel-plugin-transform-es2015-for-of": "^6.23.0", - "babel-plugin-transform-es2015-function-name": "^6.22.0", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.22.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-umd": "^6.23.0", - "babel-plugin-transform-es2015-object-super": "^6.22.0", - "babel-plugin-transform-es2015-parameters": "^6.23.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", - "babel-plugin-transform-exponentiation-operator": "^6.22.0", - "babel-plugin-transform-regenerator": "^6.22.0", - "browserslist": "^3.2.6", - "invariant": "^2.2.2", - "semver": "^5.3.0" - }, - "dependencies": { - "browserslist": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", - "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30000844", - "electron-to-chromium": "^1.3.47" - } - } + "babel-helper-remap-async-to-generator": "^6.24.1", + "babel-plugin-syntax-async-functions": "^6.8.0", + "babel-runtime": "^6.22.0" } }, - "babel-preset-flow": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", - "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", + "babel-plugin-transform-class-constructor-call": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz", + "integrity": "sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk=", "dev": true, "requires": { - "babel-plugin-transform-flow-strip-types": "^6.22.0" + "babel-plugin-syntax-class-constructor-call": "^6.18.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" } }, - "babel-preset-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", - "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", + "babel-plugin-transform-class-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", + "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", "dev": true, "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" + "babel-helper-function-name": "^6.24.1", + "babel-plugin-syntax-class-properties": "^6.8.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" } }, - "babel-preset-react": { + "babel-plugin-transform-decorators": { "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", - "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz", + "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=", "dev": true, "requires": { - "babel-plugin-syntax-jsx": "^6.3.13", - "babel-plugin-transform-react-display-name": "^6.23.0", - "babel-plugin-transform-react-jsx": "^6.24.1", - "babel-plugin-transform-react-jsx-self": "^6.22.0", - "babel-plugin-transform-react-jsx-source": "^6.22.0", - "babel-preset-flow": "^6.23.0" + "babel-helper-explode-class": "^6.24.1", + "babel-plugin-syntax-decorators": "^6.13.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-types": "^6.24.1" } }, - "babel-preset-stage-0": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz", - "integrity": "sha1-VkLRUEL5E4TX5a+LyIsduVsDnmo=", + "babel-plugin-transform-decorators-legacy": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz", + "integrity": "sha512-jYHwjzRXRelYQ1uGm353zNzf3QmtdCfvJbuYTZ4gKveK7M9H1fs3a5AKdY1JUDl0z97E30ukORW1dzhWvsabtA==", "dev": true, "requires": { - "babel-plugin-transform-do-expressions": "^6.22.0", - "babel-plugin-transform-function-bind": "^6.22.0", - "babel-preset-stage-1": "^6.24.1" + "babel-plugin-syntax-decorators": "^6.1.18", + "babel-runtime": "^6.2.0", + "babel-template": "^6.3.0" } }, - "babel-preset-stage-1": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz", - "integrity": "sha1-dpLNfc1oSZB+auSgqFWJz7niv7A=", + "babel-plugin-transform-do-expressions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz", + "integrity": "sha1-KMyvkoEtlJws0SgfaQyP3EaK6bs=", "dev": true, "requires": { - "babel-plugin-transform-class-constructor-call": "^6.24.1", - "babel-plugin-transform-export-extensions": "^6.22.0", - "babel-preset-stage-2": "^6.24.1" + "babel-plugin-syntax-do-expressions": "^6.8.0", + "babel-runtime": "^6.22.0" } }, - "babel-preset-stage-2": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz", - "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=", + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", "dev": true, "requires": { - "babel-plugin-syntax-dynamic-import": "^6.18.0", - "babel-plugin-transform-class-properties": "^6.24.1", - "babel-plugin-transform-decorators": "^6.24.1", - "babel-preset-stage-3": "^6.24.1" + "babel-runtime": "^6.22.0" } }, - "babel-preset-stage-3": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz", - "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=", + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", "dev": true, "requires": { - "babel-plugin-syntax-trailing-function-commas": "^6.22.0", - "babel-plugin-transform-async-generator-functions": "^6.24.1", - "babel-plugin-transform-async-to-generator": "^6.24.1", - "babel-plugin-transform-exponentiation-operator": "^6.24.1", - "babel-plugin-transform-object-rest-spread": "^6.22.0" + "babel-runtime": "^6.22.0" } }, - "babel-register": { + "babel-plugin-transform-es2015-block-scoping": { "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - }, - "dependencies": { - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", - "dev": true - } - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" - } - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", "dev": true, "requires": { "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", "babel-traverse": "^6.26.0", "babel-types": "^6.26.0", - "babylon": "^6.18.0", "lodash": "^4.17.4" } }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", "dev": true, "requires": { - "babel-code-frame": "^6.26.0", + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "dependencies": { - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - } + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" } }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - }, - "dependencies": { - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - } + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" } }, - "babelify": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-8.0.0.tgz", - "integrity": "sha512-xVr63fKEvMWUrrIbqlHYsMcc5Zdw4FSVesAHgkgajyCE1W8gbm9rbMakqavhxKvikGYMhEcqxTwB/gQmQ6lBtw==", - "dev": true - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "bach": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", "dev": true, "requires": { - "arr-filter": "^1.1.1", - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "array-each": "^1.0.0", - "array-initial": "^1.0.0", - "array-last": "^1.1.1", - "async-done": "^1.2.2", - "async-settle": "^1.0.0", - "now-and-later": "^2.0.0" + "babel-runtime": "^6.22.0" } }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", - "dev": true - }, - "bail": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, - "base64-arraybuffer": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", - "dev": true - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", - "dev": true - }, - "base64id": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", - "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", - "dev": true - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", "dev": true, "requires": { - "tweetnacl": "^0.14.3" + "babel-runtime": "^6.22.0" } }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true - }, - "better-assert": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", - "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", "dev": true, "requires": { - "callsite": "1.0.0" + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, - "bfj": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", - "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==", - "dev": true, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, "requires": { - "bluebird": "^3.5.5", - "check-types": "^8.0.3", - "hoopy": "^0.1.4", - "tryer": "^1.0.1" + "babel-runtime": "^6.22.0" } }, - "big-integer": { - "version": "1.6.48", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", - "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==", - "dev": true + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" + } }, - "binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", "dev": true, "requires": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" } }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } }, - "binaryextensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.2.0.tgz", - "integrity": "sha512-bHhs98rj/7i/RZpCSJ3uk55pLXOItjIrh2sRQZSM6OoktScX+LxJzvlU+FELp9j3TdcddTmmYArLSGptCTwjuw==", - "dev": true + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" + } }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", "dev": true, - "optional": true, "requires": { - "file-uri-to-path": "1.0.0" + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" } }, - "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", "dev": true, "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, - "blob": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", - "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", - "dev": true + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } }, - "body": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", "dev": true, "requires": { - "continuable-cache": "^0.3.1", - "error": "^7.0.0", - "raw-body": "~1.1.0", - "safe-json-parse": "~1.0.1" + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "regexpu-core": "^2.0.0" }, "dependencies": { - "bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true }, - "raw-body": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", - "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", "dev": true, "requires": { - "bytes": "1", - "string_decoder": "0.10" + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } } } }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "dev": true, "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", + "babel-plugin-syntax-exponentiation-operator": "^6.8.0", + "babel-runtime": "^6.22.0" } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "babel-plugin-transform-export-extensions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz", + "integrity": "sha1-U3OLR+deghhYnuqUbLvTkQm75lM=", "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "babel-plugin-syntax-export-extensions": "^6.8.0", + "babel-runtime": "^6.22.0" } }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "babel-plugin-transform-flow-strip-types": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", + "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "babel-plugin-syntax-flow": "^6.18.0", + "babel-runtime": "^6.22.0" } }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browser-cookies": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browser-cookies/-/browser-cookies-1.2.0.tgz", - "integrity": "sha1-/KP/ubamOq3E2MCZnGtX0Pp9KbU=" - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "babel-plugin-transform-function-bind": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz", + "integrity": "sha1-xvuOlqwpajELjPjqQBRiQH3fapc=", "dev": true, "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } + "babel-plugin-syntax-function-bind": "^6.8.0", + "babel-runtime": "^6.22.0" } }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, + "babel-plugin-transform-object-assign": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-assign/-/babel-plugin-transform-object-assign-6.22.0.tgz", + "integrity": "sha1-+Z0vZvGgsNSY40bFNZaEdAyqILo=", "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "babel-runtime": "^6.22.0" } }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", "dev": true, "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" } }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "babel-plugin-transform-react-display-name": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", + "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", "dev": true, "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "babel-runtime": "^6.22.0" } }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "babel-plugin-transform-react-jsx": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", + "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", "dev": true, "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" + "babel-helper-builder-react-jsx": "^6.24.1", + "babel-plugin-syntax-jsx": "^6.8.0", + "babel-runtime": "^6.22.0" } }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "babel-plugin-transform-react-jsx-self": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", + "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", "dev": true, "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" + "babel-plugin-syntax-jsx": "^6.8.0", + "babel-runtime": "^6.22.0" } }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "babel-plugin-transform-react-jsx-source": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", + "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", "dev": true, "requires": { - "pako": "~1.0.5" + "babel-plugin-syntax-jsx": "^6.8.0", + "babel-runtime": "^6.22.0" } }, - "browserslist": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.9.1.tgz", - "integrity": "sha512-Q0DnKq20End3raFulq6Vfp1ecB9fh8yUNV55s8sekaDDeqBaCtWlRHCUdaWyUeSSBJM7IbM6HcsyaeYqgeDhnw==", + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001030", - "electron-to-chromium": "^1.3.363", - "node-releases": "^1.1.50" + "regenerator-transform": "^0.10.0" + }, + "dependencies": { + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" + } + } } }, - "browserstack": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz", - "integrity": "sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==", + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", "dev": true, "requires": { - "https-proxy-agent": "^2.2.1" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, - "browserstack-local": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.4.5.tgz", - "integrity": "sha512-0/VdSv2YVXmcnwBb64XThMvjM1HnZJnPdv7CUgQbC5y/N9Wsr0Fu+j1oknE9fC/VPx9CpoSC6CJ0kza42skMSA==", + "babel-preset-env": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", + "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", "dev": true, "requires": { - "https-proxy-agent": "^4.0.0", - "is-running": "^2.1.0", - "ps-tree": "=1.2.0", - "temp-fs": "^0.9.9" + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-syntax-trailing-function-commas": "^6.22.0", + "babel-plugin-transform-async-to-generator": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.23.0", + "babel-plugin-transform-es2015-classes": "^6.23.0", + "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", + "babel-plugin-transform-es2015-for-of": "^6.23.0", + "babel-plugin-transform-es2015-function-name": "^6.22.0", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-umd": "^6.23.0", + "babel-plugin-transform-es2015-object-super": "^6.22.0", + "babel-plugin-transform-es2015-parameters": "^6.23.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", + "babel-plugin-transform-exponentiation-operator": "^6.22.0", + "babel-plugin-transform-regenerator": "^6.22.0", + "browserslist": "^3.2.6", + "invariant": "^2.2.2", + "semver": "^5.3.0" }, "dependencies": { - "agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", - "dev": true - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "https-proxy-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", - "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "browserslist": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", "dev": true, "requires": { - "agent-base": "5", - "debug": "4" + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true } } }, - "browserstacktunnel-wrapper": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.4.tgz", - "integrity": "sha512-GCV599FUUxNOCFl3WgPnfc5dcqq9XTmMXoxWpqkvmk0R9TOIoqmjENNU6LY6DtgIL6WfBVbg/jmWtnM5K6UYSg==", + "babel-preset-flow": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", + "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", "dev": true, "requires": { - "https-proxy-agent": "^2.2.1", - "unzipper": "^0.9.3" + "babel-plugin-transform-flow-strip-types": "^6.22.0" } }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "babel-preset-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", "dev": true, "requires": { - "node-int64": "^0.4.0" + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" } }, - "buffer": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.5.0.tgz", - "integrity": "sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww==", + "babel-preset-react": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", + "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", "dev": true, "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "babel-plugin-syntax-jsx": "^6.3.13", + "babel-plugin-transform-react-display-name": "^6.23.0", + "babel-plugin-transform-react-jsx": "^6.24.1", + "babel-plugin-transform-react-jsx-self": "^6.22.0", + "babel-plugin-transform-react-jsx-source": "^6.22.0", + "babel-preset-flow": "^6.23.0" + } + }, + "babel-preset-stage-0": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz", + "integrity": "sha1-VkLRUEL5E4TX5a+LyIsduVsDnmo=", "dev": true, "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" + "babel-plugin-transform-do-expressions": "^6.22.0", + "babel-plugin-transform-function-bind": "^6.22.0", + "babel-preset-stage-1": "^6.24.1" } }, - "buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, - "buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", - "dev": true - }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "buffer-indexof-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.1.tgz", - "integrity": "sha1-qfuAbOgUXVQoUQznLyeLs2OmOL8=", - "dev": true - }, - "buffer-shims": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", - "dev": true - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true + "babel-preset-stage-1": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz", + "integrity": "sha1-dpLNfc1oSZB+auSgqFWJz7niv7A=", + "dev": true, + "requires": { + "babel-plugin-transform-class-constructor-call": "^6.24.1", + "babel-plugin-transform-export-extensions": "^6.22.0", + "babel-preset-stage-2": "^6.24.1" + } }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "babel-preset-stage-2": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz", + "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=", + "dev": true, + "requires": { + "babel-plugin-syntax-dynamic-import": "^6.18.0", + "babel-plugin-transform-class-properties": "^6.24.1", + "babel-plugin-transform-decorators": "^6.24.1", + "babel-preset-stage-3": "^6.24.1" + } }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "babel-preset-stage-3": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz", + "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=", "dev": true, "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "babel-plugin-syntax-trailing-function-commas": "^6.22.0", + "babel-plugin-transform-async-generator-functions": "^6.24.1", + "babel-plugin-transform-async-to-generator": "^6.24.1", + "babel-plugin-transform-exponentiation-operator": "^6.24.1", + "babel-plugin-transform-object-rest-spread": "^6.22.0" } }, - "cacheable-request": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", - "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", "dev": true, "requires": { - "clone-response": "1.0.2", - "get-stream": "3.0.0", - "http-cache-semantics": "3.8.1", - "keyv": "3.0.0", - "lowercase-keys": "1.0.0", - "normalize-url": "2.0.1", - "responselike": "1.0.2" + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" }, "dependencies": { - "lowercase-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", - "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", - "dev": true - }, - "normalize-url": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", - "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", - "dev": true, - "requires": { - "prepend-http": "^2.0.0", - "query-string": "^5.0.1", - "sort-keys": "^2.0.0" - } - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", "dev": true }, - "query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", - "dev": true, - "requires": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { - "is-plain-obj": "^1.0.0" + "minimist": "^1.2.5" } } } }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { - "callsites": "^0.2.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" }, "dependencies": { - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" } } }, - "callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", - "dev": true - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" }, "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true } } }, - "caniuse-lite": { - "version": "1.0.30001035", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001035.tgz", - "integrity": "sha512-C1ZxgkuA4/bUEdMbU5WrGY4+UhMFFiXrgNAfxiMIqWgFTWfv/xsZCS2xEHT2LMq7xAZfuAnu6mcqyDl0ZR6wLQ==", - "dev": true - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "rsvp": "^4.8.4" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + }, + "dependencies": { + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + } } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "babelify": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-8.0.0.tgz", + "integrity": "sha512-xVr63fKEvMWUrrIbqlHYsMcc5Zdw4FSVesAHgkgajyCE1W8gbm9rbMakqavhxKvikGYMhEcqxTwB/gQmQ6lBtw==", "dev": true }, - "ccount": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz", - "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==", + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "dev": true }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "dev": true, - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, - "chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - } - }, - "chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", - "dev": true, - "requires": { - "traverse": ">=0.3.0 <0.4" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" } }, - "character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", "dev": true }, - "character-entities-html4": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz", - "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==", + "bail": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", + "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", "dev": true }, - "character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "dev": true + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", "dev": true }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", "dev": true }, - "check-types": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", - "integrity": "sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==", + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", "dev": true }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "dev": true, "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "safe-buffer": "5.1.2" } }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "dev": true, "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "tweetnacl": "^0.14.3" } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "beeper": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", "dev": true }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "callsite": "1.0.0" } }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "bfj": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", + "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "bluebird": "^3.5.5", + "check-types": "^8.0.3", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" } }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "big-integer": { + "version": "1.6.48", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", + "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==", "dev": true }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" } }, - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", "dev": true }, - "clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "binaryextensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", + "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", "dev": true }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "dev": true, + "optional": true, "requires": { - "mimic-response": "^1.0.0" + "file-uri-to-path": "1.0.0" } }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", - "dev": true - }, - "cloneable-readable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", - "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "bl": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", + "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", "dev": true, "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + } } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", "dev": true }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, - "collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", + "bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==", "dev": true }, - "collection-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "body": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", + "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", "dev": true, "requires": { - "arr-map": "^2.0.2", - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" + "continuable-cache": "^0.3.1", + "error": "^7.0.0", + "raw-body": "~1.1.0", + "safe-json-parse": "~1.0.1" + }, + "dependencies": { + "bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", + "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", + "dev": true + }, + "raw-body": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", + "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", + "dev": true, + "requires": { + "bytes": "1", + "string_decoder": "0.10" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } } }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" } }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "color-name": "1.1.3" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { - "delayed-stream": "~1.0.0" + "fill-range": "^7.0.1" } }, - "comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "dev": true }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true + "browser-cookies": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browser-cookies/-/browser-cookies-1.2.0.tgz", + "integrity": "sha1-/KP/ubamOq3E2MCZnGtX0Pp9KbU=" }, - "component-bind": { + "browser-process-hrtime": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "component-inherit": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, - "compress-commons": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz", - "integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=", + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", "dev": true, "requires": { - "buffer-crc32": "^0.2.1", - "crc32-stream": "^2.0.0", - "normalize-path": "^2.0.0", - "readable-stream": "^2.0.0" + "resolve": "1.1.7" }, "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "concat-with-sourcemaps": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", - "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true } } }, - "connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, - "requires": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - } - }, - "connect-livereload": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.1.tgz", - "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==", + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "console-browserify": { + "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, "requires": { - "safe-buffer": "5.1.2" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "continuable-cache": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", - "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", - "dev": true - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "requires": { - "safe-buffer": "~5.1.1" + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "copy-props": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", - "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { - "each-props": "^1.3.0", - "is-plain-object": "^2.0.1" + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "core-js": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz", - "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==" - }, - "core-js-compat": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.4.tgz", - "integrity": "sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==", + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { - "browserslist": "^4.8.3", - "semver": "7.0.0" + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" }, "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", "dev": true } } }, - "core-js-pure": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz", - "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "browserify-sign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz", + "integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.2", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } }, - "coveralls": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.9.tgz", - "integrity": "sha512-nNBg3B1+4iDox5A5zqHKzUTiwl2ey4k2o0NEcVZYvl+GOSJdKBj4AJGKLv6h3SvWch7tABHePAQOSZWM9E2hMg==", + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "requires": { - "js-yaml": "^3.13.1", - "lcov-parse": "^1.0.0", - "log-driver": "^1.2.7", - "minimist": "^1.2.0", - "request": "^2.88.0" + "pako": "~1.0.5" } }, - "crc": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "browserslist": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.13.0.tgz", + "integrity": "sha512-MINatJ5ZNrLnQ6blGvePd/QOz9Xtu+Ne+x29iQSCHfkU5BugKVJwZKn/iiL8UbpIpa3JhviKjz+XxMo0m2caFQ==", "dev": true, "requires": { - "buffer": "^5.1.0" + "caniuse-lite": "^1.0.30001093", + "electron-to-chromium": "^1.3.488", + "escalade": "^3.0.1", + "node-releases": "^1.1.58" } }, - "crc32-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", - "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", + "browserstack": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz", + "integrity": "sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==", "dev": true, "requires": { - "crc": "^3.4.4", - "readable-stream": "^2.0.0" + "https-proxy-agent": "^2.2.1" + }, + "dependencies": { + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "browserstack-local": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.4.5.tgz", + "integrity": "sha512-0/VdSv2YVXmcnwBb64XThMvjM1HnZJnPdv7CUgQbC5y/N9Wsr0Fu+j1oknE9fC/VPx9CpoSC6CJ0kza42skMSA==", "dev": true, "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" + "https-proxy-agent": "^4.0.0", + "is-running": "^2.1.0", + "ps-tree": "=1.2.0", + "temp-fs": "^0.9.9" } }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "browserstacktunnel-wrapper": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.4.tgz", + "integrity": "sha512-GCV599FUUxNOCFl3WgPnfc5dcqq9XTmMXoxWpqkvmk0R9TOIoqmjENNU6LY6DtgIL6WfBVbg/jmWtnM5K6UYSg==", "dev": true, "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" + "https-proxy-agent": "^2.2.1", + "unzipper": "^0.9.3" + }, + "dependencies": { + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "node-int64": "^0.4.0" } }, - "criteo-direct-rsa-validate": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/criteo-direct-rsa-validate/-/criteo-direct-rsa-validate-1.1.0.tgz", - "integrity": "sha512-7gQ3zX+d+hS/vOxzLrZ4aRAceB7qNJ0VzaGNpcWjDCmtOpASB50USJDupTik/H2nHgiSAA3VNZ3SFuONs8LR9Q==" - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "dev": true, "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" } }, - "crypto-js": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", - "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true }, - "css": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", - "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-indexof-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.1.tgz", + "integrity": "sha1-qfuAbOgUXVQoUQznLyeLs2OmOL8=", + "dev": true + }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cac": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/cac/-/cac-3.0.4.tgz", + "integrity": "sha1-bSTO7Dcu/lybeYgIvH9JtHJCpO8=", "dev": true, "requires": { - "inherits": "^2.0.3", - "source-map": "^0.6.1", - "source-map-resolve": "^0.5.2", - "urix": "^0.1.0" + "camelcase-keys": "^3.0.0", + "chalk": "^1.1.3", + "indent-string": "^3.0.0", + "minimist": "^1.2.0", + "read-pkg-up": "^1.0.1", + "suffix": "^0.1.0", + "text-table": "^0.2.0" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } } }, - "css-parse": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", - "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "css": "^2.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, - "css-value": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", - "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=", - "dev": true - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "cacheable-lookup": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz", + "integrity": "sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w==", "dev": true }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "cacheable-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", + "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", "dev": true, "requires": { - "cssom": "0.3.x" + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^2.0.0" } }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "array-find-index": "^1.0.1" + "callsites": "^0.2.0" + }, + "dependencies": { + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + } } }, - "custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", "dev": true }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "camelcase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-3.0.0.tgz", + "integrity": "sha1-/AxsNgNj9zd+N5O5oWvM8QcMHKQ=", "dev": true, "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" + "camelcase": "^3.0.0", + "map-obj": "^1.0.0" }, "dependencies": { - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true } } }, - "date-format": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", - "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", + "caniuse-lite": { + "version": "1.0.30001105", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001105.tgz", + "integrity": "sha512-JupOe6+dGMr7E20siZHIZQwYqrllxotAhiaej96y6x00b/48rPt42o+SzOSCPbrpsDWvRja40Hwrj0g0q6LZJg==", "dev": true }, - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", "dev": true, "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" + "rsvp": "^4.8.4" } }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true }, - "debug-fabulous": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", - "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", + "ccount": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz", + "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, "requires": { - "debug": "3.X", - "memoizee": "0.4.X", - "object-assign": "4.X" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", "dev": true, "requires": { - "mimic-response": "^1.0.0" + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" } }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", "dev": true, "requires": { - "type-detect": "^4.0.0" + "traverse": ">=0.3.0 <0.4" } }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", "dev": true }, - "deepmerge": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.0.1.tgz", - "integrity": "sha512-VIPwiMJqJ13ZQfaCsIFnp5Me9tnjURiaIFxfz7EH0Ci0dTSQpZtSLrqOicXqEd/z2r+z+Klk9GzmnRsgpgbOsQ==", + "character-entities-html4": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz", + "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==", "dev": true }, - "default-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "dev": true + }, + "character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "dev": true + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "check-types": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", + "integrity": "sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==", + "dev": true + }, + "chokidar": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.1.tgz", + "integrity": "sha512-TQTJyr2stihpC4Sya9hs2Xh+O2wf+igjL36Y75xx2WdHuiICcn/XJza46Jwt0eT5hVpQOzo3FpY3cj3RVYLX0g==", "dev": true, "requires": { - "kind-of": "^5.0.2" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" } }, - "default-require-extensions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", - "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "chrome-launcher": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz", + "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==", "dev": true, "requires": { - "strip-bom": "^2.0.0" + "@types/node": "*", + "escape-string-regexp": "^1.0.5", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^0.5.3", + "rimraf": "^3.0.2" }, "dependencies": { - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { - "is-utf8": "^0.2.0" + "glob": "^7.1.3" } } } }, - "default-resolution": { + "ci-info": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, "requires": { - "object-keys": "^1.0.12" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-descriptor": "^0.1.0" } } } }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "cli-spinners": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.4.0.tgz", + "integrity": "sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA==", "dev": true }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" } }, - "destroy": { + "clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "detab": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.3.tgz", - "integrity": "sha512-Up8P0clUVwq0FnFjDclzZsy9PadzRn5FFxrr47tQQvMHqyiFYVbpH8oXDzWtF0Q7pYy3l+RPmtBl+BsFF6wH0A==", - "dev": true, - "requires": { - "repeat-string": "^1.5.4" - } + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true }, - "detect-file": { + "clone-buffer": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", "dev": true }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", "dev": true, "requires": { - "repeating": "^2.0.0" + "mimic-response": "^1.0.0" } }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", "dev": true }, - "detective": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", - "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", "dev": true, "requires": { - "acorn": "^5.2.1", - "defined": "^1.0.0" + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, - "di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, - "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "collapse-white-space": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", + "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", "dev": true }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", "dev": true, "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" } }, - "disparity": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/disparity/-/disparity-2.0.0.tgz", - "integrity": "sha1-V92stHMkrl9Y0swNqIbbTOnutxg=", + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "ansi-styles": "^2.0.1", - "diff": "^1.3.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - } + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, - "dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "color-name": "1.1.3" } }, - "doctrine-temporary-fork": { - "version": "2.0.0-alpha-allowarrayindex", - "resolved": "https://registry.npmjs.org/doctrine-temporary-fork/-/doctrine-temporary-fork-2.0.0-alpha-allowarrayindex.tgz", - "integrity": "sha1-QAFahn6yfnWybIKLcVJPE3+J+fA=", + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "delayed-stream": "~1.0.0" } }, - "documentation": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/documentation/-/documentation-5.5.0.tgz", - "integrity": "sha512-Aod3HOI+8zMhwWztDlECRsDfJ8SFu4oADvipOLq3gnWKy4Cpg2oF5AWT+U6PcX85KuguDI6c+q+2YwYEx99B/A==", + "comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "dev": true + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compress-commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-3.0.0.tgz", + "integrity": "sha512-FyDqr8TKX5/X0qo+aVfaZ+PVmNJHJeckFBlq8jZGSJOgnynhfifoyl24qaqdUdDIBe0EVTHByN6NAkqYvE/2Xg==", "dev": true, "requires": { - "ansi-html": "^0.0.7", - "babel-core": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-plugin-system-import-transformer": "3.1.0", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-preset-env": "^1.6.1", - "babel-preset-react": "^6.24.1", - "babel-preset-stage-0": "^6.24.1", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babelify": "^8.0.0", - "babylon": "^6.18.0", - "chalk": "^2.3.0", - "chokidar": "^2.0.0", - "concat-stream": "^1.6.0", - "disparity": "^2.0.0", - "doctrine-temporary-fork": "2.0.0-alpha-allowarrayindex", - "get-port": "^3.2.0", - "git-url-parse": "^8.0.0", - "github-slugger": "1.2.0", - "glob": "^7.1.2", - "globals-docs": "^2.4.0", - "highlight.js": "^9.12.0", - "js-yaml": "^3.10.0", - "lodash": "^4.17.4", - "mdast-util-inject": "^1.1.0", - "micromatch": "^3.1.5", - "mime": "^1.4.1", - "module-deps-sortable": "4.0.6", - "parse-filepath": "^1.0.2", - "pify": "^3.0.0", - "read-pkg-up": "^3.0.0", - "remark": "^9.0.0", - "remark-html": "7.0.0", - "remark-reference-links": "^4.0.1", - "remark-toc": "^5.0.0", - "remote-origin-url": "0.4.0", - "shelljs": "^0.8.1", - "stream-array": "^1.1.2", - "strip-json-comments": "^2.0.1", - "tiny-lr": "^1.1.0", - "unist-builder": "^1.0.2", - "unist-util-visit": "^1.3.0", - "vfile": "^2.3.0", - "vfile-reporter": "^4.0.0", - "vfile-sort": "^2.1.0", - "vinyl": "^2.1.0", - "vinyl-fs": "^3.0.2", - "yargs": "^9.0.1" + "buffer-crc32": "^0.2.13", + "crc32-stream": "^3.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^2.3.7" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { - "p-try": "^1.0.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { - "p-limit": "^1.1.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + } + } + }, + "concat-with-sourcemaps": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true - }, - "yargs": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz", - "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", - "dev": true, - "requires": { - "camelcase": "^4.1.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "read-pkg-up": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^7.0.0" - }, - "dependencies": { - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - } - } - }, - "yargs-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", - "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } } } }, - "dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "requires": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" } }, - "domain-browser": { + "connect-livereload": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.1.tgz", + "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==", + "dev": true + }, + "console-browserify": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", "dev": true }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", "requires": { - "webidl-conversions": "^4.0.2" + "safe-buffer": "5.1.2" } }, - "dset": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/dset/-/dset-2.0.1.tgz", - "integrity": "sha512-nI29OZMRYq36hOcifB6HTjajNAAiBKSXsyWZrq+VniusseuP2OpNlTiYgsaNRSGvpyq5Wjbc2gQLyBdTyWqhnQ==" + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "continuable-cache": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", + "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", "dev": true }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", "dev": true, "requires": { - "readable-stream": "^2.0.2" + "safe-buffer": "~5.1.1" } }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "copy-props": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", "dev": true, "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "each-props": "^1.3.0", + "is-plain-object": "^2.0.1" } }, - "each-props": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==" + }, + "core-js-compat": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", + "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", "dev": true, "requires": { - "is-plain-object": "^2.0.1", - "object.defaults": "^1.1.0" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "browserslist": "^4.8.5", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } } }, - "editions": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", - "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", - "dev": true - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "ejs": { - "version": "2.5.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.9.tgz", - "integrity": "sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ==", - "dev": true + "core-js-pure": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz", + "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==" }, - "electron-to-chromium": { - "version": "1.3.376", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.376.tgz", - "integrity": "sha512-cv/PYVz5szeMz192ngilmezyPNFkUjuynuL2vNdiqIrio440nfTDdc0JJU0TS2KHLSVCs9gBbt4CFqM+HcBnjw==", + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, - "elliptic": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", - "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "coveralls": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.0.tgz", + "integrity": "sha512-sHxOu2ELzW8/NC1UP5XVLbZDzO4S3VxfFye3XYCznopHy02YjNkHcj5bKaVw2O7hVaBdBjEdQGpie4II1mWhuQ==", "dev": true, "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "js-yaml": "^3.13.1", + "lcov-parse": "^1.0.0", + "log-driver": "^1.2.7", + "minimist": "^1.2.5", + "request": "^2.88.2" } }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", "dev": true, "requires": { - "once": "^1.4.0" + "buffer": "^5.1.0" } }, - "engine.io": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", - "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "crc32-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-3.0.1.tgz", + "integrity": "sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==", "dev": true, "requires": { - "accepts": "~1.3.4", - "base64id": "1.0.0", - "cookie": "0.3.1", - "debug": "~3.1.0", - "engine.io-parser": "~2.1.0", - "ws": "~3.3.1" - }, - "dependencies": { - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "dev": true - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - } + "crc": "^3.4.4", + "readable-stream": "^3.4.0" } }, - "engine.io-client": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", - "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "dev": true, "requires": { - "component-emitter": "1.2.1", - "component-inherit": "0.0.3", - "debug": "~3.1.0", - "engine.io-parser": "~2.1.1", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "ws": "~3.3.1", - "xmlhttprequest-ssl": "~1.5.4", - "yeast": "0.1.2" + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" }, "dependencies": { - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", "dev": true - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } } } }, - "engine.io-parser": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", - "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.5", - "has-binary2": "~1.0.2" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, - "enhanced-resolve": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", - "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "object-assign": "^4.0.1", - "tapable": "^0.2.7" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", - "dev": true + "criteo-direct-rsa-validate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/criteo-direct-rsa-validate/-/criteo-direct-rsa-validate-1.1.0.tgz", + "integrity": "sha512-7gQ3zX+d+hS/vOxzLrZ4aRAceB7qNJ0VzaGNpcWjDCmtOpASB50USJDupTik/H2nHgiSAA3VNZ3SFuONs8LR9Q==" }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", "dev": true, "requires": { - "prr": "~1.0.1" + "lru-cache": "^4.0.1", + "which": "^1.2.9" } }, - "error": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", - "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, "requires": { - "string-template": "~0.2.1" + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", "dev": true, "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", - "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dev": true, - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } + "css-value": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", + "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=", + "dev": true }, - "es5-shim": { - "version": "4.5.13", - "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.13.tgz", - "integrity": "sha512-xi6hh6gsvDE0MaW4Vp1lgNEBpVcCXRWfPXj5egDvtgLz4L9MEvNwYEMdJH+JJinWkwa8c3c3o5HduV7dB/e1Hw==", + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", "dev": true, "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" + "cssom": "0.3.x" } }, - "es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "dev": true, "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" + "array-find-index": "^1.0.1" } }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", "dev": true }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", "dev": true, "requires": { - "es6-promise": "^4.0.3" + "es5-ext": "^0.10.50", + "type": "^1.0.1" } }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" }, "dependencies": { - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", "dev": true, "requires": { - "d": "1", - "es5-ext": "~0.10.14" + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" } } } }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "date-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", + "dev": true + }, + "dateformat": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", "dev": true, "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" + "get-stdin": "^4.0.1", + "meow": "^3.3.0" } }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "debug-fabulous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", + "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", "dev": true, "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" + "debug": "3.X", + "memoizee": "0.4.X", + "object-assign": "4.X" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, - "escodegen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", - "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "mimic-response": "^3.1.0" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true } } }, - "escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { - "es6-map": "^0.1.3", - "es6-weak-map": "^2.0.1", - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "type-detect": "^4.0.0" } }, - "eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "deep-equal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.3.tgz", + "integrity": "sha512-Spqdl4H+ky45I9ByyJtXteOm9CaIrPmnIPmOhrkKGNYWeDgCvJ8jNYVCTjChxW4FqGuZnLHADc8EKRMX6+CgvA==", "dev": true, "requires": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.4", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" + "es-abstract": "^1.17.5", + "es-get-iterator": "^1.1.0", + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.2", + "is-regex": "^1.0.5", + "isarray": "^2.0.5", + "object-is": "^1.1.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.2", + "which-boxed-primitive": "^1.0.1", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.2" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true - }, - "cross-spawn": { + } + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "dev": true, + "requires": { + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } } } }, - "eslint-config-standard": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", - "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "default-require-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "dev": true, + "requires": { + "strip-bom": "^2.0.0" + } + }, + "default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", "dev": true }, - "eslint-import-resolver-node": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", - "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, + "optional": true, "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" + "clone": "^1.0.2" } }, - "eslint-module-utils": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz", - "integrity": "sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==", + "defer-to-connect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", + "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "p-try": "^1.0.0" + "kind-of": "^6.0.0" } }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "p-limit": "^1.1.0" + "kind-of": "^6.0.0" } }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "find-up": "^2.1.0" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } }, - "eslint-plugin-import": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", - "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "dev": true, "requires": { - "array-includes": "^3.0.3", - "array.prototype.flat": "^1.2.1", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.1", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.0", - "read-pkg-up": "^2.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - } + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, - "eslint-plugin-node": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz", - "integrity": "sha512-xhPXrh0Vl/b7870uEbaumb2Q+LxaEcOQ3kS1jtIXanBAwpMre1l5q/l2l/hESYJGEFKuI78bp6Uw50hlpr7B+g==", + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detab": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.3.tgz", + "integrity": "sha512-Up8P0clUVwq0FnFjDclzZsy9PadzRn5FFxrr47tQQvMHqyiFYVbpH8oXDzWtF0Q7pYy3l+RPmtBl+BsFF6wH0A==", "dev": true, "requires": { - "ignore": "^3.3.6", - "minimatch": "^3.0.4", - "resolve": "^1.3.3", - "semver": "5.3.0" - }, - "dependencies": { - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true - } + "repeat-string": "^1.5.4" } }, - "eslint-plugin-prebid": { - "version": "file:plugins/eslint", - "dev": true - }, - "eslint-plugin-promise": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz", - "integrity": "sha512-JiFL9UFR15NKpHyGii1ZcvmtIqa3UTwiDAGb8atSffe43qJ3+1czVGN6UtkklpcJ2DVnqvTMzEKRaJdBkAL2aQ==", - "dev": true - }, - "eslint-plugin-standard": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz", - "integrity": "sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w==", + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true }, - "eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "dev": true, "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "repeating": "^2.0.0" } }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dev": true, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", "dev": true }, - "esquery": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.1.0.tgz", - "integrity": "sha512-MxYW9xKmROWF672KqjO75sszsA8Mxhw06YFeS5VHlB98KDHbOSurm3ArsjO60Eaf3QmGMCP1yn+0JQkNLo/97Q==", + "detective": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", + "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", "dev": true, "requires": { - "estraverse": "^4.0.0" + "acorn": "^5.2.1", + "defined": "^1.0.0" } }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "devtools": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-6.3.4.tgz", + "integrity": "sha512-dOcLdArp5/dJBzD8T5wcT2YgqkA22Mkqo0OS9cXz7JkHNgwOx1FI2Bq9GvP6o0TENHifYSYg3G0K/z0bacekqg==", "dev": true, "requires": { - "estraverse": "^4.1.0" + "@wdio/config": "6.1.14", + "@wdio/logger": "6.0.16", + "@wdio/protocols": "6.3.0", + "@wdio/utils": "6.3.0", + "chrome-launcher": "^0.13.1", + "puppeteer-core": "^5.1.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" } }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "devtools-protocol": { + "version": "0.0.781568", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.781568.tgz", + "integrity": "sha512-9Uqnzy6m6zEStluH9iyJ3iHyaQziFnMnLeC8vK0eN6smiJmIx7+yB64d67C2lH/LZra+5cGscJAJsNXO+MdPMg==", "dev": true }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", "dev": true }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "diff-sequences": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.0.0.tgz", + "integrity": "sha512-JC/eHYEC3aSS0vZGjuoc4vHA0yAQTzhQQldXMeMF+JlxLGJlCO38Gma82NV9gk1jGFz8mDzUMeaKXvjRRdJ2dg==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { - "d": "1", - "es5-ext": "~0.10.14" + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, - "event-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "disparity": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/disparity/-/disparity-2.0.0.tgz", + "integrity": "sha1-V92stHMkrl9Y0swNqIbbTOnutxg=", "dev": true, "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" + "ansi-styles": "^2.0.1", + "diff": "^1.3.2" }, "dependencies": { - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", "dev": true } } }, - "eventemitter3": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", - "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", - "dev": true - }, - "events": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", - "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==", - "dev": true + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "esutils": "^2.0.2", + "isarray": "^1.0.0" } }, - "exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "doctrine-temporary-fork": { + "version": "2.0.0-alpha-allowarrayindex", + "resolved": "https://registry.npmjs.org/doctrine-temporary-fork/-/doctrine-temporary-fork-2.0.0-alpha-allowarrayindex.tgz", + "integrity": "sha1-QAFahn6yfnWybIKLcVJPE3+J+fA=", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } + "esutils": "^2.0.2", + "isarray": "^1.0.0" } }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "documentation": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/documentation/-/documentation-5.5.0.tgz", + "integrity": "sha512-Aod3HOI+8zMhwWztDlECRsDfJ8SFu4oADvipOLq3gnWKy4Cpg2oF5AWT+U6PcX85KuguDI6c+q+2YwYEx99B/A==", "dev": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "ansi-html": "^0.0.7", + "babel-core": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-plugin-system-import-transformer": "3.1.0", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.24.1", + "babel-preset-stage-0": "^6.24.1", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babelify": "^8.0.0", + "babylon": "^6.18.0", + "chalk": "^2.3.0", + "chokidar": "^2.0.0", + "concat-stream": "^1.6.0", + "disparity": "^2.0.0", + "doctrine-temporary-fork": "2.0.0-alpha-allowarrayindex", + "get-port": "^3.2.0", + "git-url-parse": "^8.0.0", + "github-slugger": "1.2.0", + "glob": "^7.1.2", + "globals-docs": "^2.4.0", + "highlight.js": "^9.12.0", + "js-yaml": "^3.10.0", + "lodash": "^4.17.4", + "mdast-util-inject": "^1.1.0", + "micromatch": "^3.1.5", + "mime": "^1.4.1", + "module-deps-sortable": "4.0.6", + "parse-filepath": "^1.0.2", + "pify": "^3.0.0", + "read-pkg-up": "^3.0.0", + "remark": "^9.0.0", + "remark-html": "7.0.0", + "remark-reference-links": "^4.0.1", + "remark-toc": "^5.0.0", + "remote-origin-url": "0.4.0", + "shelljs": "^0.8.1", + "stream-array": "^1.1.2", + "strip-json-comments": "^2.0.1", + "tiny-lr": "^1.1.0", + "unist-builder": "^1.0.2", + "unist-util-visit": "^1.3.0", + "vfile": "^2.3.0", + "vfile-reporter": "^4.0.0", + "vfile-sort": "^2.1.0", + "vinyl": "^2.1.0", + "vinyl-fs": "^3.0.2", + "yargs": "^9.0.1" }, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } - } - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "requires": { - "fill-range": "^2.1.0" - }, - "dependencies": { + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, - "is-number": { + "find-up": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "locate-path": "^2.0.0" } }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, + "optional": true, "requires": { - "isarray": "1.0.0" + "bindings": "^1.5.0", + "nan": "^2.12.1" } }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", + "dev": true + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } } - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - } - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dev": true, - "requires": { - "type": "^2.0.0" - }, - "dependencies": { - "type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", - "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", - "dev": true - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { + }, + "is-binary-path": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "binary-extensions": "^1.0.0" } - } - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "number-is-nan": "^1.0.0" } }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { - "kind-of": "^6.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" } }, - "is-data-descriptor": { + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { - "kind-of": "^6.0.0" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "pify": "^3.0.0" } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "faker": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/faker/-/faker-3.1.0.tgz", - "integrity": "sha1-D5CPr05uwCUk5UpX5DLFwBPgjJ8=", - "dev": true - }, - "fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", - "dev": true, - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "requires": { - "bser": "2.1.1" + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz", + "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^7.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + } + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } } }, - "fibers": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-3.1.1.tgz", - "integrity": "sha512-dl3Ukt08rHVQfY8xGD0ODwyjwrRALtaghuqGH2jByYX1wpY+nAnRQjJ6Dbqq0DnVgNVQ9yibObzbF4IlPyiwPw==", + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", "dev": true, "requires": { - "detect-libc": "^1.0.3" + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" } }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "webidl-conversions": "^4.0.2" } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, - "filename-regex": { + "dset": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "resolved": "https://registry.npmjs.org/dset/-/dset-2.0.1.tgz", + "integrity": "sha512-nI29OZMRYq36hOcifB6HTjajNAAiBKSXsyWZrq+VniusseuP2OpNlTiYgsaNRSGvpyq5Wjbc2gQLyBdTyWqhnQ==" + }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, - "fileset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", - "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, "requires": { - "glob": "^7.0.3", - "minimatch": "^3.0.3" + "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, - "filesize": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", - "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" }, "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } } } }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", "dev": true, "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" } }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "easy-table": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.1.tgz", + "integrity": "sha512-C9Lvm0WFcn2RgxbMnTbXZenMIWcBtkzMr+dWqq/JsVoGFSVUVlPqeOa5LP5kM0I3zoOazFpckOEb2/0LDFfToQ==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "ansi-regex": "^3.0.0", + "wcwidth": ">=1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } } }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "dev": true, "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "editions": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", + "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", + "dev": true + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "ejs": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.3.tgz", + "integrity": "sha512-wmtrUGyfSC23GC/B1SMv2ogAUgbQEtDmTIhfqielrG5ExIM9TP4UoYdi90jLF1aTcsWCJNEO0UrgKzP0y3nTSg==", "dev": true, "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" + "jake": "^10.6.1" } }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "electron-to-chromium": { + "version": "1.3.505", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.505.tgz", + "integrity": "sha512-Aunrp3HWtmdiJLIl+IPSFtEvJ/4Q9a3eKaxmzCthaZF1gbTbpHUTCU2zOVnFPH7r/AD7zQXyuFidYXzSHXBdsw==", "dev": true }, - "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", "dev": true, "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" }, "dependencies": { - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true } } }, - "flatted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "once": "^1.4.0" } }, - "follow-redirects": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.10.0.tgz", - "integrity": "sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ==", + "engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", "dev": true, "requires": { - "debug": "^3.0.0" + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" }, "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.0.0" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } } } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", "dev": true, "requires": { - "for-in": "^1.0.1" - } - }, - "foreachasync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", - "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "fork-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", - "integrity": "sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", "dev": true, "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" } }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "enhanced-resolve": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", + "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", "dev": true, "requires": { - "map-cache": "^0.2.2" + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "object-assign": "^4.0.1", + "tapable": "^0.2.7" } }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true }, - "from": { + "errno": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", - "dev": true + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "error": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", + "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "string-template": "~0.2.1" } }, - "fs-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", - "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { - "null-check": "^1.0.0" + "is-arrayish": "^0.2.1" } }, - "fs-constants": { + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-array-method-boxes-properly": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", "dev": true }, - "fs-extra": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz", - "integrity": "sha1-9G8MdbeEH40gCzNIzU1pHVoJnRU=", + "es-get-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", + "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", "dev": true, "requires": { - "jsonfile": "~1.0.1", - "mkdirp": "0.3.x", - "ncp": "~0.4.2", - "rimraf": "~2.2.0" + "es-abstract": "^1.17.4", + "has-symbols": "^1.0.1", + "is-arguments": "^1.0.4", + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-string": "^1.0.5", + "isarray": "^2.0.5" }, "dependencies": { - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", - "dev": true - }, - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true } } }, - "fs-mkdirp-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" } }, - "fs.extra": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz", - "integrity": "sha1-3QI/kwE77iRTHxszUUw3sg/ZM0k=", + "es5-shim": { + "version": "4.5.14", + "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.14.tgz", + "integrity": "sha512-7SwlpL+2JpymWTt8sNLuC2zdhhc+wrfe5cMPI2j0o6WsPdfAiPwmFy2f0AocPB4RQVBOZ9kNTgi5YF7TdhkvEg==", + "dev": true + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "dev": true, "requires": { - "fs-extra": "~0.6.1", - "mkdirp": "~0.3.5", - "walk": "^2.3.9" - }, - "dependencies": { - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", - "dev": true - } + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "dev": true }, - "fsevents": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", - "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", "dev": true, - "optional": true, "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1", - "node-pre-gyp": "*" + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" }, "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "dev": true, - "optional": true, "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "d": "1", + "es5-ext": "~0.10.14" } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, + } + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "escalade": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz", + "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true + } + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true }, - "concat-map": { - "version": "0.0.1", - "bundled": true, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, - "optional": true + "requires": { + "restore-cursor": "^2.0.0" + } }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, - "optional": true + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } }, "debug": { "version": "3.2.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, - "optional": true, "requires": { "ms": "^2.1.1" } }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.7", - "bundled": true, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "optional": true, "requires": { - "minipass": "^2.6.0" + "esutils": "^2.0.2" } }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, - "optional": true, "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" } }, - "glob": { - "version": "7.1.6", - "bundled": true, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, - "optional": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "escape-string-regexp": "^1.0.5" } }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" } }, - "ignore-walk": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true }, - "inflight": { - "version": "1.0.6", - "bundled": true, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, - "optional": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "minimist": "^1.2.5" } }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "optional": true + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, - "optional": true, "requires": { - "number-is-nan": "^1.0.0" + "mimic-fn": "^1.0.0" } }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, - "optional": true, "requires": { - "brace-expansion": "^1.1.7" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.9.0", - "bundled": true, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, - "optional": true, "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, - "minizlib": { - "version": "1.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, - "optional": true, "requires": { - "minimist": "0.0.8" + "ansi-regex": "^3.0.0" } }, - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.4.0", - "bundled": true, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, + "eslint-config-standard": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", + "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, - "optional": true, "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" + "locate-path": "^2.0.0" } }, - "node-pre-gyp": { - "version": "0.14.0", - "bundled": true, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, - "optional": true, "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, - "nopt": { - "version": "4.0.1", - "bundled": true, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, - "optional": true, "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "p-try": "^1.0.0" } }, - "npm-bundled": { - "version": "1.1.1", - "bundled": true, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, - "optional": true, "requires": { - "npm-normalize-package-bin": "^1.0.1" + "p-limit": "^1.1.0" } }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true }, - "npm-packlist": { - "version": "1.4.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, - "npmlog": { - "version": "4.1.2", - "bundled": true, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, - "optional": true, "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "find-up": "^2.1.0" } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, + } + } + }, + "eslint-plugin-import": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", + "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.3", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, - "optional": true, "requires": { - "wrappy": "1" + "locate-path": "^2.0.0" } }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, - "optional": true, "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" } }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, - "optional": true, "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, - "optional": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "p-try": "^1.0.0" } }, - "rimraf": { - "version": "2.7.1", - "bundled": true, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, - "optional": true, "requires": { - "glob": "^7.1.3" + "p-limit": "^1.1.0" } }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true }, - "semver": { - "version": "5.7.1", - "bundled": true, - "dev": true, - "optional": true + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, - "set-blocking": { + "path-type": { "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, - "optional": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "pify": "^2.0.0" } }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, - "optional": true, "requires": { - "safe-buffer": "~5.1.0" + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" } }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, - "optional": true, "requires": { - "ansi-regex": "^2.0.0" + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" } }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.13", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "optional": true + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true } } }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "eslint-plugin-node": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz", + "integrity": "sha512-xhPXrh0Vl/b7870uEbaumb2Q+LxaEcOQ3kS1jtIXanBAwpMre1l5q/l2l/hESYJGEFKuI78bp6Uw50hlpr7B+g==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" + "ignore": "^3.3.6", + "minimatch": "^3.0.4", + "resolve": "^1.3.3", + "semver": "5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } } }, - "fun-hooks": { - "version": "0.9.8", - "resolved": "https://registry.npmjs.org/fun-hooks/-/fun-hooks-0.9.8.tgz", - "integrity": "sha512-FZUHodONJBOCCETXnHTSvqnz+pLZiN2ZqbOZsjXIqJRI8AbvTqOJzDTEeMfPzFf8rPuSZnD5EPcbl7yZsEQ/NA==", - "requires": { - "typescript-tuple": "^2.2.1" - } + "eslint-plugin-prebid": { + "version": "file:plugins/eslint", + "dev": true }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "eslint-plugin-promise": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz", + "integrity": "sha512-JiFL9UFR15NKpHyGii1ZcvmtIqa3UTwiDAGb8atSffe43qJ3+1czVGN6UtkklpcJ2DVnqvTMzEKRaJdBkAL2aQ==", + "dev": true }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "eslint-plugin-standard": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz", + "integrity": "sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w==", "dev": true }, - "gaze": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", - "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", "dev": true, "requires": { - "globule": "^1.0.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, - "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true }, - "get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", - "dev": true + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } }, - "get-stdin": { + "esprima": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } } }, - "git-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/git-up/-/git-up-2.1.0.tgz", - "integrity": "sha512-MJgwfcSd9qxgDyEYpRU/CDxNpUadrK80JHuEQDG4Urn0m7tpSOgCBrtiSIa9S9KH8Tbuo/TN8SSQmJBvsw1HkA==", + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { - "is-ssh": "^1.3.0", - "parse-url": "^3.0.2" + "estraverse": "^4.1.0" } }, - "git-url-parse": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-8.3.1.tgz", - "integrity": "sha512-r/FxXIdfgdSO+V2zl4ZK1JGYkHT9nqVRSzom5WsYPLg3XzeBeKPl3R/6X9E9ZJRx/sE/dXwXtfl+Zp7YL8ktWQ==", + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { - "git-up": "^2.0.0", - "parse-domain": "^2.0.0" + "d": "1", + "es5-ext": "~0.10.14" } }, - "github-slugger": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.2.0.tgz", - "integrity": "sha512-wIaa75k1vZhyPm9yWrD08A5Xnx/V+RmzGrpjQuLemGKSb77Qukiaei58Bogrl/LZSADDfPzKJX8jhLs4CRTl7Q==", + "event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { - "emoji-regex": ">=6.0.0 <=6.1.1" - }, - "dependencies": { - "emoji-regex": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz", - "integrity": "sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4=", - "dev": true - } + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" } }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "events": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "exec-sh": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", + "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" }, "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "is-glob": "^2.0.0" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { - "is-extglob": "^1.0.0" + "pump": "^3.0.0" } } } }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" } } } }, - "glob-stream": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, - "glob-watcher": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", - "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "dev": true, "requires": { - "anymatch": "^2.0.0", - "async-done": "^1.2.0", - "chokidar": "^2.0.0", - "is-negated-glob": "^1.0.0", - "just-debounce": "^1.0.0", - "object.defaults": "^1.1.0" + "homedir-polyfill": "^1.0.1" } }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "expect": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.1.0.tgz", + "integrity": "sha512-QbH4LZXDsno9AACrN9eM0zfnby9G+OsdNgZUohjg/P0mLy1O+/bzTAJGT6VSIjVCe8yKM6SzEl/ckEOFBT7Vnw==", "dev": true, "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "@jest/types": "^26.1.0", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.0.0", + "jest-matcher-utils": "^26.1.0", + "jest-message-util": "^26.1.0", + "jest-regex-util": "^26.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } } }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "expect-webdriverio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-1.2.0.tgz", + "integrity": "sha512-nis1EL4LJSKvhqES6ojx1QqAZYtWAUHaVtwilXBXJELN2YZhwOcrfBT0AvxDvJXYKzgDDTED9STc9MwcK8KbYg==", "dev": true, "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "expect": "^26.0.1", + "jest-matcher-utils": "^26.0.1" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globals-docs": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/globals-docs/-/globals-docs-2.4.1.tgz", - "integrity": "sha512-qpPnUKkWnz8NESjrCvnlGklsgiQzlq+rcCxoG5uNQ+dNA7cFMCmn231slLAwS2N/PlkzZ3COL8CcS10jXmLHqg==", - "dev": true - }, - "globule": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz", - "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==", - "dev": true, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", "requires": { - "glob": "~7.1.1", - "lodash": "~4.17.12", - "minimatch": "~3.0.2" + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" } }, - "glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", "dev": true, "requires": { - "sparkles": "^1.0.0" - } - }, - "got": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", - "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.7.0", - "cacheable-request": "^2.1.1", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "into-stream": "^3.1.0", - "is-retry-allowed": "^1.1.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "mimic-response": "^1.0.0", - "p-cancelable": "^0.4.0", - "p-timeout": "^2.0.1", - "pify": "^3.0.0", - "safe-buffer": "^5.1.1", - "timed-out": "^4.0.1", - "url-parse-lax": "^3.0.0", - "url-to-options": "^1.0.1" + "type": "^2.0.0" }, "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", "dev": true } } }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true - }, - "gulp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "glob-watcher": "^5.0.3", - "gulp-cli": "^2.2.0", - "undertaker": "^1.2.1", - "vinyl-fs": "^3.0.0" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "gulp-cli": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.0.tgz", - "integrity": "sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA==", + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "ansi-colors": "^1.0.1", - "archy": "^1.0.0", - "array-sort": "^1.0.0", - "color-support": "^1.1.3", - "concat-stream": "^1.6.0", - "copy-props": "^2.0.1", - "fancy-log": "^1.3.2", - "gulplog": "^1.0.0", - "interpret": "^1.1.0", - "isobject": "^3.0.1", - "liftoff": "^3.1.0", - "matchdep": "^2.0.0", - "mute-stdout": "^1.0.0", - "pretty-hrtime": "^1.0.0", - "replace-homedir": "^1.0.0", - "semver-greatest-satisfied-range": "^1.1.0", - "v8flags": "^3.0.1", - "yargs": "^7.1.0" + "is-plain-object": "^2.0.4" } - }, - "is-fullwidth-code-point": { + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, - "requires": { - "lcid": "^1.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "pinkie-promise": "^2.0.0" + "is-descriptor": "^1.0.0" } }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "is-extendable": "^0.1.0" } }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "kind-of": "^6.0.0" } }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "kind-of": "^6.0.0" } }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "string-width": { + "is-descriptor": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-utf8": "^0.2.0" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } - }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + } + } + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "ms": "^2.1.1" } }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true - }, - "yargs": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", - "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", - "dev": true, - "requires": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.0" - } - }, - "yargs-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", - "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", - "dev": true, - "requires": { - "camelcase": "^3.0.0" - } } } }, - "gulp-clean": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/gulp-clean/-/gulp-clean-0.3.2.tgz", - "integrity": "sha1-o0fUc6zqQBgvk1WHpFGUFnGSgQI=", + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "faker": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/faker/-/faker-3.1.0.tgz", + "integrity": "sha1-D5CPr05uwCUk5UpX5DLFwBPgjJ8=", + "dev": true + }, + "fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", "dev": true, "requires": { - "gulp-util": "^2.2.14", - "rimraf": "^2.2.8", - "through2": "^0.4.2" + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "fibers": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fibers/-/fibers-4.0.3.tgz", + "integrity": "sha512-MW5VrDtTOLpKK7lzw4qD7Z9tXaAhdOmOED5RHzg3+HjUk+ibkjVW0Py2ERtdqgTXaerLkVkBy2AEmJiT6RMyzg==", + "dev": true, + "requires": { + "detect-libc": "^1.0.3" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "filelist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz", + "integrity": "sha512-8zSK6Nu0DQIC08mUC46sWGXi+q3GGpKydAG36k+JDba6VRpkevvOWUW5a/PhShij4+vHT9M+ghgG7eM+a9JDUQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" }, "dependencies": { - "ansi-regex": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", - "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", - "dev": true + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } }, - "ansi-styles": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", - "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", - "dev": true + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } }, - "chalk": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", - "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "ansi-styles": "^1.1.0", - "escape-string-regexp": "^1.0.0", - "has-ansi": "^0.1.0", - "strip-ansi": "^0.3.0", - "supports-color": "^0.2.0" + "p-limit": "^2.0.0" } }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, - "gulp-util": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-2.2.20.tgz", - "integrity": "sha1-1xRuVyiRC9jwR6awseVJvCLb1kw=", + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "requires": { - "chalk": "^0.5.0", - "dateformat": "^1.0.7-1.2.3", - "lodash._reinterpolate": "^2.4.1", - "lodash.template": "^2.4.1", - "minimist": "^0.2.0", - "multipipe": "^0.1.0", - "through2": "^0.5.0", - "vinyl": "^0.2.1" + "find-up": "^3.0.0" + } + } + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { - "through2": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", - "integrity": "sha1-390BLrnHAOIyP9M084rGIqs3Lac=", + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "readable-stream": "~1.0.17", - "xtend": "~3.0.0" + "is-extendable": "^0.1.0" } } } }, - "has-ansi": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", - "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "ansi-regex": "^0.2.0" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "minimist": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.1.tgz", - "integrity": "sha512-GY8fANSrTMfBVfInqJAY41QkOM+upUTytK1jZ0c8+3HdHrJxBJ3rF5i9moClXTE8uUSnUo8cAsCoxDXvSY4DHg==", - "dev": true - }, - "object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } }, - "strip-ansi": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", - "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "ansi-regex": "^0.2.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } - }, - "supports-color": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", - "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", - "dev": true - }, - "through2": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", - "integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=", + } + } + }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "readable-stream": "~1.0.17", - "xtend": "~2.1.1" - }, - "dependencies": { - "xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", - "dev": true, - "requires": { - "object-keys": "~0.4.0" - } - } + "glob": "^7.1.3" } - }, - "vinyl": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.2.3.tgz", - "integrity": "sha1-vKk4IJWC7FpJrVOKAPofEl5RMlI=", + } + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { - "clone-stats": "~0.0.1" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "follow-redirects": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.12.1.tgz", + "integrity": "sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg==", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "foreachasync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", + "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "fork-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", + "integrity": "sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } - }, - "xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=", - "dev": true } } }, - "gulp-concat": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", - "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "^1.0.0" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + } + }, + "fs.extra": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz", + "integrity": "sha1-3QI/kwE77iRTHxszUUw3sg/ZM0k=", + "dev": true, + "requires": { + "fs-extra": "~0.6.1", + "mkdirp": "~0.3.5", + "walk": "^2.3.9" + }, + "dependencies": { + "fs-extra": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz", + "integrity": "sha1-9G8MdbeEH40gCzNIzU1pHVoJnRU=", + "dev": true, + "requires": { + "jsonfile": "~1.0.1", + "mkdirp": "0.3.x", + "ncp": "~0.4.2", + "rimraf": "~2.2.0" + } + }, + "jsonfile": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz", + "integrity": "sha1-6l7+QLg2kLmGZ2FKc5L8YOhCwN0=", + "dev": true + }, + "mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", + "dev": true + }, + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + } + } + }, + "fun-hooks": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/fun-hooks/-/fun-hooks-0.9.9.tgz", + "integrity": "sha512-821UhoYfO9Sg01wAl/QsDRB088BW0aeOqzC1PXLxSlB+kaUVbK+Vp6wMDHU5huZZopYxmMmv5jDkEYqDpK3hqg==", + "requires": { + "typescript-tuple": "^2.2.1" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "requires": { + "globule": "^1.0.0" + } + }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "git-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-2.1.0.tgz", + "integrity": "sha512-MJgwfcSd9qxgDyEYpRU/CDxNpUadrK80JHuEQDG4Urn0m7tpSOgCBrtiSIa9S9KH8Tbuo/TN8SSQmJBvsw1HkA==", + "dev": true, + "requires": { + "is-ssh": "^1.3.0", + "parse-url": "^3.0.2" + } + }, + "git-url-parse": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-8.3.1.tgz", + "integrity": "sha512-r/FxXIdfgdSO+V2zl4ZK1JGYkHT9nqVRSzom5WsYPLg3XzeBeKPl3R/6X9E9ZJRx/sE/dXwXtfl+Zp7YL8ktWQ==", + "dev": true, + "requires": { + "git-up": "^2.0.0", + "parse-domain": "^2.0.0" + } + }, + "github-slugger": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.2.0.tgz", + "integrity": "sha512-wIaa75k1vZhyPm9yWrD08A5Xnx/V+RmzGrpjQuLemGKSb77Qukiaei58Bogrl/LZSADDfPzKJX8jhLs4CRTl7Q==", + "dev": true, + "requires": { + "emoji-regex": ">=6.0.0 <=6.1.1" + }, + "dependencies": { + "emoji-regex": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz", + "integrity": "sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4=", + "dev": true + } + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "dev": true, + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "dependencies": { + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globals-docs": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/globals-docs/-/globals-docs-2.4.1.tgz", + "integrity": "sha512-qpPnUKkWnz8NESjrCvnlGklsgiQzlq+rcCxoG5uNQ+dNA7cFMCmn231slLAwS2N/PlkzZ3COL8CcS10jXmLHqg==", + "dev": true + }, + "globule": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", + "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, + "glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "requires": { + "sparkles": "^1.0.0" + } + }, + "got": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/got/-/got-11.5.1.tgz", + "integrity": "sha512-reQEZcEBMTGnujmQ+Wm97mJs/OK6INtO6HmLI+xt3+9CvnRwWjXutUvb2mqr+Ao4Lu05Rx6+udx9sOQAmExMxA==", + "dev": true, + "requires": { + "@sindresorhus/is": "^3.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.1", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.0", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "dev": true, + "requires": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "requires": { + "ansi-wrap": "^0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz", + "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "5.0.0-security.0" + } + }, + "yargs-parser": { + "version": "5.0.0-security.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz", + "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + } + } + }, + "gulp-clean": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/gulp-clean/-/gulp-clean-0.3.2.tgz", + "integrity": "sha1-o0fUc6zqQBgvk1WHpFGUFnGSgQI=", + "dev": true, + "requires": { + "gulp-util": "^2.2.14", + "rimraf": "^2.2.8", + "through2": "^0.4.2" + }, + "dependencies": { + "ansi-regex": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", + "dev": true + }, + "ansi-styles": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", + "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", + "dev": true + }, + "chalk": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", + "dev": true, + "requires": { + "ansi-styles": "^1.1.0", + "escape-string-regexp": "^1.0.0", + "has-ansi": "^0.1.0", + "strip-ansi": "^0.3.0", + "supports-color": "^0.2.0" + } + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "dev": true + }, + "gulp-util": { + "version": "2.2.20", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-2.2.20.tgz", + "integrity": "sha1-1xRuVyiRC9jwR6awseVJvCLb1kw=", + "dev": true, + "requires": { + "chalk": "^0.5.0", + "dateformat": "^1.0.7-1.2.3", + "lodash._reinterpolate": "^2.4.1", + "lodash.template": "^2.4.1", + "minimist": "^0.2.0", + "multipipe": "^0.1.0", + "through2": "^0.5.0", + "vinyl": "^0.2.1" + }, + "dependencies": { + "through2": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", + "integrity": "sha1-390BLrnHAOIyP9M084rGIqs3Lac=", + "dev": true, + "requires": { + "readable-stream": "~1.0.17", + "xtend": "~3.0.0" + } + } + } + }, + "has-ansi": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", + "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", + "dev": true, + "requires": { + "ansi-regex": "^0.2.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "minimist": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.1.tgz", + "integrity": "sha512-GY8fANSrTMfBVfInqJAY41QkOM+upUTytK1jZ0c8+3HdHrJxBJ3rF5i9moClXTE8uUSnUo8cAsCoxDXvSY4DHg==", + "dev": true + }, + "object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-ansi": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", + "dev": true, + "requires": { + "ansi-regex": "^0.2.1" + } + }, + "supports-color": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", + "dev": true + }, + "through2": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", + "integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=", + "dev": true, + "requires": { + "readable-stream": "~1.0.17", + "xtend": "~2.1.1" + }, + "dependencies": { + "xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "dev": true, + "requires": { + "object-keys": "~0.4.0" + } + } + } + }, + "vinyl": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.2.3.tgz", + "integrity": "sha1-vKk4IJWC7FpJrVOKAPofEl5RMlI=", + "dev": true, + "requires": { + "clone-stats": "~0.0.1" + } + }, + "xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=", + "dev": true + } + } + }, + "gulp-concat": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", + "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", + "dev": true, + "requires": { + "concat-with-sourcemaps": "^1.0.0", + "through2": "^2.0.0", + "vinyl": "^2.0.0" + } + }, + "gulp-connect": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/gulp-connect/-/gulp-connect-5.7.0.tgz", + "integrity": "sha512-8tRcC6wgXMLakpPw9M7GRJIhxkYdgZsXwn7n56BA2bQYGLR9NOPhMzx7js+qYDy6vhNkbApGKURjAw1FjY4pNA==", + "dev": true, + "requires": { + "ansi-colors": "^2.0.5", + "connect": "^3.6.6", + "connect-livereload": "^0.6.0", + "fancy-log": "^1.3.2", + "map-stream": "^0.0.7", + "send": "^0.16.2", + "serve-index": "^1.9.1", + "serve-static": "^1.13.2", + "tiny-lr": "^1.1.1" + }, + "dependencies": { + "ansi-colors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-2.0.5.tgz", + "integrity": "sha512-yAdfUZ+c2wetVNIFsNRn44THW+Lty6S5TwMpUfLA/UaGhiXbBv/F8E60/1hMLd0cnF/CDoWH8vzVaI5bAcHCjw==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", + "dev": true + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + } + } + }, + "gulp-eslint": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-4.0.2.tgz", + "integrity": "sha512-fcFUQzFsN6dJ6KZlG+qPOEkqfcevRUXgztkYCvhNvJeSvOicC8ucutN4qR/ID8LmNZx9YPIkBzazTNnVvbh8wg==", + "dev": true, + "requires": { + "eslint": "^4.0.0", + "fancy-log": "^1.3.2", + "plugin-error": "^1.0.0" + } + }, + "gulp-footer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/gulp-footer/-/gulp-footer-2.0.2.tgz", + "integrity": "sha512-HsG5VOgKHFRqZXnHGI6oGhPDg70p9pobM+dYOnjBZVLMQUHzLG6bfaPNRJ7XG707E+vWO3TfN0CND9UrYhk94g==", + "dev": true, + "requires": { + "lodash._reescape": "^3.0.0", + "lodash._reevaluate": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.template": "^3.6.2", + "map-stream": "0.0.7" + }, + "dependencies": { + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "dev": true, + "requires": { + "lodash._root": "^3.0.0" + } + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" + } + }, + "map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", + "dev": true + } + } + }, + "gulp-header": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.12.tgz", + "integrity": "sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ==", + "dev": true, + "requires": { + "concat-with-sourcemaps": "*", + "lodash.template": "^4.4.0", + "through2": "^2.0.0" + }, + "dependencies": { + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + } + } + }, + "gulp-if": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/gulp-if/-/gulp-if-2.0.2.tgz", + "integrity": "sha1-pJe351cwBQQcqivIt92jyARE1ik=", + "dev": true, + "requires": { + "gulp-match": "^1.0.3", + "ternary-stream": "^2.0.1", + "through2": "^2.0.1" + } + }, + "gulp-js-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gulp-js-escape/-/gulp-js-escape-1.0.1.tgz", + "integrity": "sha1-HNRF+9AJ4Np2lZoDp/SbNWav+Gg=", + "dev": true, + "requires": { + "through2": "^0.6.3" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, + "gulp-match": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.1.0.tgz", + "integrity": "sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.3" + } + }, + "gulp-replace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.0.0.tgz", + "integrity": "sha512-lgdmrFSI1SdhNMXZQbrC75MOl1UjYWlOWNbNRnz+F/KHmgxt3l6XstBoAYIdadwETFyG/6i+vWUSCawdC3pqOw==", + "dev": true, + "requires": { + "istextorbinary": "2.2.1", + "readable-stream": "^2.0.1", + "replacestream": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "gulp-shell": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/gulp-shell/-/gulp-shell-0.5.2.tgz", + "integrity": "sha1-pJWcoGUa0ce7/nCy0K27tOGuqY0=", + "dev": true, + "requires": { + "async": "^1.5.0", + "gulp-util": "^3.0.7", + "lodash": "^4.0.0", + "through2": "^2.0.0" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } + } + }, + "gulp-sourcemaps": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", + "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", + "dev": true, + "requires": { + "@gulp-sourcemaps/identity-map": "1.X", + "@gulp-sourcemaps/map-sources": "1.X", + "acorn": "5.X", + "convert-source-map": "1.X", + "css": "2.X", + "debug-fabulous": "1.X", + "detect-newline": "2.X", + "graceful-fs": "4.X", + "source-map": "~0.6.0", + "strip-bom-string": "1.X", + "through2": "2.X" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "gulp-uglify": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz", + "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==", + "dev": true, + "requires": { + "array-each": "^1.0.1", + "extend-shallow": "^3.0.2", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "isobject": "^3.0.1", + "make-error-cause": "^1.1.1", + "safe-buffer": "^5.1.2", + "through2": "^2.0.0", + "uglify-js": "^3.0.5", + "vinyl-sourcemaps-apply": "^0.2.0" + } + }, + "gulp-util": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", + "dev": true, + "requires": { + "array-differ": "^1.0.0", + "array-uniq": "^1.0.2", + "beeper": "^1.0.0", + "chalk": "^1.0.0", + "dateformat": "^2.0.0", + "fancy-log": "^1.1.0", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "lodash._reescape": "^3.0.0", + "lodash._reevaluate": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.template": "^3.0.0", + "minimist": "^1.1.0", + "multipipe": "^0.1.2", + "object-assign": "^3.0.0", + "replace-ext": "0.0.1", + "through2": "^2.0.0", + "vinyl": "^0.5.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "dev": true + }, + "dateformat": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", + "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", + "dev": true + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "dev": true, + "requires": { + "lodash._root": "^3.0.0" + } + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" + } + }, + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", + "dev": true + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "vinyl": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "dev": true, + "requires": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + } + } + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "requires": { + "glogg": "^1.0.0" + } + }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "handlebars": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-gulplog": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "dev": true, + "requires": { + "sparkles": "^1.0.0" + } + }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hast-util-is-element": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.0.4.tgz", + "integrity": "sha512-NFR6ljJRvDcyPP5SbV7MyPBgF47X3BsskLnmw1U34yL+X6YC0MoBx9EyMg8Jtx4FzGH95jw8+c1VPLHaRA0wDQ==", + "dev": true + }, + "hast-util-sanitize": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/hast-util-sanitize/-/hast-util-sanitize-1.3.1.tgz", + "integrity": "sha512-AIeKHuHx0Wk45nSkGVa2/ujQYTksnDl8gmmKo/mwQi7ag7IBZ8cM3nJ2G86SajbjGP/HRpud6kMkPtcM2i0Tlw==", + "dev": true, + "requires": { + "xtend": "^4.0.1" + } + }, + "hast-util-to-html": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-3.1.0.tgz", + "integrity": "sha1-iCyZhJ5AEw6ZHAQuRW1FPZXDbP8=", + "dev": true, + "requires": { + "ccount": "^1.0.0", + "comma-separated-tokens": "^1.0.1", + "hast-util-is-element": "^1.0.0", + "hast-util-whitespace": "^1.0.0", + "html-void-elements": "^1.0.0", + "kebab-case": "^1.0.0", + "property-information": "^3.1.0", + "space-separated-tokens": "^1.0.0", + "stringify-entities": "^1.0.1", + "unist-util-is": "^2.0.0", + "xtend": "^4.0.1" + }, + "dependencies": { + "unist-util-is": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-2.1.3.tgz", + "integrity": "sha512-4WbQX2iwfr/+PfM4U3zd2VNXY+dWtZsN1fLnWEi2QQXA4qyDYAZcDMfXUX0Cu6XZUHHAO9q4nyxxLT4Awk1qUA==", + "dev": true + } + } + }, + "hast-util-whitespace": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz", + "integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "highlight.js": { + "version": "9.18.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz", + "integrity": "sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "html-void-elements": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", + "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-parser-js": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz", + "integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "http2-wrapper": { + "version": "1.0.0-beta.5.2", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz", + "integrity": "sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "dev": true, + "requires": { + "agent-base": "5", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "dev": true, + "requires": { + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "dev": true + }, + "is-alphanumeric": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz", + "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=", + "dev": true + }, + "is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dev": true, + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.0.tgz", + "integrity": "sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.1.tgz", + "integrity": "sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==", + "dev": true + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-docker": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-1.1.0.tgz", + "integrity": "sha1-8EN01O7lMQ6ajhE78UlUEeRhdqE=", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "dev": true + }, + "is-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", + "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", + "dev": true + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "dev": true + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true + }, + "is-running": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz", + "integrity": "sha1-MKc/9cw4VOT8JUkICen1q/jeCeA=", + "dev": true + }, + "is-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", + "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", + "dev": true + }, + "is-ssh": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.1.tgz", + "integrity": "sha512-0eRIASHZt1E68/ixClI8bp2YK2wmBPVWEismTs6M+M099jKgrzl/3E976zIbImSIob48N2/XGe9y7ZiYdImSlg==", + "dev": true, + "requires": { + "protocols": "^1.1.0" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "dev": true, "requires": { - "concat-with-sourcemaps": "^1.0.0", - "through2": "^2.0.0", - "vinyl": "^2.0.0" + "has-symbols": "^1.0.1" } }, - "gulp-connect": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/gulp-connect/-/gulp-connect-5.7.0.tgz", - "integrity": "sha512-8tRcC6wgXMLakpPw9M7GRJIhxkYdgZsXwn7n56BA2bQYGLR9NOPhMzx7js+qYDy6vhNkbApGKURjAw1FjY4pNA==", + "is-typed-array": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.3.tgz", + "integrity": "sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==", "dev": true, "requires": { - "ansi-colors": "^2.0.5", - "connect": "^3.6.6", - "connect-livereload": "^0.6.0", - "fancy-log": "^1.3.2", - "map-stream": "^0.0.7", - "send": "^0.16.2", - "serve-index": "^1.9.1", - "serve-static": "^1.13.2", - "tiny-lr": "^1.1.1" - }, - "dependencies": { - "ansi-colors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-2.0.5.tgz", - "integrity": "sha512-yAdfUZ+c2wetVNIFsNRn44THW+Lty6S5TwMpUfLA/UaGhiXbBv/F8E60/1hMLd0cnF/CDoWH8vzVaI5bAcHCjw==", - "dev": true - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true - }, - "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" - } - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true - } + "available-typed-arrays": "^1.0.0", + "es-abstract": "^1.17.4", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" } }, - "gulp-eslint": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-4.0.2.tgz", - "integrity": "sha512-fcFUQzFsN6dJ6KZlG+qPOEkqfcevRUXgztkYCvhNvJeSvOicC8ucutN4qR/ID8LmNZx9YPIkBzazTNnVvbh8wg==", + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { - "eslint": "^4.0.0", - "fancy-log": "^1.3.2", - "plugin-error": "^1.0.0" + "unc-path-regex": "^0.1.2" } }, - "gulp-footer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/gulp-footer/-/gulp-footer-2.0.2.tgz", - "integrity": "sha512-HsG5VOgKHFRqZXnHGI6oGhPDg70p9pobM+dYOnjBZVLMQUHzLG6bfaPNRJ7XG707E+vWO3TfN0CND9UrYhk94g==", + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", + "dev": true + }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true + }, + "is-weakset": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz", + "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==", + "dev": true + }, + "is-whitespace-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", + "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-word-character": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", + "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "requires": { - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.6.2", - "map-stream": "0.0.7" + "is-docker": "^2.0.0" }, "dependencies": { - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "is-docker": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz", + "integrity": "sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==", "dev": true - }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "requires": { - "lodash._root": "^3.0.0" - } - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } } } }, - "gulp-header": { - "version": "1.8.12", - "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.12.tgz", - "integrity": "sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ==", + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, "requires": { - "concat-with-sourcemaps": "*", - "lodash.template": "^4.4.0", - "through2": "^2.0.0" + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" }, "dependencies": { - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, - "lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" } }, - "lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, "requires": { - "lodash._reinterpolate": "^3.0.0" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } - } - } - }, - "gulp-if": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/gulp-if/-/gulp-if-2.0.2.tgz", - "integrity": "sha1-pJe351cwBQQcqivIt92jyARE1ik=", - "dev": true, - "requires": { - "gulp-match": "^1.0.3", - "ternary-stream": "^2.0.1", - "through2": "^2.0.1" - } - }, - "gulp-js-escape": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gulp-js-escape/-/gulp-js-escape-1.0.1.tgz", - "integrity": "sha1-HNRF+9AJ4Np2lZoDp/SbNWav+Gg=", - "dev": true, - "requires": { - "through2": "^0.6.3" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", "dev": true }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "minimist": "^1.2.5" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "dev": true, + "optional": true, "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" + "amdefine": ">=0.0.4" + } + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" } } } }, - "gulp-match": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.1.0.tgz", - "integrity": "sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ==", - "dev": true, - "requires": { - "minimatch": "^3.0.3" - } - }, - "gulp-replace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.0.0.tgz", - "integrity": "sha512-lgdmrFSI1SdhNMXZQbrC75MOl1UjYWlOWNbNRnz+F/KHmgxt3l6XstBoAYIdadwETFyG/6i+vWUSCawdC3pqOw==", - "dev": true, - "requires": { - "istextorbinary": "2.2.1", - "readable-stream": "^2.0.1", - "replacestream": "^4.0.0" - } - }, - "gulp-shell": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/gulp-shell/-/gulp-shell-0.5.2.tgz", - "integrity": "sha1-pJWcoGUa0ce7/nCy0K27tOGuqY0=", - "dev": true, - "requires": { - "async": "^1.5.0", - "gulp-util": "^3.0.7", - "lodash": "^4.0.0", - "through2": "^2.0.0" - } - }, - "gulp-sourcemaps": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", - "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", - "dev": true, - "requires": { - "@gulp-sourcemaps/identity-map": "1.X", - "@gulp-sourcemaps/map-sources": "1.X", - "acorn": "5.X", - "convert-source-map": "1.X", - "css": "2.X", - "debug-fabulous": "1.X", - "detect-newline": "2.X", - "graceful-fs": "4.X", - "source-map": "~0.6.0", - "strip-bom-string": "1.X", - "through2": "2.X" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "gulp-uglify": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz", - "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==", - "dev": true, - "requires": { - "array-each": "^1.0.1", - "extend-shallow": "^3.0.2", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "isobject": "^3.0.1", - "make-error-cause": "^1.1.1", - "safe-buffer": "^5.1.2", - "through2": "^2.0.0", - "uglify-js": "^3.0.5", - "vinyl-sourcemaps-apply": "^0.2.0" - } - }, - "gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", + "istanbul-api": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.7.tgz", + "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==", "dev": true, "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" + "async": "^2.1.4", + "fileset": "^2.0.2", + "istanbul-lib-coverage": "^1.2.1", + "istanbul-lib-hook": "^1.2.2", + "istanbul-lib-instrument": "^1.10.2", + "istanbul-lib-report": "^1.1.5", + "istanbul-lib-source-maps": "^1.2.6", + "istanbul-reports": "^1.5.1", + "js-yaml": "^3.7.0", + "mkdirp": "^0.5.1", + "once": "^1.4.0" }, "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "lodash": "^4.17.14" } }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", "dev": true }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "istanbul-lib-coverage": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", + "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==", "dev": true }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "istanbul-lib-instrument": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", + "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", "dev": true, "requires": { - "lodash._root": "^3.0.0" + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.1", + "semver": "^5.3.0" } }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "istanbul-lib-report": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz", + "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==", "dev": true, "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" + "istanbul-lib-coverage": "^1.2.1", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" } }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "istanbul-lib-source-maps": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz", + "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==", "dev": true, "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.2.1", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" } }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "istanbul-reports": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.1.tgz", + "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==", "dev": true, "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" + "handlebars": "^4.0.3" } }, - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" + "glob": "^7.1.3" } - } - } - }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "dev": true, - "requires": { - "glogg": "^1.0.0" - } - }, - "gzip-size": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", - "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", - "dev": true, - "requires": { - "duplexer": "^0.1.1", - "pify": "^4.0.1" - } - }, - "handlebars": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.3.tgz", - "integrity": "sha512-SRGwSYuNfx8DwHD/6InAPzD6RgeruWLT+B8e8a7gGs8FWgHzlExpTFMEq2IA6QpAfOClpKHy6+8IqTjeBCu6Kg==", - "dev": true, - "requires": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", - "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "has-flag": "^1.0.0" } - }, - "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - } - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-binary2": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", - "dev": true, - "requires": { - "isarray": "2.0.1" - }, - "dependencies": { - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "dev": true } } }, - "has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", - "dev": true - }, - "has-flag": { + "istanbul-lib-coverage": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", - "dev": true, - "requires": { - "sparkles": "^1.0.0" - } - }, - "has-symbol-support-x": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", "dev": true }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" - }, - "has-to-string-tag-x": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", - "dev": true, - "requires": { - "has-symbol-support-x": "^1.4.1" - } - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "istanbul-lib-hook": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz", + "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "append-transform": "^0.4.0" } }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", "dev": true, "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" }, "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hast-util-is-element": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.0.4.tgz", - "integrity": "sha512-NFR6ljJRvDcyPP5SbV7MyPBgF47X3BsskLnmw1U34yL+X6YC0MoBx9EyMg8Jtx4FzGH95jw8+c1VPLHaRA0wDQ==", - "dev": true - }, - "hast-util-sanitize": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/hast-util-sanitize/-/hast-util-sanitize-1.3.1.tgz", - "integrity": "sha512-AIeKHuHx0Wk45nSkGVa2/ujQYTksnDl8gmmKo/mwQi7ag7IBZ8cM3nJ2G86SajbjGP/HRpud6kMkPtcM2i0Tlw==", - "dev": true, - "requires": { - "xtend": "^4.0.1" - } - }, - "hast-util-to-html": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-3.1.0.tgz", - "integrity": "sha1-iCyZhJ5AEw6ZHAQuRW1FPZXDbP8=", + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", "dev": true, "requires": { - "ccount": "^1.0.0", - "comma-separated-tokens": "^1.0.1", - "hast-util-is-element": "^1.0.0", - "hast-util-whitespace": "^1.0.0", - "html-void-elements": "^1.0.0", - "kebab-case": "^1.0.0", - "property-information": "^3.1.0", - "space-separated-tokens": "^1.0.0", - "stringify-entities": "^1.0.1", - "unist-util-is": "^2.0.0", - "xtend": "^4.0.1" + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" }, "dependencies": { - "unist-util-is": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-2.1.3.tgz", - "integrity": "sha512-4WbQX2iwfr/+PfM4U3zd2VNXY+dWtZsN1fLnWEi2QQXA4qyDYAZcDMfXUX0Cu6XZUHHAO9q4nyxxLT4Awk1qUA==", + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, - "hast-util-whitespace": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz", - "integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==", - "dev": true - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "highlight.js": { - "version": "9.18.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.1.tgz", - "integrity": "sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg==", - "dev": true - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "html-escaper": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz", - "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==", - "dev": true - }, - "html-void-elements": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", - "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==", - "dev": true - }, - "http-cache-semantics": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", - "dev": true - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "http-parser-js": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", - "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", - "dev": true - }, - "http-proxy": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", - "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", - "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", "dev": true, "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" } }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, - "humanize-duration": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.15.3.tgz", - "integrity": "sha512-BMz6w8p3NVa6QP9wDtqUkXfwgBqDaZ5z/np0EYdoWrLqL849Onp6JWMXMhbHtuvO9jUThLN5H1ThRQ8dUWnYkA==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "html-escaper": "^2.0.0" } }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "istextorbinary": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz", + "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", "dev": true, "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" + "binaryextensions": "2", + "editions": "^1.3.3", + "textextensions": "2" } }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "dev": true, "requires": { - "repeating": "^2.0.0" + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" } }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "iterate-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", + "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", "dev": true }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true + "jake": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "dev": true, + "requires": { + "async": "0.9.x", + "chalk": "^2.4.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + } }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", + "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" + "import-local": "^2.0.0", + "jest-cli": "^24.9.0" }, "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "jest-cli": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", + "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "@jest/core": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^13.3.0" } }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" } - } - } - }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", - "dev": true - }, - "into-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", - "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", - "dev": true, - "requires": { - "from2": "^2.1.1", - "p-is-promise": "^1.1.0" - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "dev": true, - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } }, - "is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "dev": true - }, - "is-alphanumeric": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz", - "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=", - "dev": true - }, - "is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dev": true, - "requires": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "jest-changed-files": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", "dev": true, "requires": { - "kind-of": "^3.0.2" + "@jest/types": "^24.9.0", + "execa": "^1.0.0", + "throat": "^4.0.0" }, "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" } } } }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" - }, - "is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" }, "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true - } - } - }, - "is-docker": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-1.1.0.tgz", - "integrity": "sha1-8EN01O7lMQ6ajhE78UlUEeRhdqE=", - "dev": true - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } } }, - "is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "dev": true - }, - "is-negated-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "jest-diff": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.1.0.tgz", + "integrity": "sha512-GZpIcom339y0OXznsEKjtkfKxNdg7bVbEofK8Q6MnevTIiR1jNhDWKhRX6X0SDXJlwn3dy59nZ1z55fLkAqPWg==", "dev": true, "requires": { - "kind-of": "^3.0.2" + "chalk": "^4.0.0", + "diff-sequences": "^26.0.0", + "jest-get-type": "^26.0.0", + "pretty-format": "^26.1.0" }, "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" } } } }, - "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", - "dev": true - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "requires": { - "has": "^1.0.3" - } - }, - "is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "dev": true, - "requires": { - "is-unc-path": "^1.0.0" - } - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "dev": true - }, - "is-running": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz", - "integrity": "sha1-MKc/9cw4VOT8JUkICen1q/jeCeA=", - "dev": true - }, - "is-ssh": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.1.tgz", - "integrity": "sha512-0eRIASHZt1E68/ixClI8bp2YK2wmBPVWEismTs6M+M099jKgrzl/3E976zIbImSIob48N2/XGe9y7ZiYdImSlg==", + "jest-docblock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", "dev": true, "requires": { - "protocols": "^1.1.0" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "requires": { - "has-symbols": "^1.0.1" + "detect-newline": "^2.1.0" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "jest-each": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", "dev": true, "requires": { - "unc-path-regex": "^0.1.2" - } - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-valid-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", - "dev": true - }, - "is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + } + } + } }, - "isbinaryfile": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", - "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "jest-environment-jsdom": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", "dev": true, "requires": { - "buffer-alloc": "^1.2.0" + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", + "jsdom": "^11.5.1" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } } }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "jest-environment-node": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } + } }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "jest-get-type": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.0.0.tgz", + "integrity": "sha512-zRc1OAPnnws1EVfykXOj19zo2EMw5Hi6HLbFCSjpuJiXtOWAYIjNsHVSbpQ8bDX7L5BGYGI8m+HmKdjHYFF0kg==", "dev": true }, - "istanbul": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", - "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "jest-haste-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", "dev": true, "requires": { - "abbrev": "1.0.x", - "async": "1.x", - "escodegen": "1.8.x", - "esprima": "2.7.x", - "glob": "^5.0.15", - "handlebars": "^4.0.1", - "js-yaml": "3.x", - "mkdirp": "0.5.x", - "nopt": "3.x", - "once": "1.x", - "resolve": "1.1.x", - "supports-color": "^3.1.0", - "which": "^1.1.1", - "wordwrap": "^1.0.0" + "@jest/types": "^24.9.0", + "anymatch": "^2.0.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.7", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" }, "dependencies": { - "escodegen": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", "dev": true, "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.2.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" } }, - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } }, - "estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", - "dev": true + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } }, - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } }, - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "jest-jasmine2": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.9.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", + "throat": "^4.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", "dev": true, - "optional": true, "requires": { - "amdefine": ">=0.0.4" + "@types/yargs-parser": "*" } }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "has-flag": "^1.0.0" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } - } - } - }, - "istanbul-api": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.7.tgz", - "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==", - "dev": true, - "requires": { - "async": "^2.1.4", - "fileset": "^2.0.2", - "istanbul-lib-coverage": "^1.2.1", - "istanbul-lib-hook": "^1.2.2", - "istanbul-lib-instrument": "^1.10.2", - "istanbul-lib-report": "^1.1.5", - "istanbul-lib-source-maps": "^1.2.6", - "istanbul-reports": "^1.5.1", - "js-yaml": "^3.7.0", - "mkdirp": "^0.5.1", - "once": "^1.4.0" - }, - "dependencies": { - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + }, + "diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true + }, + "expect": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", "dev": true, "requires": { - "lodash": "^4.17.14" + "@jest/types": "^24.9.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" } }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "ms": "^2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "istanbul-lib-coverage": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", - "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==", - "dev": true + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } }, - "istanbul-lib-instrument": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", - "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", + "jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", "dev": true, "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.1", - "semver": "^5.3.0" + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" } }, - "istanbul-lib-report": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz", - "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==", + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "jest-matcher-utils": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", "dev": true, "requires": { - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" } }, - "istanbul-lib-source-maps": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz", - "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==", + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", "dev": true, "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" } }, - "istanbul-reports": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.1.tgz", - "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==", + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", "dev": true, "requires": { - "handlebars": "^4.0.3" + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "has-flag": "^1.0.0" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } } } }, - "istanbul-instrumenter-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz", - "integrity": "sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w==", + "jest-leak-detector": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", "dev": true, "requires": { - "convert-source-map": "^1.5.0", - "istanbul-lib-instrument": "^1.7.3", - "loader-utils": "^1.1.0", - "schema-utils": "^0.3.0" + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" }, "dependencies": { - "istanbul-lib-coverage": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", - "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==", + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "istanbul-lib-instrument": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", - "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", "dev": true, "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.1", - "semver": "^5.3.0" + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" } } } }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz", - "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==", - "dev": true, - "requires": { - "append-transform": "^0.4.0" - } - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "jest-matcher-utils": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.1.0.tgz", + "integrity": "sha512-PW9JtItbYvES/xLn5mYxjMd+Rk+/kIt88EfH3N7w9KeOrHWaHrdYPnVHndGbsFGRJ2d5gKtwggCvkqbFDoouQA==", "dev": true, "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" + "chalk": "^4.0.0", + "jest-diff": "^26.1.0", + "jest-get-type": "^26.0.0", + "pretty-format": "^26.1.0" }, "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } } } }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "jest-message-util": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.1.0.tgz", + "integrity": "sha512-dY0+UlldiAJwNDJ08SF0HdF32g9PkbF2NRK/+2iMPU40O6q+iSn1lgog/u0UH8ksWoPv0+gNq8cjhYO2MFtT0g==", "dev": true, "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.1.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.2" }, "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "dev": true, "requires": { - "ms": "^2.1.1" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "istanbul-reports": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", - "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0" - } - }, - "istextorbinary": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz", - "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", - "dev": true, - "requires": { - "binaryextensions": "2", - "editions": "^1.3.3", - "textextensions": "2" - } - }, - "isurl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", - "dev": true, - "requires": { - "has-to-string-tag-x": "^1.2.0", - "is-object": "^1.0.1" - } - }, - "jest": { + "jest-mock": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", - "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", "dev": true, "requires": { - "import-local": "^2.0.0", - "jest-cli": "^24.9.0" + "@jest/types": "^24.9.0" }, "dependencies": { - "jest-cli": { + "@jest/types": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", - "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", "dev": true, "requires": { - "@jest/core": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "import-local": "^2.0.0", - "is-ci": "^2.0.0", - "jest-config": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "prompts": "^2.0.1", - "realpath-native": "^1.1.0", - "yargs": "^13.3.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" } }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", "dev": true, "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "@types/yargs-parser": "*" } } } }, - "jest-changed-files": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", - "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.0" - } - }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.9.0", - "@jest/types": "^24.9.0", - "babel-jest": "^24.9.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^24.9.0", - "jest-environment-node": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "micromatch": "^3.1.10", - "pretty-format": "^24.9.0", - "realpath-native": "^1.1.0" - } - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true }, - "jest-docblock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", - "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", - "dev": true, - "requires": { - "detect-newline": "^2.1.0" - } + "jest-regex-util": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "dev": true }, - "jest-each": { + "jest-resolve": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", - "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", "dev": true, "requires": { "@jest/types": "^24.9.0", + "browser-resolve": "^1.11.3", "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-environment-jsdom": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", - "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0", - "jsdom": "^11.5.1" - } - }, - "jest-environment-node": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", - "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0" + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } } }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", - "dev": true - }, - "jest-haste-map": { + "jest-resolve-dependencies": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", "dev": true, "requires": { "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.9.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + } } }, - "jest-jasmine2": { + "jest-runner": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", - "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", "dev": true, "requires": { - "@babel/traverse": "^7.1.0", + "@jest/console": "^24.7.1", "@jest/environment": "^24.9.0", "@jest/test-result": "^24.9.0", "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^24.9.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^24.9.0", - "jest-matcher-utils": "^24.9.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", "jest-util": "^24.9.0", - "pretty-format": "^24.9.0", + "jest-worker": "^24.6.0", + "source-map-support": "^0.5.6", "throat": "^4.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } } }, - "jest-leak-detector": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", - "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", - "dev": true, - "requires": { - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-message-util": { + "jest-runtime": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.9.0", "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", + "@types/yargs": "^13.0.0", "chalk": "^2.0.1", - "micromatch": "^3.1.10", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "realpath-native": "^1.1.0", "slash": "^2.0.0", - "stack-utils": "^1.0.1" + "strip-bom": "^3.0.0", + "yargs": "^13.3.0" }, "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + } + }, + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", - "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", - "dev": true - }, - "jest-regex-util": { + "jest-serializer": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", "dev": true }, - "jest-resolve": { + "jest-snapshot": { "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", "dev": true, "requires": { + "@babel/types": "^7.0.0", "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } - }, - "jest-resolve-dependencies": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", - "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.9.0" - } - }, - "jest-runner": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", - "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.4.2", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-docblock": "^24.3.0", - "jest-haste-map": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-leak-detector": "^24.9.0", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", "jest-message-util": "^24.9.0", "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.9.0", + "semver": "^6.2.0" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true + }, + "expect": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "jest-matcher-utils": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + } + }, + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, - "source-map-support": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", - "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - } - } - }, - "jest-runtime": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", - "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/source-map": "^24.3.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "strip-bom": "^3.0.0", - "yargs": "^13.3.0" - }, - "dependencies": { "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } } } }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", - "dev": true - }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "jest-util": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", @@ -10556,6 +14841,35 @@ "source-map": "^0.6.0" }, "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -10582,6 +14896,52 @@ "jest-get-type": "^24.9.0", "leven": "^3.1.0", "pretty-format": "^24.9.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + } + } } }, "jest-watcher": { @@ -10597,6 +14957,34 @@ "chalk": "^2.0.1", "jest-util": "^24.9.0", "string-length": "^2.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/yargs": { + "version": "13.0.9", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", + "integrity": "sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + } } }, "jest-worker": { @@ -10674,6 +15062,17 @@ "whatwg-url": "^6.4.1", "ws": "^5.2.0", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } } }, "jsencrypt": { @@ -10688,9 +15087,9 @@ "dev": true }, "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, "json-loader": { @@ -10712,9 +15111,9 @@ "dev": true }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "json-stable-stringify-without-jsonify": { @@ -10730,19 +15129,23 @@ "dev": true }, "json5": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", "dev": true, "requires": { - "minimist": "^1.2.0" + "minimist": "^1.2.5" } }, "jsonfile": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz", - "integrity": "sha1-6l7+QLg2kLmGZ2FKc5L8YOhCwN0=", - "dev": true + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } }, "jsonparse": { "version": "1.3.1", @@ -10783,130 +15186,49 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/karma/-/karma-4.4.1.tgz", "integrity": "sha512-L5SIaXEYqzrh6b1wqYC42tNsFMx2PWuxky84pK9coK09MvmL7mxii3G3bZBh/0rvD27lqDd0le9jyhzvwif73A==", - "dev": true, - "requires": { - "bluebird": "^3.3.0", - "body-parser": "^1.16.1", - "braces": "^3.0.2", - "chokidar": "^3.0.0", - "colors": "^1.1.0", - "connect": "^3.6.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.0", - "flatted": "^2.0.0", - "glob": "^7.1.1", - "graceful-fs": "^4.1.2", - "http-proxy": "^1.13.0", - "isbinaryfile": "^3.0.0", - "lodash": "^4.17.14", - "log4js": "^4.0.0", - "mime": "^2.3.1", - "minimatch": "^3.0.2", - "optimist": "^0.6.1", - "qjobs": "^1.1.4", - "range-parser": "^1.2.0", - "rimraf": "^2.6.0", - "safe-buffer": "^5.0.1", - "socket.io": "2.1.1", - "source-map": "^0.6.1", - "tmp": "0.0.33", - "useragent": "2.3.0" - }, - "dependencies": { - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", - "dev": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "chokidar": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", - "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", - "dev": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.3.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fsevents": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", - "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", - "dev": true, - "optional": true - }, - "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, + "dev": true, + "requires": { + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "braces": "^3.0.2", + "chokidar": "^3.0.0", + "colors": "^1.1.0", + "connect": "^3.6.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "flatted": "^2.0.0", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.14", + "log4js": "^4.0.0", + "mime": "^2.3.1", + "minimatch": "^3.0.2", + "optimist": "^0.6.1", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", + "socket.io": "2.1.1", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "useragent": "2.3.0" + }, + "dependencies": { "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", "dev": true }, - "readdirp": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", - "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { - "picomatch": "^2.0.7" + "glob": "^7.1.3" } }, "source-map": { @@ -10914,15 +15236,6 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, @@ -10963,21 +15276,102 @@ } }, "karma-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.0.1.tgz", - "integrity": "sha512-SnFkHsnLsaXfxkey51rRN9JDLAEKYW2Lb0qOEvcruukk0NkSNDkjobNDZPt9Ni3kIhLZkLtpGOz661hN7OaZvQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.0.2.tgz", + "integrity": "sha512-zge5qiGEIKDdzWciQwP4p0LSac4k/L6VfrBsERMUn5mpDvxhv1sPVOrSlpzpi70T7NhuEy4bgnpAKIYuumIMCw==", "dev": true, "requires": { - "dateformat": "^1.0.6", - "istanbul": "^0.4.0", - "istanbul-lib-coverage": "^2.0.5", - "istanbul-lib-instrument": "^3.3.0", - "istanbul-lib-report": "^2.0.8", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^2.2.4", - "lodash": "^4.17.11", - "minimatch": "^3.0.0", - "source-map": "^0.5.1" + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.1", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.0", + "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "karma-coverage-istanbul-reporter": { @@ -11006,14 +15400,6 @@ "dev": true, "requires": { "is-wsl": "^2.1.0" - }, - "dependencies": { - "is-wsl": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", - "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==", - "dev": true - } } }, "karma-ie-launcher": { @@ -11059,6 +15445,15 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -11134,6 +15529,26 @@ "requires": { "lodash": "^4.17.14" } + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } } } }, @@ -11144,12 +15559,12 @@ "dev": true }, "keyv": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", - "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.1.tgz", + "integrity": "sha512-xz6Jv6oNkbhrFCvCP7HQa8AaII8y8LRpoSm661NOKLr4uHuBwhX4epXrPQgF3+xdJnN4Esm5X0xwY4bOlALOtw==", "dev": true, "requires": { - "json-buffer": "3.0.0" + "json-buffer": "3.0.1" } }, "kind-of": { @@ -11187,6 +15602,23 @@ "dev": true, "requires": { "readable-stream": "^2.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, "lcid": { @@ -11260,6 +15692,16 @@ "resolve": "^1.1.7" } }, + "lighthouse-logger": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz", + "integrity": "sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "marky": "^1.2.0" + } + }, "listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -11267,15 +15709,14 @@ "dev": true }, "live-connect-js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-1.1.1.tgz", - "integrity": "sha512-PsYiZ6R6ecBQgcg3BWvzGf2TNOqpNFK1lUyfYAUEZ+DPwPciKNRM3CQIDtytVvR9vsH7nhotMaU3bBgb7iuPfQ==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/live-connect-js/-/live-connect-js-1.1.10.tgz", + "integrity": "sha512-G/LJKN3b21DZILCQRyataC/znLvJRyogtu7mAkKlkhP9B9UJ8bcOL7ihW/clD2PsT4hVUkeabHhUGsPCmhsjFw==", "requires": { "@kiosked/ulid": "^3.0.0", - "abab": "^2.0.2", + "abab": "^2.0.3", "browser-cookies": "^1.2.0", - "tiny-hashes": "1.0.1", - "tiny-uuid4": "^1.0.1" + "tiny-hashes": "1.0.1" } }, "livereload-js": { @@ -11285,23 +15726,16 @@ "dev": true }, "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" } }, "loader-runner": { @@ -11311,41 +15745,29 @@ "dev": true }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", "dev": true, "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } + "json5": "^2.1.2" } }, "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "lodash._basecopy": { @@ -11460,15 +15882,23 @@ "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", "dev": true }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, "lodash.defaults": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.4.1.tgz", - "integrity": "sha1-p+iIXwXmiFEUS24SqPNngCa8TFQ=", - "dev": true, - "requires": { - "lodash._objecttypes": "~2.4.1", - "lodash.keys": "~2.4.1" - } + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "dev": true + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "dev": true }, "lodash.escape": { "version": "2.4.1", @@ -11481,6 +15911,18 @@ "lodash.keys": "~2.4.1" } }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -11500,13 +15942,16 @@ "dev": true }, "lodash.isobject": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", - "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", - "dev": true, - "requires": { - "lodash._objecttypes": "~2.4.1" - } + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", + "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "dev": true }, "lodash.keys": { "version": "2.4.1", @@ -11517,8 +15962,31 @@ "lodash._isnative": "~2.4.1", "lodash._shimkeys": "~2.4.1", "lodash.isobject": "~2.4.1" + }, + "dependencies": { + "lodash.isobject": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", + "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", + "dev": true, + "requires": { + "lodash._objecttypes": "~2.4.1" + } + } } }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=", + "dev": true + }, "lodash.restparam": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", @@ -11550,6 +16018,18 @@ "lodash.keys": "~2.4.1", "lodash.templatesettings": "~2.4.1", "lodash.values": "~2.4.1" + }, + "dependencies": { + "lodash.defaults": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.4.1.tgz", + "integrity": "sha1-p+iIXwXmiFEUS24SqPNngCa8TFQ=", + "dev": true, + "requires": { + "lodash._objecttypes": "~2.4.1", + "lodash.keys": "~2.4.1" + } + } } }, "lodash.templatesettings": { @@ -11562,6 +16042,12 @@ "lodash.escape": "~2.4.1" } }, + "lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", + "dev": true + }, "lodash.values": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-2.4.1.tgz", @@ -11571,6 +16057,12 @@ "lodash.keys": "~2.4.1" } }, + "lodash.zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", + "integrity": "sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=", + "dev": true + }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", @@ -11578,12 +16070,12 @@ "dev": true }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "dev": true, "requires": { - "chalk": "^2.0.1" + "chalk": "^2.4.2" } }, "log4js": { @@ -11616,6 +16108,18 @@ } } }, + "loglevel": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.8.tgz", + "integrity": "sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA==", + "dev": true + }, + "loglevel-plugin-prefix": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz", + "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", + "dev": true + }, "loglevelnext": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/loglevelnext/-/loglevelnext-1.0.5.tgz", @@ -11664,9 +16168,9 @@ } }, "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", "dev": true }, "lru-cache": { @@ -11696,6 +16200,14 @@ "requires": { "pify": "^4.0.1", "semver": "^5.6.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } } }, "make-error": { @@ -11744,9 +16256,9 @@ "dev": true }, "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", "dev": true }, "map-visit": { @@ -11770,6 +16282,12 @@ "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", "dev": true }, + "marky": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.1.tgz", + "integrity": "sha512-md9k+Gxa3qLH6sUKpeC2CNkJK/Ld+bEz5X96nYwloqphQE0CKCVEKco/6jxEZixinqNdz5RFi/KaCyfbMDMAXQ==", + "dev": true + }, "matchdep": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", @@ -11782,6 +16300,58 @@ "stack-trace": "0.0.10" }, "dependencies": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, "findup-sync": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", @@ -11794,6 +16364,12 @@ "resolve-dir": "^1.0.1" } }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", @@ -11802,6 +16378,57 @@ "requires": { "is-extglob": "^2.1.0" } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } } } }, @@ -11927,6 +16554,14 @@ "dev": true, "requires": { "mimic-fn": "^1.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + } } }, "memoizee": { @@ -11953,6 +16588,23 @@ "requires": { "errno": "^0.1.3", "readable-stream": "^2.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, "memorystream": { @@ -11979,92 +16631,20 @@ "trim-newlines": "^1.0.0" }, "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", "dev": true }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { - "is-utf8": "^0.2.0" + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" } } } @@ -12074,6 +16654,23 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -12086,24 +16683,13 @@ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "braces": "^3.0.1", + "picomatch": "^2.0.5" } }, "miller-rabin": { @@ -12114,6 +16700,14 @@ "requires": { "bn.js": "^4.0.0", "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, "mime": { @@ -12122,22 +16716,22 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" }, "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", "requires": { - "mime-db": "1.43.0" + "mime-db": "1.44.0" } }, "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, "mimic-response": { @@ -12195,21 +16789,16 @@ } }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true }, "mocha": { "version": "5.2.0", @@ -12230,12 +16819,6 @@ "supports-color": "5.4.0" }, "dependencies": { - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -12265,6 +16848,27 @@ "path-is-absolute": "^1.0.0" } }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", @@ -12331,6 +16935,38 @@ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", "dev": true }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -12339,6 +16975,27 @@ } } }, + "morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dev": true, + "requires": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + } + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -12395,15 +17052,15 @@ "dev": true }, "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", "dev": true, "optional": true }, @@ -12444,9 +17101,9 @@ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, "next-tick": { @@ -12563,6 +17220,21 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } } } }, @@ -12583,25 +17255,22 @@ "semver": "^5.5.0", "shellwords": "^0.1.1", "which": "^1.3.0" - } - }, - "node-releases": { - "version": "1.1.52", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.52.tgz", - "integrity": "sha512-snSiT1UypkgGt2wxPqS6ImEUICbNCMb31yaxWrOLXjhlt2z2/IBpaOxzONExqSm4y5oLnAqjjRWu+wsDzK5yNQ==", - "dev": true, - "requires": { - "semver": "^6.3.0" }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", "dev": true } } }, + "node-releases": { + "version": "1.1.60", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz", + "integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==", + "dev": true + }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -12630,16 +17299,10 @@ "dev": true }, "normalize-url": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", - "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "prepend-http": "^1.0.0", - "query-string": "^4.1.0", - "sort-keys": "^1.0.0" - } + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true }, "now-and-later": { "version": "2.0.1", @@ -12650,12 +17313,6 @@ "once": "^1.3.2" } }, - "npm-install-package": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/npm-install-package/-/npm-install-package-2.1.0.tgz", - "integrity": "sha1-1+/jz816sAYUuJbqUxGdyaslkSU=", - "dev": true - }, "npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", @@ -12671,6 +17328,75 @@ "read-pkg": "^3.0.0", "shell-quote": "^1.6.1", "string.prototype.padend": "^3.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } } }, "npm-run-path": { @@ -12738,6 +17464,12 @@ "is-descriptor": "^0.1.0" } }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -12750,19 +17482,25 @@ } }, "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" }, "object-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", - "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", + "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true }, "object-visit": { "version": "1.0.1", @@ -12777,6 +17515,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, "requires": { "define-properties": "^1.1.2", "function-bind": "^1.1.1", @@ -12876,6 +17615,12 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -12886,12 +17631,12 @@ } }, "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "^2.1.0" } }, "opener": { @@ -12907,6 +17652,14 @@ "dev": true, "requires": { "is-wsl": "^1.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + } } }, "optimist": { @@ -12954,6 +17707,23 @@ "dev": true, "requires": { "readable-stream": "^2.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, "os-browserify": { @@ -13004,6 +17774,12 @@ "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true } } }, @@ -13014,9 +17790,9 @@ "dev": true }, "p-cancelable": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", - "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", + "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==", "dev": true }, "p-each-series": { @@ -13041,21 +17817,21 @@ "dev": true }, "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "^2.2.0" } }, "p-reduce": { @@ -13118,6 +17894,171 @@ "jest": "^24.9.0", "mkdirp": "^0.5.1", "npm-run-all": "^4.1.5" + }, + "dependencies": { + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true + }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "dev": true, + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + }, + "dependencies": { + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", + "dev": true + } + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "got": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.7.0", + "cacheable-request": "^2.1.1", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "into-stream": "^3.1.0", + "is-retry-allowed": "^1.1.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "mimic-response": "^1.0.0", + "p-cancelable": "^0.4.0", + "p-timeout": "^2.0.1", + "pify": "^3.0.0", + "safe-buffer": "^5.1.1", + "timed-out": "^4.0.1", + "url-parse-lax": "^3.0.0", + "url-to-options": "^1.0.1" + } + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dev": true, + "requires": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + } + }, + "p-cancelable": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + } } }, "parse-entities": { @@ -13184,15 +18125,20 @@ } }, "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "error-ex": "^1.2.0" } }, + "parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true + }, "parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", @@ -13225,6 +18171,20 @@ "normalize-url": "^1.9.1", "parse-path": "^3.0.1", "protocols": "^1.4.0" + }, + "dependencies": { + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + } } }, "parse5": { @@ -13275,9 +18235,9 @@ "dev": true }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "path-is-absolute": { @@ -13331,20 +18291,14 @@ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "pathval": { @@ -13363,9 +18317,9 @@ } }, "pbkdf2": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", - "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", "dev": true, "requires": { "create-hash": "^1.1.2", @@ -13381,6 +18335,12 @@ "integrity": "sha1-tuDI+plJTZTgURV1gCpZpcFC8og=", "dev": true }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -13388,21 +18348,21 @@ "dev": true }, "picomatch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", - "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, "pidtree": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", - "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", "dev": true }, "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pinkie": { @@ -13430,12 +18390,12 @@ } }, "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { - "find-up": "^3.0.0" + "find-up": "^4.0.0" } }, "plugin-error": { @@ -13448,6 +18408,17 @@ "arr-diff": "^4.0.0", "arr-union": "^3.1.0", "extend-shallow": "^3.0.2" + }, + "dependencies": { + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "requires": { + "ansi-wrap": "^0.1.0" + } + } } }, "pluralize": { @@ -13487,21 +18458,40 @@ "dev": true }, "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.1.0.tgz", + "integrity": "sha512-GmeO1PEYdM+non4BKCj+XsPJjFOJIPnsLewqhDVoqY1xo0yNmDas7tC2XwpMrRAHR3MaE2hPo37deX5OisJ2Wg==", "dev": true, "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" + "@jest/types": "^26.1.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true } } @@ -13512,6 +18502,15 @@ "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, + "pretty-ms": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.0.tgz", + "integrity": "sha512-J3aPWiC5e9ZeZFuSeBraGxSkGMOvulSWsxDByOcbD1Pr75YL3LSNIKIb52WXbCLE1sS5s4inBBbryjF4Y05Ceg==", + "dev": true, + "requires": { + "parse-ms": "^2.1.0" + } + }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -13536,10 +18535,23 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "promise.allsettled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz", + "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==", + "dev": true, + "requires": { + "array.prototype.map": "^1.0.1", + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "iterate-value": "^1.0.0" + } + }, "prompts": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.1.tgz", - "integrity": "sha512-qIP2lQyCwYbdzcqHIUi2HAxiWixhoM9OdLCWf8txXsapC/X9YdsCoeyRIXE/GP+Q0J37Q7+XN/MFqbUa7IzXNA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz", + "integrity": "sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA==", "dev": true, "requires": { "kleur": "^3.0.3", @@ -13567,6 +18579,12 @@ "ipaddr.js": "1.9.1" } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -13589,9 +18607,9 @@ "dev": true }, "psl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", - "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, "public-encrypt": { @@ -13606,6 +18624,14 @@ "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, "pump": { @@ -13647,6 +18673,58 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "puppeteer-core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-5.2.1.tgz", + "integrity": "sha512-gLjEOrzwgcnwRH+sm4hS1TBqe2/DN248nRb2hYB7+lZ9kCuLuACNvuzlXILlPAznU3Ob+mEvVEBDcLuFa0zq3g==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "devtools-protocol": "0.0.781568", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^4.0.0", + "mime": "^2.0.3", + "pkg-dir": "^4.2.0", + "progress": "^2.0.1", + "proxy-from-env": "^1.0.0", + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -13692,6 +18770,12 @@ "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", "dev": true }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + }, "randomatic": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", @@ -13747,101 +18831,71 @@ } }, "react-is": { - "version": "16.13.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", - "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==", + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "load-json-file": "^4.0.0", + "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "path-type": "^1.0.0" } }, "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" }, "dependencies": { "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "p-try": "^1.0.0" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "p-limit": "^1.1.0" + "pinkie-promise": "^2.0.0" } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true } } }, "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "picomatch": "^2.2.1" } }, "realpath-native": { @@ -13862,6 +18916,15 @@ "resolve": "^1.1.6" } }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, "redent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", @@ -13870,12 +18933,23 @@ "requires": { "indent-string": "^2.1.0", "strip-indent": "^1.0.1" + }, + "dependencies": { + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + } } }, "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", + "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", "dev": true }, "regenerate-unicode-properties": { @@ -13893,13 +18967,12 @@ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, "regenerator-transform": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.3.tgz", - "integrity": "sha512-zXHNKJspmONxBViAb3ZUmFoFPnTBs3zFhCEZJiwp/gkNzxVbTqNJVjYKx6Qk1tQ1P4XLf4TbH9+KBB7wGoAaUw==", + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", "dev": true, "requires": { - "@babel/runtime": "^7.8.4", - "private": "^0.1.8" + "@babel/runtime": "^7.8.4" } }, "regex-cache": { @@ -13925,6 +18998,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1" @@ -13951,9 +19025,9 @@ } }, "regjsgen": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", - "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", "dev": true }, "regjsparser": { @@ -14088,6 +19162,14 @@ "requires": { "is-buffer": "^1.1.5", "is-utf8": "^0.2.1" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } } }, "remove-bom-stream": { @@ -14154,6 +19236,23 @@ "escape-string-regexp": "^1.0.3", "object-assign": "^4.0.1", "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, "request": { @@ -14189,37 +19288,31 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true } } }, - "request-promise": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz", - "integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==", - "dev": true, - "requires": { - "bluebird": "^3.5.0", - "request-promise-core": "1.1.3", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, "request-promise-core": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", - "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", "dev": true, "requires": { - "lodash": "^4.17.15" + "lodash": "^4.17.19" } }, "request-promise-native": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", - "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", "dev": true, "requires": { - "request-promise-core": "1.1.3", + "request-promise-core": "1.1.4", "stealthy-require": "^1.1.1", "tough-cookie": "^2.3.3" } @@ -14261,14 +19354,20 @@ "dev": true }, "resolve": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", - "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", "dev": true, "requires": { "path-parse": "^1.0.6" } }, + "resolve-alpn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.0.0.tgz", + "integrity": "sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA==", + "dev": true + }, "resolve-cwd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", @@ -14318,21 +19417,38 @@ "dev": true }, "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "dev": true, + "requires": { + "lowercase-keys": "^2.0.0" + } + }, + "resq": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/resq/-/resq-1.7.1.tgz", + "integrity": "sha512-09u9Q5SAuJfAW5UoVAmvRtLvCOMaKP+djiixTXsZvPaojGKhuvc0Nfvp84U1rIfopJWEOXi5ywpCFwCk7mj8Xw==", "dev": true, "requires": { - "lowercase-keys": "^1.0.0" + "fast-deep-equal": "^2.0.1" + }, + "dependencies": { + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + } } }, "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "requires": { - "onetime": "^2.0.0", + "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, @@ -14349,9 +19465,9 @@ "dev": true }, "rgb2hex": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.1.10.tgz", - "integrity": "sha512-vKz+kzolWbL3rke/xeTE2+6vHmZnNxGyDnaVW4OckntAIcc7DcZzWkQSfxMDwqHS8vhgySnIFyBUH7lIk6PxvQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.0.tgz", + "integrity": "sha512-cHdNTwmTMPu/TpP1bJfdApd6MbD+Kzi4GNnM6h35mdFChhQPSi9cAI8J7DMn5kQDKX8NuBaQXAyo360Oa7tOEA==", "dev": true }, "right-align": { @@ -14364,12 +19480,12 @@ } }, "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", + "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", "dev": true, "requires": { - "glob": "^7.1.3" + "glob": "^7.0.5" } }, "ripemd160": { @@ -14389,13 +19505,10 @@ "dev": true }, "run-async": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", - "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true }, "rx-lite": { "version": "4.0.8", @@ -14412,6 +19525,15 @@ "rx-lite": "*" } }, + "rxjs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.0.tgz", + "integrity": "sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -14458,6 +19580,136 @@ "micromatch": "^3.1.4", "minimist": "^1.1.1", "walker": "~1.0.5" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } } }, "sax": { @@ -14467,12 +19719,28 @@ "dev": true }, "schema-utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", - "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", "dev": true, "requires": { - "ajv": "^5.0.0" + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + } } }, "semver": { @@ -14517,6 +19785,29 @@ } } }, + "serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "requires": { + "type-fest": "^0.13.1" + }, + "dependencies": { + "type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz", + "integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==", + "dev": true + }, "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", @@ -14635,9 +19926,9 @@ "dev": true }, "shelljs": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", - "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", "dev": true, "requires": { "glob": "^7.0.0", @@ -14651,10 +19942,20 @@ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, + "side-channel": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", + "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", + "dev": true, + "requires": { + "es-abstract": "^1.17.0-next.1", + "object-inspect": "^1.7.0" + } + }, "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, "sinon": { @@ -14681,15 +19982,15 @@ } }, "sisteransi": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.4.tgz", - "integrity": "sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true }, "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "slice-ansi": { @@ -14699,6 +20000,14 @@ "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } } }, "snapdragon": { @@ -14797,6 +20106,12 @@ "kind-of": "^3.2.0" }, "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -14974,9 +20289,9 @@ "dev": true }, "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -14984,15 +20299,15 @@ } }, "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", "dev": true }, "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -15053,10 +20368,21 @@ "dev": true }, "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", - "dev": true + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.2.tgz", + "integrity": "sha512-0H7QK2ECz3fyZMzQ8rH0j2ykpfbnd20BFtfg/SqVC2+sCTtcw0aDTGB7dk+de4U4uUeuz6nOtJcrkFFLG1B0Rg==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } }, "state-toggle": { "version": "1.0.3", @@ -15142,8 +20468,31 @@ "requires": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, + "stream-buffers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", + "integrity": "sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==", + "dev": true + }, "stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", @@ -15161,6 +20510,23 @@ "requires": { "duplexer2": "~0.1.0", "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, "stream-exhaust": { @@ -15180,6 +20546,23 @@ "readable-stream": "^2.3.6", "to-arraybuffer": "^1.0.0", "xtend": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, "stream-shift": { @@ -15244,6 +20627,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true } } }, @@ -15287,31 +20676,14 @@ "dev": true }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" } }, "string.prototype.padend": { @@ -15324,22 +20696,24 @@ "es-abstract": "^1.17.0-next.1" } }, - "string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5" } }, - "string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5" } }, "string_decoder": { @@ -15364,19 +20738,22 @@ } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^5.0.0" } }, "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } }, "strip-bom-string": { "version": "1.0.0", @@ -15400,9 +20777,9 @@ } }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true }, "subarg": { @@ -15414,6 +20791,12 @@ "minimist": "^1.1.0" } }, + "suffix": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", + "integrity": "sha1-zFgjFkag7xEC95R47zqSSP2chC8=", + "dev": true + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -15453,12 +20836,24 @@ "string-width": "^2.1.1" }, "dependencies": { + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -15486,19 +20881,29 @@ "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==", "dev": true }, + "tar-fs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.0.tgz", + "integrity": "sha512-9uW5iDvrIMCVpvasdFHW0wJPez0K4JnMZtsuIeDI7HyMGJNxmDZDOCQROr7lXyS+iL/QMpj07qcjGYTSdRFXUg==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, "tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.3.tgz", + "integrity": "sha512-Z9yri56Dih8IaK8gncVPx4Wqt86NDmQTSh49XLZgjWpGZL9GK9HKParS2scqHCC4w6X9Gh2jwaU45V47XTKwVA==", "dev": true, "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", + "bl": "^4.0.1", + "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" } }, "temp-fs": { @@ -15508,17 +20913,6 @@ "dev": true, "requires": { "rimraf": "~2.5.2" - }, - "dependencies": { - "rimraf": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", - "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", - "dev": true, - "requires": { - "glob": "^7.0.5" - } - } } }, "ternary-stream": { @@ -15541,6 +20935,21 @@ "requires": { "readable-stream": "^2.0.1" } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } } } }, @@ -15556,6 +20965,88 @@ "require-main-filename": "^2.0.0" }, "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, "read-pkg-up": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", @@ -15565,6 +21056,12 @@ "find-up": "^3.0.0", "read-pkg": "^3.0.0" } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true } } }, @@ -15600,6 +21097,23 @@ "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, "through2-filter": { @@ -15679,11 +21193,6 @@ } } }, - "tiny-uuid4": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tiny-uuid4/-/tiny-uuid4-1.0.1.tgz", - "integrity": "sha1-vUTp3V9fvRdo1tH78wIMiGobd2Y=" - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -15721,12 +21230,6 @@ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", "dev": true }, - "to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "dev": true - }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -15742,6 +21245,12 @@ "kind-of": "^3.0.2" }, "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -15766,13 +21275,12 @@ } }, "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" } }, "to-through": { @@ -15856,6 +21364,41 @@ "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", "dev": true }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", @@ -15898,6 +21441,12 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -15934,23 +21483,17 @@ "typescript-compare": "^0.0.2" } }, + "ua-parser-js": { + "version": "0.7.21", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz", + "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==", + "dev": true + }, "uglify-js": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.8.0.tgz", - "integrity": "sha512-ugNSTT8ierCsDHso2jkBHXYrU8Y5/fY2ZUprfrJUiD7YpuFvV4jODLFmb3h4btQjqr5Nh4TX4XtgDfCU1WdioQ==", - "dev": true, - "requires": { - "commander": "~2.20.3", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz", + "integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==", + "dev": true }, "uglify-to-browserify": { "version": "1.0.2", @@ -16023,6 +21566,16 @@ "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", "dev": true }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -16187,9 +21740,9 @@ } }, "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", "dev": true }, "unpipe": { @@ -16259,6 +21812,21 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } } } }, @@ -16389,15 +21957,15 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", + "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==", "dev": true }, "v8flags": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", - "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" @@ -16445,6 +22013,14 @@ "replace-ext": "1.0.0", "unist-util-stringify-position": "^1.0.0", "vfile-message": "^1.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } } }, "vfile-location": { @@ -16475,6 +22051,12 @@ "vfile-statistics": "^1.1.0" }, "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, "has-flag": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", @@ -16501,6 +22083,15 @@ "strip-ansi": "^3.0.0" } }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, "supports-color": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", @@ -16536,6 +22127,14 @@ "cloneable-readable": "^1.0.0", "remove-trailing-separator": "^1.0.1", "replace-ext": "^1.0.0" + }, + "dependencies": { + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + } } }, "vinyl-fs": { @@ -16561,6 +22160,23 @@ "value-or-function": "^3.0.0", "vinyl": "^2.0.0", "vinyl-sourcemap": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } } }, "vinyl-sourcemap": { @@ -16638,117 +22254,321 @@ } }, "watchpack": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", - "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.2.tgz", + "integrity": "sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g==", "dev": true, "requires": { - "chokidar": "^2.0.2", + "chokidar": "^3.4.0", "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.0" } }, - "wdio-browserstack-service": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/wdio-browserstack-service/-/wdio-browserstack-service-0.1.19.tgz", - "integrity": "sha512-ZAq20McWrQy80FQst+4cn1l5WRP9u+9DOKif2TarxYFzw/EmhdNg9TFcXBT5dxH+LcP5v47v7mXMmsO7B3+92Q==", - "dev": true, - "requires": { - "browserstack-local": "^1.3.7", - "request": "^2.81.0", - "request-promise": "^4.2.1" - } - }, - "wdio-concise-reporter": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/wdio-concise-reporter/-/wdio-concise-reporter-0.1.2.tgz", - "integrity": "sha1-+kmA768kszWfHqQz73thYxVDphQ=", - "dev": true - }, - "wdio-dot-reporter": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/wdio-dot-reporter/-/wdio-dot-reporter-0.0.10.tgz", - "integrity": "sha512-A0TCk2JdZEn3M1DSG9YYbNRcGdx/YRw19lTiRpgwzH4qqWkO/oRDZRmi3Snn4L2j54KKTfPalBhlOtc8fojVgg==", - "dev": true - }, - "wdio-mocha-framework": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/wdio-mocha-framework/-/wdio-mocha-framework-0.6.4.tgz", - "integrity": "sha512-GZsXwoW60/fkkfqZJR/ZAdiALaM+hW+BbnTT9x214qPR4Pe5XeyYxhJNEdyf0dNI9625cMdkyZYaWoFHN5zDcA==", + "watchpack-chokidar2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz", + "integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==", "dev": true, + "optional": true, "requires": { - "babel-runtime": "^6.23.0", - "mocha": "^5.2.0", - "wdio-sync": "0.7.3" + "chokidar": "^2.1.8" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "optional": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "optional": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "optional": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true, + "optional": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "optional": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "optional": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } } }, - "wdio-spec-reporter": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/wdio-spec-reporter/-/wdio-spec-reporter-0.1.5.tgz", - "integrity": "sha512-MqvgTow8hFwhFT47q67JwyJyeynKodGRQCxF7ijKPGfsaG1NLssbXYc0JhiL7SiAyxnQxII0UxzTCd3I6sEdkg==", + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", "dev": true, + "optional": true, "requires": { - "babel-runtime": "~6.26.0", - "chalk": "^2.3.0", - "humanize-duration": "~3.15.0" + "defaults": "^1.0.3" } }, - "wdio-sync": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/wdio-sync/-/wdio-sync-0.7.3.tgz", - "integrity": "sha512-ukASSHOQmOxaz5HTILR0jykqlHBtAPsBpMtwhpiG0aW9uc7SO7PF+E5LhVvTG4ypAh+UGmY3rTjohOsqDr39jw==", + "webdriver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-6.3.0.tgz", + "integrity": "sha512-osHp5DX8eQ76Sy6/UYoECmDnUXwLhy5tlBeJh86er7S04FLAlmEqCvYXgxTSb8YtDjh9Xt9gP768RGhxR7ik5A==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "fibers": "^3.0.0", - "object.assign": "^4.0.3" + "@wdio/config": "6.1.14", + "@wdio/logger": "6.0.16", + "@wdio/protocols": "6.3.0", + "@wdio/utils": "6.3.0", + "got": "^11.0.2", + "lodash.merge": "^4.6.1" } }, "webdriverio": { - "version": "4.14.4", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-4.14.4.tgz", - "integrity": "sha512-Knp2vzuzP5c5ybgLu+zTwy/l1Gh0bRP4zAr8NWcrStbuomm9Krn9oRF0rZucT6AyORpXinETzmeowFwIoo7mNA==", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-6.3.4.tgz", + "integrity": "sha512-/53xQEituEFTaJtZMgg5Uz3GXY1Otqyry0LA8dYLYUNkTK0yCa26DL4ycDnWE0i9wEYNFX6YHCgiqTJjHEjKAg==", "dev": true, "requires": { - "archiver": "~2.1.0", - "babel-runtime": "^6.26.0", - "css-parse": "^2.0.0", - "css-value": "~0.0.1", - "deepmerge": "~2.0.1", - "ejs": "~2.5.6", - "gaze": "~1.1.2", - "glob": "~7.1.1", + "@types/puppeteer": "^3.0.1", + "@wdio/config": "6.1.14", + "@wdio/logger": "6.0.16", + "@wdio/repl": "6.3.0", + "@wdio/utils": "6.3.0", + "archiver": "^4.0.1", + "atob": "^2.1.2", + "css-value": "^0.0.1", + "devtools": "6.3.4", + "get-port": "^5.1.1", "grapheme-splitter": "^1.0.2", - "inquirer": "~3.3.0", - "json-stringify-safe": "~5.0.1", - "mkdirp": "~0.5.1", - "npm-install-package": "~2.1.0", - "optimist": "~0.6.1", - "q": "~1.5.0", - "request": "^2.83.0", - "rgb2hex": "^0.1.9", - "safe-buffer": "~5.1.1", - "supports-color": "~5.0.0", - "url": "~0.11.0", - "wdio-dot-reporter": "~0.0.8", - "wgxpath": "~1.0.0" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true - }, - "supports-color": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.0.1.tgz", - "integrity": "sha512-7FQGOlSQ+AQxBNXJpVDj8efTA/FtyB5wcNE1omXXJ0cq6jm1jjDwuROlYDbnzHqdNPqliWFhcioCWSyav+xBnA==", - "dev": true, - "requires": { - "has-flag": "^2.0.0" - } - } + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "minimatch": "^3.0.4", + "puppeteer-core": "^5.1.0", + "resq": "^1.6.0", + "rgb2hex": "^0.2.0", + "serialize-error": "^7.0.0", + "webdriver": "6.3.0" } }, "webidl-conversions": { @@ -16788,9 +22608,9 @@ }, "dependencies": { "ajv": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", - "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -16799,16 +22619,10 @@ "uri-js": "^4.2.2" } }, - "ajv-keywords": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", - "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", - "dev": true - }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "async": { @@ -16850,12 +22664,6 @@ } } }, - "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", - "dev": true - }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -16886,12 +22694,6 @@ "number-is-nan": "^1.0.0" } }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", @@ -16910,6 +22712,28 @@ "strip-bom": "^3.0.0" } }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", @@ -16920,6 +22744,15 @@ "path-exists": "^3.0.0" } }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -16944,14 +22777,11 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, "path-type": { "version": "2.0.0", @@ -16962,12 +22792,6 @@ "pify": "^2.0.0" } }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -17005,6 +22829,12 @@ "strip-ansi": "^4.0.0" }, "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -17022,6 +22852,21 @@ } } }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "supports-color": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", @@ -17093,9 +22938,9 @@ } }, "webpack-bundle-analyzer": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.6.1.tgz", - "integrity": "sha512-Nfd8HDwfSx1xBwC+P8QMGvHAOITxNBSvu/J/mCJvOwv+G4VWkU7zir9SSenTtyCi0LnVtmsc7G5SZo1uV+bxRw==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.8.0.tgz", + "integrity": "sha512-PODQhAYVEourCcOuU+NiYI7WdR8QyELZGgPvB1y2tjbUpbmcQOt5Q7jEK+ttd5se0KSBKD9SXHCEozS++Wllmw==", "dev": true, "requires": { "acorn": "^7.1.1", @@ -17114,15 +22959,21 @@ }, "dependencies": { "acorn": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", - "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", "dev": true }, "acorn-walk": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", - "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, "ejs": { @@ -17131,6 +22982,15 @@ "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", "dev": true }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, "ws": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", @@ -17185,9 +23045,9 @@ }, "dependencies": { "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", "dev": true } } @@ -17202,6 +23062,23 @@ "log-symbols": "^2.1.0", "loglevelnext": "^1.0.1", "uuid": "^3.1.0" + }, + "dependencies": { + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, "webpack-sources": { @@ -17268,12 +23145,24 @@ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", "dev": true }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, "big.js": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", "dev": true }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, "braces": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", @@ -17348,12 +23237,6 @@ "wordwrap": "0.0.2" } }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, "clone-stats": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", @@ -17421,6 +23304,40 @@ "is-extglob": "^1.0.0" } }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, "glob-parent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", @@ -17448,6 +23365,74 @@ "integrity": "sha1-/s16GOfOXKar+5U+H4YhOknxYls=", "dev": true }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", @@ -17463,6 +23448,15 @@ "is-extglob": "^1.0.0" } }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", @@ -17521,6 +23515,15 @@ "regex-cache": "^0.4.2" } }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, "node-libs-browser": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-0.7.0.tgz", @@ -17550,6 +23553,14 @@ "url": "^0.11.0", "util": "^0.10.3", "vm-browserify": "0.0.4" + }, + "dependencies": { + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } } }, "normalize-path": { @@ -17585,6 +23596,230 @@ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, "replace-ext": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", @@ -17603,12 +23838,6 @@ "integrity": "sha1-F93t3F9yL7ZlAWWIlUYZd4ZzFbo=", "dev": true }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", @@ -17624,6 +23853,16 @@ "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=", "dev": true }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, "uglify-js": { "version": "2.7.5", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz", @@ -17736,26 +23975,20 @@ } }, "websocket-driver": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", - "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, "requires": { - "http-parser-js": ">=0.4.0 <0.4.11", + "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "websocket-extensions": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", - "dev": true - }, - "wgxpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wgxpath/-/wgxpath-1.0.0.tgz", - "integrity": "sha1-7vikudVYzEla06mit1FZfs2a9pA=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, "whatwg-encoding": { @@ -17793,12 +24026,93 @@ "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz", + "integrity": "sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ==", + "dev": true, + "requires": { + "is-bigint": "^1.0.0", + "is-boolean-object": "^1.0.0", + "is-number-object": "^1.0.3", + "is-string": "^1.0.4", + "is-symbol": "^1.0.2" + } + }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "which-typed-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.2.tgz", + "integrity": "sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "es-abstract": "^1.17.5", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", @@ -17817,31 +24131,47 @@ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, + "workerpool": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz", + "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==", + "dev": true + }, "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "color-name": "~1.1.4" } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true } } }, @@ -17858,6 +24188,17 @@ "dev": true, "requires": { "mkdirp": "^0.5.1" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + } } }, "write-file-atomic": { @@ -17872,13 +24213,10 @@ } }, "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", + "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==", + "dev": true }, "x-is-string": { "version": "0.1.0", @@ -17923,15 +24261,213 @@ "dev": true }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "yarn-install": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yarn-install/-/yarn-install-1.0.0.tgz", + "integrity": "sha1-V/RQULgu/VcYKzlzxUqgXLXSUjA=", + "dev": true, + "requires": { + "cac": "^3.0.3", + "chalk": "^1.1.3", + "cross-spawn": "^4.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", @@ -17939,15 +24475,14 @@ "dev": true }, "zip-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz", - "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-3.0.1.tgz", + "integrity": "sha512-r+JdDipt93ttDjsOVPU5zaq5bAyY+3H19bDrThkvuVxC0xMQzU1PJcS6D+KrP3u96gH9XLomcHPb+2skoDjulQ==", "dev": true, "requires": { - "archiver-utils": "^1.3.0", - "compress-commons": "^1.2.0", - "lodash": "^4.8.0", - "readable-stream": "^2.0.0" + "archiver-utils": "^2.1.0", + "compress-commons": "^3.0.0", + "readable-stream": "^3.6.0" } } } diff --git a/package.json b/package.json index 464e1515877..35b0f6925e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "3.20.0-pre", + "version": "4.11.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { @@ -26,14 +26,24 @@ "devDependencies": { "@babel/core": "^7.8.4", "@babel/preset-env": "^7.8.4", + "@jsdevtools/coverage-istanbul-loader": "^3.0.3", + "@wdio/browserstack-service": "^6.1.4", + "@wdio/cli": "^6.1.5", + "@wdio/concise-reporter": "^6.1.5", + "@wdio/local-runner": "^6.1.7", + "@wdio/mocha-framework": "^6.1.6", + "@wdio/spec-reporter": "^6.1.5", + "@wdio/sync": "^6.1.5", "ajv": "5.5.2", "babel-loader": "^8.0.5", + "body-parser": "^1.19.0", "chai": "^4.2.0", - "coveralls": "^3.0.2", + "coveralls": "^3.1.0", + "deep-equal": "^2.0.3", "documentation": "^5.2.2", - "es5-shim": "^4.5.2", + "es5-shim": "^4.5.14", "eslint-config-standard": "^10.2.1", - "eslint-plugin-import": "^2.20.1", + "eslint-plugin-import": "^2.20.2", "eslint-plugin-node": "^5.1.0", "eslint-plugin-prebid": "file:./plugins/eslint", "eslint-plugin-promise": "^3.5.0", @@ -57,7 +67,6 @@ "gulp-util": "^3.0.0", "is-docker": "^1.1.0", "istanbul": "^0.4.5", - "istanbul-instrumenter-loader": "^3.0.0", "karma": "^4.0.0", "karma-babel-preprocessor": "^6.0.1", "karma-browserstack-launcher": "1.4.0", @@ -79,34 +88,30 @@ "karma-webpack": "^3.0.5", "lodash": "^4.17.4", "mocha": "^5.0.0", + "morgan": "^1.10.0", "opn": "^5.4.0", "resolve-from": "^5.0.0", "sinon": "^4.1.3", "through2": "^2.0.3", "url-parse": "^1.0.5", - "wdio-browserstack-service": "^0.1.17", - "wdio-concise-reporter": "^0.1.2", - "wdio-mocha-framework": "^0.6.3", - "wdio-spec-reporter": "^0.1.5", - "webdriverio": "^4.13.2", + "webdriverio": "^6.1.5", "webpack": "^3.0.0", - "webpack-bundle-analyzer": "^3.3.2", + "webpack-bundle-analyzer": "^3.8.0", "webpack-stream": "^3.2.0", "yargs": "^1.3.1" }, "dependencies": { "babel-plugin-transform-object-assign": "^6.22.0", "core-js": "^3.0.0", + "core-js-pure": "^3.6.5", "criteo-direct-rsa-validate": "^1.1.0", "crypto-js": "^3.3.0", - "deep-equal": "^1.0.1", "dlv": "1.1.3", "dset": "2.0.1", "express": "^4.15.4", - "fun-hooks": "^0.9.8", + "fun-hooks": "^0.9.9", "jsencrypt": "^3.0.0-rc.1", "just-clone": "^1.0.2", - "live-connect-js": "1.1.1", - "core-js-pure": "^3.6.5" + "live-connect-js": "1.1.10" } } diff --git a/src/AnalyticsAdapter.js b/src/AnalyticsAdapter.js index f3297412a35..80c12a3eb8e 100644 --- a/src/AnalyticsAdapter.js +++ b/src/AnalyticsAdapter.js @@ -18,6 +18,7 @@ const { BIDDER_DONE, SET_TARGETING, AD_RENDER_FAILED, + AUCTION_DEBUG, ADD_AD_UNITS } } = CONSTANTS; @@ -112,6 +113,7 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } [SET_TARGETING]: args => this.enqueue({ eventType: SET_TARGETING, args }), [AUCTION_END]: args => this.enqueue({ eventType: AUCTION_END, args }), [AD_RENDER_FAILED]: args => this.enqueue({ eventType: AD_RENDER_FAILED, args }), + [AUCTION_DEBUG]: args => this.enqueue({ eventType: AUCTION_DEBUG, args }), [ADD_AD_UNITS]: args => this.enqueue({ eventType: ADD_AD_UNITS, args }), [AUCTION_INIT]: args => { args.config = typeof config === 'object' ? config.options || {} : {}; // enableAnaltyics configuration object diff --git a/src/Renderer.js b/src/Renderer.js index b4a912d5714..f073d97d052 100644 --- a/src/Renderer.js +++ b/src/Renderer.js @@ -37,12 +37,21 @@ export function Renderer(options) { this.process(); }); - if (!isRendererDefinedOnAdUnit(adUnitCode)) { - // we expect to load a renderer url once only so cache the request to load script - loadExternalScript(url, moduleCode, this.callback); - } else { - utils.logWarn(`External Js not loaded by Renderer since renderer url and callback is already defined on adUnit ${adUnitCode}`); - } + // use a function, not an arrow, in order to be able to pass "arguments" through + this.render = function () { + if (!isRendererPreferredFromAdUnit(adUnitCode)) { + // we expect to load a renderer url once only so cache the request to load script + loadExternalScript(url, moduleCode, this.callback); + } else { + utils.logWarn(`External Js not loaded by Renderer since renderer url and callback is already defined on adUnit ${adUnitCode}`); + } + + if (this._render) { + this._render.apply(this, arguments) // _render is expected to use push as appropriate + } else { + utils.logWarn(`No render function was provided, please use .setRender on the renderer`); + } + }.bind(this) // bind the function to this object to avoid 'this' errors } Renderer.install = function({ url, config, id, callback, loaded, adUnitCode }) { @@ -54,7 +63,7 @@ Renderer.prototype.getConfig = function() { }; Renderer.prototype.setRender = function(fn) { - this.render = fn; + this._render = fn; }; Renderer.prototype.setEventHandlers = function(handlers) { @@ -101,10 +110,10 @@ export function executeRenderer(renderer, bid) { renderer.render(bid); } -function isRendererDefinedOnAdUnit(adUnitCode) { +function isRendererPreferredFromAdUnit(adUnitCode) { const adUnits = $$PREBID_GLOBAL$$.adUnits; const adUnit = find(adUnits, adUnit => { return adUnit.code === adUnitCode; }); - return !!(adUnit && adUnit.renderer && adUnit.renderer.url && adUnit.renderer.render); + return !!(adUnit && adUnit.renderer && adUnit.renderer.url && adUnit.renderer.render && !(utils.isBoolean(adUnit.renderer.backupOnly) && adUnit.renderer.backupOnly)); } diff --git a/src/adapterManager.js b/src/adapterManager.js index 2108bb7a4f6..5124ae99694 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -426,7 +426,7 @@ adapterManager.registerBidAdapter = function (bidAdaptor, bidderCode, {supported } }; -adapterManager.aliasBidAdapter = function (bidderCode, alias) { +adapterManager.aliasBidAdapter = function (bidderCode, alias, options) { let existingAlias = _bidderRegistry[alias]; if (typeof existingAlias === 'undefined') { @@ -452,7 +452,8 @@ adapterManager.aliasBidAdapter = function (bidderCode, alias) { newAdapter.setBidderCode(alias); } else { let spec = bidAdaptor.getSpec(); - newAdapter = newBidder(Object.assign({}, spec, { code: alias })); + let gvlid = options && options.gvlid; + newAdapter = newBidder(Object.assign({}, spec, { code: alias, gvlid })); _aliasRegistry[alias] = bidderCode; } adapterManager.registerBidAdapter(newAdapter, alias, { @@ -467,11 +468,11 @@ adapterManager.aliasBidAdapter = function (bidderCode, alias) { } }; -adapterManager.registerAnalyticsAdapter = function ({adapter, code}) { +adapterManager.registerAnalyticsAdapter = function ({adapter, code, gvlid}) { if (adapter && code) { if (typeof adapter.enableAnalytics === 'function') { adapter.code = code; - _analyticsRegistry[code] = adapter; + _analyticsRegistry[code] = { adapter, gvlid }; } else { utils.logError(`Prebid Error: Analytics adaptor error for analytics "${code}" analytics adapter must implement an enableAnalytics() function`); @@ -487,7 +488,7 @@ adapterManager.enableAnalytics = function (config) { } utils._each(config, adapterConfig => { - var adapter = _analyticsRegistry[adapterConfig.provider]; + var adapter = _analyticsRegistry[adapterConfig.provider].adapter; if (adapter) { adapter.enableAnalytics(adapterConfig); } else { @@ -495,12 +496,16 @@ adapterManager.enableAnalytics = function (config) { ${adapterConfig.provider}.`); } }); -}; +} adapterManager.getBidAdapter = function(bidder) { return _bidderRegistry[bidder]; }; +adapterManager.getAnalyticsAdapter = function(code) { + return _analyticsRegistry[code]; +} + // the s2sTesting module is injected when it's loaded rather than being imported // importing it causes the packager to include it even when it's not explicitly included in the build export function setS2STestingModule(module) { diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index 42aa91fa74a..3b6260efc88 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -9,7 +9,7 @@ import CONSTANTS from '../constants.json'; import events from '../events.js'; import includes from 'core-js-pure/features/array/includes.js'; import { ajax } from '../ajax.js'; -import { logWarn, logError, parseQueryStringParameters, delayExecution, parseSizesInput, getBidderRequest, flatten, uniques, timestamp, deepAccess, isArray } from '../utils.js'; +import { logWarn, logError, parseQueryStringParameters, delayExecution, parseSizesInput, getBidderRequest, flatten, uniques, timestamp, deepAccess, isArray, isPlainObject } from '../utils.js'; import { ADPOD } from '../mediaTypes.js'; import { getHook, hook } from '../hook.js'; import { getCoreStorageManager } from '../storageManager.js'; @@ -106,7 +106,7 @@ export const storage = getCoreStorageManager('bidderFactory'); * @property {object} [native] Object for storing native creative assets * @property {object} [video] Object for storing video response data * @property {object} [meta] Object for storing bid meta data - * @property {string} [meta.iabSubCatId] The IAB subcategory ID + * @property {string} [meta.primaryCatId] The IAB primary category ID * @property [Renderer] renderer A Renderer which can be used as a default for this bid, * if the publisher doesn't override it. This is only relevant for Outstream Video bids. */ @@ -153,8 +153,14 @@ export function registerBidder(spec) { putBidder(spec); if (Array.isArray(spec.aliases)) { spec.aliases.forEach(alias => { - adapterManager.aliasRegistry[alias] = spec.code; - putBidder(Object.assign({}, spec, { code: alias })); + let aliasCode = alias; + let gvlid; + if (isPlainObject(alias)) { + aliasCode = alias.code; + gvlid = alias.gvlid; + } + adapterManager.aliasRegistry[aliasCode] = spec.code; + putBidder(Object.assign({}, spec, { code: aliasCode, gvlid })); }); } } @@ -307,6 +313,7 @@ export function newBidder(spec) { // creating a copy of original values as cpm and currency are modified later bid.originalCpm = bid.cpm; bid.originalCurrency = bid.currency; + bid.meta = bid.meta || Object.assign({}, bid[bidRequest.bidder]); const prebidBid = Object.assign(createBid(CONSTANTS.STATUS.GOOD, bidRequest), bid); addBidWithCode(bidRequest.adUnitCode, prebidBid); } else { @@ -382,26 +389,31 @@ export function preloadBidderMappingFile(fn, adUnits) { let refreshInDays = (info.refreshInDays) ? info.refreshInDays : DEFAULT_REFRESHIN_DAYS; let key = (info.localStorageKey) ? info.localStorageKey : bidderSpec.getSpec().code; let mappingData = storage.getDataFromLocalStorage(key); - if (!mappingData || timestamp() < mappingData.lastUpdated + refreshInDays * 24 * 60 * 60 * 1000) { - ajax(info.url, - { - success: (response) => { - try { - response = JSON.parse(response); - let mapping = { - lastUpdated: timestamp(), - mapping: response.mapping + try { + mappingData = mappingData ? JSON.parse(mappingData) : undefined; + if (!mappingData || timestamp() > mappingData.lastUpdated + refreshInDays * 24 * 60 * 60 * 1000) { + ajax(info.url, + { + success: (response) => { + try { + response = JSON.parse(response); + let mapping = { + lastUpdated: timestamp(), + mapping: response.mapping + } + storage.setDataInLocalStorage(key, JSON.stringify(mapping)); + } catch (error) { + logError(`Failed to parse ${bidder} bidder translation mapping file`); } - storage.setDataInLocalStorage(key, JSON.stringify(mapping)); - } catch (error) { - logError(`Failed to parse ${bidder} bidder translation mapping file`); + }, + error: () => { + logError(`Failed to load ${bidder} bidder translation file`) } }, - error: () => { - logError(`Failed to load ${bidder} bidder translation file`) - } - }, - ); + ); + } + } catch (error) { + logError(`Failed to parse ${bidder} bidder translation mapping file`); } } }); diff --git a/src/auction.js b/src/auction.js index 6166e59bbf0..5858c3edf78 100644 --- a/src/auction.js +++ b/src/auction.js @@ -57,7 +57,7 @@ * @property {function(): void} callBids - sends requests to all adapters for bids */ -import {flatten, timestamp, adUnitsFilter, deepAccess, getBidRequest, getValue, parseUrl} from './utils.js'; +import {flatten, timestamp, adUnitsFilter, deepAccess, getBidRequest, getValue, parseUrl, isBoolean} from './utils.js'; import { getPriceBucketString } from './cpmBucketManager.js'; import { getNativeTargeting } from './native.js'; import { getCacheUrl, store } from './videoCache.js'; @@ -483,7 +483,7 @@ export const callPrebidCache = hook('async', function(auctionInstance, bidRespon afterBidAdded(); } } - }); + }, bidderRequest); }, 'callPrebidCache'); // Postprocess the bids so that all the universal properties exist, no matter which bidder they came from. @@ -512,7 +512,7 @@ function getPreparedBidForAuction({adUnitCode, bid, bidderRequest, auctionId}) { const bidReq = bidderRequest.bids && find(bidderRequest.bids, bid => bid.adUnitCode == adUnitCode); const adUnitRenderer = bidReq && bidReq.renderer; - if (adUnitRenderer && adUnitRenderer.url) { + if (adUnitRenderer && adUnitRenderer.url && !(adUnitRenderer.backupOnly && isBoolean(adUnitRenderer.backupOnly) && bid.renderer)) { bidObject.renderer = Renderer.install({ url: adUnitRenderer.url }); bidObject.renderer.setRender(adUnitRenderer.render); } diff --git a/src/constants.json b/src/constants.json index 7ffef9db1aa..7c0af445cdb 100644 --- a/src/constants.json +++ b/src/constants.json @@ -36,7 +36,9 @@ "BEFORE_REQUEST_BIDS": "beforeRequestBids", "REQUEST_BIDS": "requestBids", "ADD_AD_UNITS": "addAdUnits", - "AD_RENDER_FAILED" : "adRenderFailed" + "AD_RENDER_FAILED": "adRenderFailed", + "TCF2_ENFORCEMENT": "tcf2Enforcement", + "AUCTION_DEBUG": "auctionDebug" }, "AD_RENDER_FAILED_REASON" : { "PREVENT_WRITING_ON_MAIN_DOCUMENT": "preventWritingOnMainDocuemnt", @@ -97,8 +99,5 @@ "BID_TARGETING_SET": "targetingSet", "RENDERED": "rendered", "BID_REJECTED": "bidRejected" - }, - "SUBMODULES_THAT_ALWAYS_REFRESH_ID": { - "parrableId": true } } diff --git a/src/prebid.js b/src/prebid.js index 1710849ba92..31e0140cfe2 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -1,7 +1,7 @@ /** @module pbjs */ import { getGlobal } from './prebidGlobal.js'; -import { flatten, uniques, isGptPubadsDefined, adUnitsFilter, isArrayOfNums } from './utils.js'; +import { adUnitsFilter, flatten, isArrayOfNums, isGptPubadsDefined, uniques } from './utils.js'; import { listenMessagesFromCreative } from './secureCreatives.js'; import { userSync } from './userSync.js'; import { config } from './config.js'; @@ -11,7 +11,7 @@ import { hook } from './hook.js'; import { sessionLoader } from './debugging.js'; import includes from 'core-js-pure/features/array/includes.js'; import { adunitCounter } from './adUnits.js'; -import { isRendererRequired, executeRenderer } from './Renderer.js'; +import { executeRenderer, isRendererRequired } from './Renderer.js'; import { createBid } from './bidfactory.js'; import { storageCallbacks } from './storageManager.js'; @@ -83,50 +83,58 @@ function validateSizes(sizes, targLength) { } function validateBannerMediaType(adUnit) { - const banner = adUnit.mediaTypes.banner; + const validatedAdUnit = utils.deepClone(adUnit); + const banner = validatedAdUnit.mediaTypes.banner; const bannerSizes = validateSizes(banner.sizes); if (bannerSizes.length > 0) { banner.sizes = bannerSizes; // Deprecation Warning: This property will be deprecated in next release in favor of adUnit.mediaTypes.banner.sizes - adUnit.sizes = bannerSizes; + validatedAdUnit.sizes = bannerSizes; } else { utils.logError('Detected a mediaTypes.banner object without a proper sizes field. Please ensure the sizes are listed like: [[300, 250], ...]. Removing invalid mediaTypes.banner object from request.'); - delete adUnit.mediaTypes.banner + delete validatedAdUnit.mediaTypes.banner } + return validatedAdUnit; } function validateVideoMediaType(adUnit) { - const video = adUnit.mediaTypes.video; - let tarPlayerSizeLen = (typeof video.playerSize[0] === 'number') ? 2 : 1; - - const videoSizes = validateSizes(video.playerSize, tarPlayerSizeLen); - if (videoSizes.length > 0) { - if (tarPlayerSizeLen === 2) { - utils.logInfo('Transforming video.playerSize from [640,480] to [[640,480]] so it\'s in the proper format.'); + const validatedAdUnit = utils.deepClone(adUnit); + const video = validatedAdUnit.mediaTypes.video; + if (video.playerSize) { + let tarPlayerSizeLen = (typeof video.playerSize[0] === 'number') ? 2 : 1; + + const videoSizes = validateSizes(video.playerSize, tarPlayerSizeLen); + if (videoSizes.length > 0) { + if (tarPlayerSizeLen === 2) { + utils.logInfo('Transforming video.playerSize from [640,480] to [[640,480]] so it\'s in the proper format.'); + } + video.playerSize = videoSizes; + // Deprecation Warning: This property will be deprecated in next release in favor of adUnit.mediaTypes.video.playerSize + validatedAdUnit.sizes = videoSizes; + } else { + utils.logError('Detected incorrect configuration of mediaTypes.video.playerSize. Please specify only one set of dimensions in a format like: [[640, 480]]. Removing invalid mediaTypes.video.playerSize property from request.'); + delete validatedAdUnit.mediaTypes.video.playerSize; } - video.playerSize = videoSizes; - // Deprecation Warning: This property will be deprecated in next release in favor of adUnit.mediaTypes.video.playerSize - adUnit.sizes = videoSizes; - } else { - utils.logError('Detected incorrect configuration of mediaTypes.video.playerSize. Please specify only one set of dimensions in a format like: [[640, 480]]. Removing invalid mediaTypes.video.playerSize property from request.'); - delete adUnit.mediaTypes.video.playerSize; } + return validatedAdUnit; } function validateNativeMediaType(adUnit) { - const native = adUnit.mediaTypes.native; + const validatedAdUnit = utils.deepClone(adUnit); + const native = validatedAdUnit.mediaTypes.native; if (native.image && native.image.sizes && !Array.isArray(native.image.sizes)) { utils.logError('Please use an array of sizes for native.image.sizes field. Removing invalid mediaTypes.native.image.sizes property from request.'); - delete adUnit.mediaTypes.native.image.sizes; + delete validatedAdUnit.mediaTypes.native.image.sizes; } if (native.image && native.image.aspect_ratios && !Array.isArray(native.image.aspect_ratios)) { utils.logError('Please use an array of sizes for native.image.aspect_ratios field. Removing invalid mediaTypes.native.image.aspect_ratios property from request.'); - delete adUnit.mediaTypes.native.image.aspect_ratios; + delete validatedAdUnit.mediaTypes.native.image.aspect_ratios; } if (native.icon && native.icon.sizes && !Array.isArray(native.icon.sizes)) { utils.logError('Please use an array of sizes for native.icon.sizes field. Removing invalid mediaTypes.native.icon.sizes property from request.'); - delete adUnit.mediaTypes.native.icon.sizes; + delete validatedAdUnit.mediaTypes.native.icon.sizes; } + return validatedAdUnit; } export const adUnitSetupChecks = { @@ -137,29 +145,34 @@ export const adUnitSetupChecks = { }; export const checkAdUnitSetup = hook('sync', function (adUnits) { - return adUnits.filter(adUnit => { + const validatedAdUnits = []; + + adUnits.forEach(adUnit => { const mediaTypes = adUnit.mediaTypes; + let validatedBanner, validatedVideo, validatedNative; if (!mediaTypes || Object.keys(mediaTypes).length === 0) { utils.logError(`Detected adUnit.code '${adUnit.code}' did not have a 'mediaTypes' object defined. This is a required field for the auction, so this adUnit has been removed.`); - return false; + return; } if (mediaTypes.banner) { - validateBannerMediaType(adUnit); + validatedBanner = validateBannerMediaType(adUnit); } if (mediaTypes.video) { - const video = mediaTypes.video; - if (video.playerSize) { - validateVideoMediaType(adUnit); - } + validatedVideo = validatedBanner ? validateVideoMediaType(validatedBanner) : validateVideoMediaType(adUnit); } if (mediaTypes.native) { - validateNativeMediaType(adUnit); + validatedNative = validatedVideo ? validateNativeMediaType(validatedVideo) : validatedBanner ? validateNativeMediaType(validatedBanner) : validateNativeMediaType(adUnit); } - return true; + + const validatedAdUnit = Object.assign({}, validatedBanner, validatedVideo, validatedNative); + + validatedAdUnits.push(validatedAdUnit); }); + + return validatedAdUnits; }, 'checkAdUnitSetup'); /// /////////////////////////////// @@ -192,7 +205,7 @@ $$PREBID_GLOBAL$$.getAdserverTargetingForAdUnitCodeStr = function (adunitCode) { * @alias module:pbjs.getAdserverTargetingForAdUnitCode * @returns {Object} returnObj return bids */ -$$PREBID_GLOBAL$$.getAdserverTargetingForAdUnitCode = function(adUnitCode) { +$$PREBID_GLOBAL$$.getAdserverTargetingForAdUnitCode = function (adUnitCode) { return $$PREBID_GLOBAL$$.getAdserverTargeting(adUnitCode)[adUnitCode]; }; @@ -300,7 +313,7 @@ $$PREBID_GLOBAL$$.setTargetingForGPTAsync = function (adUnit, customSlotMatching * @param {(string|string[])} adUnitCode adUnitCode or array of adUnitCodes * @alias module:pbjs.setTargetingForAst */ -$$PREBID_GLOBAL$$.setTargetingForAst = function(adUnitCodes) { +$$PREBID_GLOBAL$$.setTargetingForAst = function (adUnitCodes) { utils.logInfo('Invoking $$PREBID_GLOBAL$$.setTargetingForAn', arguments); if (!targeting.isApntagDefined()) { utils.logError('window.apntag is not defined on the page'); @@ -448,6 +461,8 @@ $$PREBID_GLOBAL$$.requestBids = hook('async', function ({ bidsBackHandler, timeo utils.logInfo('Invoking $$PREBID_GLOBAL$$.requestBids', arguments); + adUnits = checkAdUnitSetup(adUnits); + if (adUnitCodes && adUnitCodes.length) { // if specific adUnitCodes supplied filter adUnits for those codes adUnits = adUnits.filter(unit => includes(adUnitCodes, unit.code)); @@ -456,8 +471,6 @@ $$PREBID_GLOBAL$$.requestBids = hook('async', function ({ bidsBackHandler, timeo adUnitCodes = adUnits && adUnits.map(unit => unit.code); } - adUnits = checkAdUnitSetup(adUnits); - /* * for a given adunit which supports a set of mediaTypes * and a given bidder which supports a set of mediaTypes @@ -466,7 +479,7 @@ $$PREBID_GLOBAL$$.requestBids = hook('async', function ({ bidsBackHandler, timeo */ adUnits.forEach(adUnit => { // get the adunit's mediaTypes, defaulting to banner if mediaTypes isn't present - const adUnitMediaTypes = Object.keys(adUnit.mediaTypes || {'banner': 'banner'}); + const adUnitMediaTypes = Object.keys(adUnit.mediaTypes || { 'banner': 'banner' }); // get the bidder's mediaTypes const allBidders = adUnit.bids.map(bid => bid.bidder); @@ -512,7 +525,7 @@ $$PREBID_GLOBAL$$.requestBids = hook('async', function ({ bidsBackHandler, timeo return; } - const auction = auctionManager.createAuction({adUnits, adUnitCodes, callback: bidsBackHandler, cbTimeout, labels, auctionId}); + const auction = auctionManager.createAuction({ adUnits, adUnitCodes, callback: bidsBackHandler, cbTimeout, labels, auctionId }); let adUnitsLen = adUnits.length; if (adUnitsLen > 15) { @@ -523,9 +536,11 @@ $$PREBID_GLOBAL$$.requestBids = hook('async', function ({ bidsBackHandler, timeo auction.callBids(); }); -export function executeStorageCallbacks(fn, reqBidsConfigObj) { +export function executeCallbacks(fn, reqBidsConfigObj) { runAll(storageCallbacks); + runAll(enableAnalyticsCallbacks); fn.call(this, reqBidsConfigObj); + function runAll(queue) { var queued; while ((queued = queue.shift())) { @@ -535,7 +550,7 @@ export function executeStorageCallbacks(fn, reqBidsConfigObj) { } // This hook will execute all storage callbacks which were registered before gdpr enforcement hook was added. Some bidders, user id modules use storage functions when module is parsed but gdpr enforcement hook is not added at that stage as setConfig callbacks are yet to be called. Hence for such calls we execute all the stored callbacks just before requestBids. At this hook point we will know for sure that gdprEnforcement module is added or not -$$PREBID_GLOBAL$$.requestBids.before(executeStorageCallbacks, 49); +$$PREBID_GLOBAL$$.requestBids.before(executeCallbacks, 49); /** * @@ -600,6 +615,16 @@ $$PREBID_GLOBAL$$.offEvent = function (event, handler, id) { events.off(event, handler, id); }; +/** + * Return a copy of all events emitted + * + * @alias module:pbjs.getEvents + */ +$$PREBID_GLOBAL$$.getEvents = function () { + utils.logInfo('Invoking $$PREBID_GLOBAL$$.getEvents'); + return events.getEvents(); +}; + /* * Wrapper to register bidderAdapter externally (adapterManager.registerBidAdapter()) * @param {Function} bidderAdaptor [description] @@ -654,22 +679,30 @@ $$PREBID_GLOBAL$$.createBid = function (statusCode) { * @param {Object} config.options The options for this particular analytics adapter. This will likely vary between adapters. * @alias module:pbjs.enableAnalytics */ -$$PREBID_GLOBAL$$.enableAnalytics = function (config) { + +// Stores 'enableAnalytics' callbacks for later execution. +const enableAnalyticsCallbacks = []; + +const enableAnalyticsCb = hook('async', function (config) { if (config && !utils.isEmpty(config)) { utils.logInfo('Invoking $$PREBID_GLOBAL$$.enableAnalytics for: ', config); adapterManager.enableAnalytics(config); } else { utils.logError('$$PREBID_GLOBAL$$.enableAnalytics should be called with option {}'); } +}, 'enableAnalyticsCb'); + +$$PREBID_GLOBAL$$.enableAnalytics = function (config) { + enableAnalyticsCallbacks.push(enableAnalyticsCb.bind(this, config)); }; /** * @alias module:pbjs.aliasBidder */ -$$PREBID_GLOBAL$$.aliasBidder = function (bidderCode, alias) { +$$PREBID_GLOBAL$$.aliasBidder = function (bidderCode, alias, options) { utils.logInfo('Invoking $$PREBID_GLOBAL$$.aliasBidder', arguments); if (bidderCode && alias) { - adapterManager.aliasBidAdapter(bidderCode, alias); + adapterManager.aliasBidAdapter(bidderCode, alias, options); } else { utils.logError('bidderCode and alias must be passed as arguments', '$$PREBID_GLOBAL$$.aliasBidder'); } @@ -708,12 +741,12 @@ $$PREBID_GLOBAL$$.aliasBidder = function (bidderCode, alias) { * @property {string} adserverTargeting.hb_adid The ad ID of the creative, as understood by the ad server. * @property {string} adserverTargeting.hb_pb The price paid to show the creative, as logged in the ad server. * @property {string} adserverTargeting.hb_bidder The winning bidder whose ad creative will be served by the ad server. -*/ + */ /** * Get all of the bids that have been rendered. Useful for [troubleshooting your integration](http://prebid.org/dev-docs/prebid-troubleshooting-guide.html). * @return {Array} A list of bids that have been rendered. -*/ + */ $$PREBID_GLOBAL$$.getAllWinningBids = function () { return auctionManager.getAllWinningBids(); }; @@ -745,7 +778,7 @@ $$PREBID_GLOBAL$$.getHighestCpmBids = function (adUnitCode) { * @property {string} adId The id representing the ad we want to mark * * @alias module:pbjs.markWinningBidAsUsed -*/ + */ $$PREBID_GLOBAL$$.markWinningBidAsUsed = function (markBidRequest) { let bids = []; @@ -757,7 +790,7 @@ $$PREBID_GLOBAL$$.markWinningBidAsUsed = function (markBidRequest) { } else if (markBidRequest.adId) { bids = auctionManager.getBidsReceived().filter(bid => bid.adId === markBidRequest.adId); } else { - utils.logWarn('Inproper usage of markWinningBidAsUsed. It\'ll need an adUnitCode and/or adId to function.'); + utils.logWarn('Improper use of markWinningBidAsUsed. It needs an adUnitCode or an adId to function.'); } if (bids.length > 0) { @@ -843,7 +876,7 @@ $$PREBID_GLOBAL$$.que.push(() => listenMessagesFromCreative()); * the Prebid script has been fully loaded. * @alias module:pbjs.cmd.push */ -$$PREBID_GLOBAL$$.cmd.push = function(command) { +$$PREBID_GLOBAL$$.cmd.push = function (command) { if (typeof command === 'function') { try { command.call(); @@ -858,7 +891,7 @@ $$PREBID_GLOBAL$$.cmd.push = function(command) { $$PREBID_GLOBAL$$.que.push = $$PREBID_GLOBAL$$.cmd.push; function processQueue(queue) { - queue.forEach(function(cmd) { + queue.forEach(function (cmd) { if (typeof cmd.called === 'undefined') { try { cmd.call(); @@ -873,7 +906,7 @@ function processQueue(queue) { /** * @alias module:pbjs.processQueue */ -$$PREBID_GLOBAL$$.processQueue = function() { +$$PREBID_GLOBAL$$.processQueue = function () { hook.ready(); processQueue($$PREBID_GLOBAL$$.que); processQueue($$PREBID_GLOBAL$$.cmd); diff --git a/src/refererDetection.js b/src/refererDetection.js index 60198678666..da68313736b 100644 --- a/src/refererDetection.js +++ b/src/refererDetection.js @@ -10,153 +10,48 @@ import { logWarn } from './utils.js'; +/** + * @param {Window} win Window + * @returns {Function} + */ export function detectReferer(win) { - /** - * Returns number of frames to reach top from current frame where prebid.js sits - * @returns {Array} levels - */ - function getLevels() { - let levels = walkUpWindows(); - let ancestors = getAncestorOrigins(); - - if (ancestors) { - for (let i = 0, l = ancestors.length; i < l; i++) { - levels[i].ancestor = ancestors[i]; - } - } - return levels; - } - /** * This function would return a read-only array of hostnames for all the parent frames. * win.location.ancestorOrigins is only supported in webkit browsers. For non-webkit browsers it will return undefined. + * + * @param {Window} win Window object * @returns {(undefined|Array)} Ancestor origins or undefined */ - function getAncestorOrigins() { + function getAncestorOrigins(win) { try { if (!win.location.ancestorOrigins) { return; } + return win.location.ancestorOrigins; } catch (e) { // Ignore error } } - /** - * This function would try to get referer and urls for all parent frames in case of win.location.ancestorOrigins undefined. - * @param {Array} levels - * @returns {Object} urls for all parent frames and top most detected referer url - */ - function getPubUrlStack(levels) { - let stack = []; - let defUrl = null; - let frameLocation = null; - let prevFrame = null; - let prevRef = null; - let ancestor = null; - let detectedRefererUrl = null; - - let i; - for (i = levels.length - 1; i >= 0; i--) { - try { - frameLocation = levels[i].location; - } catch (e) { - // Ignore error - } - - if (frameLocation) { - stack.push(frameLocation); - if (!detectedRefererUrl) { - detectedRefererUrl = frameLocation; - } - } else if (i !== 0) { - prevFrame = levels[i - 1]; - try { - prevRef = prevFrame.referrer; - ancestor = prevFrame.ancestor; - } catch (e) { - // Ignore error - } - - if (prevRef) { - stack.push(prevRef); - if (!detectedRefererUrl) { - detectedRefererUrl = prevRef; - } - } else if (ancestor) { - stack.push(ancestor); - if (!detectedRefererUrl) { - detectedRefererUrl = ancestor; - } - } else { - stack.push(defUrl); - } - } else { - stack.push(defUrl); - } - } - return { - stack, - detectedRefererUrl - }; - } - /** * This function returns canonical URL which refers to an HTML link element, with the attribute of rel="canonical", found in the element of your webpage + * * @param {Object} doc document + * @returns {string|null} */ function getCanonicalUrl(doc) { try { - let element = doc.querySelector("link[rel='canonical']"); + const element = doc.querySelector("link[rel='canonical']"); + if (element !== null) { return element.href; } } catch (e) { + // Ignore error } - return null; - } - /** - * Walk up to the top of the window to detect origin, number of iframes, ancestor origins and canonical url - */ - function walkUpWindows() { - let acc = []; - let currentWindow; - do { - try { - currentWindow = currentWindow ? currentWindow.parent : win; - try { - let isTop = (currentWindow == win.top); - let refData = { - referrer: currentWindow.document.referrer || null, - location: currentWindow.location.href || null, - isTop - } - if (isTop) { - refData = Object.assign(refData, { - canonicalUrl: getCanonicalUrl(currentWindow.document) - }) - } - acc.push(refData); - } catch (e) { - acc.push({ - referrer: null, - location: null, - isTop: (currentWindow == win.top) - }); - logWarn('Trying to access cross domain iframe. Continuing without referrer and location'); - } - } catch (e) { - acc.push({ - referrer: null, - location: null, - isTop: false - }); - return acc; - } - } while (currentWindow != win.top); - return acc; + return null; } /** @@ -170,31 +65,114 @@ export function detectReferer(win) { */ /** - * Get referer info + * Walk up the windows to get the origin stack and best available referrer, canonical URL, etc. + * * @returns {refererInfo} */ function refererInfo() { - try { - let levels = getLevels(); - let numIframes = levels.length - 1; - let reachedTop = (levels[numIframes].location !== null || - (numIframes > 0 && levels[numIframes - 1].referrer !== null)); - let stackInfo = getPubUrlStack(levels); - let canonicalUrl; - if (levels[levels.length - 1].canonicalUrl) { - canonicalUrl = levels[levels.length - 1].canonicalUrl; + const stack = []; + const ancestors = getAncestorOrigins(win); + let currentWindow; + let bestReferrer; + let bestCanonicalUrl; + let reachedTop = false; + let level = 0; + let valuesFromAmp = false; + let inAmpFrame = false; + + do { + const previousWindow = currentWindow; + const wasInAmpFrame = inAmpFrame; + let currentLocation; + let crossOrigin = false; + let foundReferrer = null; + + inAmpFrame = false; + currentWindow = currentWindow ? currentWindow.parent : win; + + try { + currentLocation = currentWindow.location.href || null; + } catch (e) { + crossOrigin = true; } - return { - referer: stackInfo.detectedRefererUrl, - reachedTop, - numIframes, - stack: stackInfo.stack, - canonicalUrl - }; - } catch (e) { - // Ignore error - } + if (crossOrigin) { + if (wasInAmpFrame) { + const context = previousWindow.context; + + try { + foundReferrer = context.sourceUrl; + bestReferrer = foundReferrer; + + valuesFromAmp = true; + + if (currentWindow === win.top) { + reachedTop = true; + } + + if (context.canonicalUrl) { + bestCanonicalUrl = context.canonicalUrl; + } + } catch (e) { /* Do nothing */ } + } else { + logWarn('Trying to access cross domain iframe. Continuing without referrer and location'); + + try { + const referrer = previousWindow.document.referrer; + + if (referrer) { + foundReferrer = referrer; + + if (currentWindow === win.top) { + reachedTop = true; + } + } + } catch (e) { /* Do nothing */ } + + if (!foundReferrer && ancestors && ancestors[level - 1]) { + foundReferrer = ancestors[level - 1]; + } + + if (foundReferrer && !valuesFromAmp) { + bestReferrer = foundReferrer; + } + } + } else { + if (currentLocation) { + foundReferrer = currentLocation; + bestReferrer = foundReferrer; + valuesFromAmp = false; + + if (currentWindow === win.top) { + reachedTop = true; + + const canonicalUrl = getCanonicalUrl(currentWindow.document); + + if (canonicalUrl) { + bestCanonicalUrl = canonicalUrl; + } + } + } + + if (currentWindow.context && currentWindow.context.sourceUrl) { + inAmpFrame = true; + } + } + + stack.push(foundReferrer); + level++; + } while (currentWindow !== win.top); + + stack.reverse(); + + return { + referer: bestReferrer || null, + reachedTop, + isAmp: valuesFromAmp, + numIframes: level - 1, + stack, + canonicalUrl: bestCanonicalUrl || null + }; } return refererInfo; diff --git a/src/secureCreatives.js b/src/secureCreatives.js index 060a30b0a98..34de2be275c 100644 --- a/src/secureCreatives.js +++ b/src/secureCreatives.js @@ -33,7 +33,7 @@ function receiveMessage(ev) { }); if (adObject && data.message === 'Prebid Request') { - _sendAdToCreative(adObject, data.adServerDomain, ev.source); + _sendAdToCreative(adObject, ev); // save winning bids auctionManager.addWinningBid(adObject); @@ -62,21 +62,21 @@ function receiveMessage(ev) { } } -export function _sendAdToCreative(adObject, remoteDomain, source) { +export function _sendAdToCreative(adObject, ev) { const { adId, ad, adUrl, width, height, renderer, cpm } = adObject; // rendering for outstream safeframe if (isRendererRequired(renderer)) { executeRenderer(renderer, adObject); } else if (adId) { resizeRemoteCreative(adObject); - source.postMessage(JSON.stringify({ + ev.source.postMessage(JSON.stringify({ message: 'Prebid Response', ad: replaceAuctionPrice(ad, cpm), adUrl: replaceAuctionPrice(adUrl, cpm), adId, width, height - }), remoteDomain); + }), ev.origin); } } diff --git a/src/storageManager.js b/src/storageManager.js index 0d88a8ccea1..60e5a7706d0 100644 --- a/src/storageManager.js +++ b/src/storageManager.js @@ -154,7 +154,7 @@ export function newStorageManager({gvlid, moduleName, moduleType} = {}) { */ const setDataInLocalStorage = function (key, value, done) { let cb = function (result) { - if (result && result.valid) { + if (result && result.valid && hasLocalStorage()) { window.localStorage.setItem(key, value); } } @@ -174,7 +174,7 @@ export function newStorageManager({gvlid, moduleName, moduleType} = {}) { */ const getDataFromLocalStorage = function (key, done) { let cb = function (result) { - if (result && result.valid) { + if (result && result.valid && hasLocalStorage()) { return window.localStorage.getItem(key); } return null; @@ -194,7 +194,7 @@ export function newStorageManager({gvlid, moduleName, moduleType} = {}) { */ const removeDataFromLocalStorage = function (key, done) { let cb = function (result) { - if (result && result.valid) { + if (result && result.valid && hasLocalStorage()) { window.localStorage.removeItem(key); } } diff --git a/src/targeting.js b/src/targeting.js index 45c098554a5..8176bc9caff 100644 --- a/src/targeting.js +++ b/src/targeting.js @@ -44,7 +44,7 @@ export function getHighestCpmBidsFromBidPool(bidsReceived, highestCpmCallback, a Object.keys(bidsByBidder).forEach(key => bucketBids.push(bidsByBidder[key].reduce(highestCpmCallback))); // if adUnitBidLimit is set, pass top N number bids if (adUnitBidLimit > 0) { - bucketBids = dealPrioritization ? bucketBids(sortByDealAndPriceBucketOrCpm(true)) : bucketBids.sort((a, b) => b.cpm - a.cpm); + bucketBids = dealPrioritization ? bucketBids.sort(sortByDealAndPriceBucketOrCpm(true)) : bucketBids.sort((a, b) => b.cpm - a.cpm); bids.push(...bucketBids.slice(0, adUnitBidLimit)); } else { bids.push(...bucketBids); @@ -76,11 +76,11 @@ export function getHighestCpmBidsFromBidPool(bidsReceived, highestCpmCallback, a */ export function sortByDealAndPriceBucketOrCpm(useCpm = false) { return function(a, b) { - if (a.adUnitTargeting.hb_deal !== undefined && b.adUnitTargeting.hb_deal === undefined) { + if (a.adserverTargeting.hb_deal !== undefined && b.adserverTargeting.hb_deal === undefined) { return -1; } - if ((a.adUnitTargeting.hb_deal === undefined && b.adUnitTargeting.hb_deal !== undefined)) { + if ((a.adserverTargeting.hb_deal === undefined && b.adserverTargeting.hb_deal !== undefined)) { return 1; } @@ -89,7 +89,7 @@ export function sortByDealAndPriceBucketOrCpm(useCpm = false) { return b.cpm - a.cpm; } - return b.adUnitTargeting.hb_pb - a.adUnitTargeting.hb_pb; + return b.adserverTargeting.hb_pb - a.adserverTargeting.hb_pb; } } @@ -181,6 +181,48 @@ export function newTargeting(auctionManager) { return []; }; + /** + * Returns filtered ad server targeting for custom and allowed keys. + * @param {targetingArray} targeting + * @param {string[]} allowedKeys + * @return {targetingArray} filtered targeting + */ + function getAllowedTargetingKeyValues(targeting, allowedKeys) { + const defaultKeyring = Object.assign({}, CONSTANTS.TARGETING_KEYS, CONSTANTS.NATIVE_KEYS); + const defaultKeys = Object.keys(defaultKeyring); + const keyDispositions = {}; + logInfo(`allowTargetingKeys - allowed keys [ ${allowedKeys.map(k => defaultKeyring[k]).join(', ')} ]`); + targeting.map(adUnit => { + const adUnitCode = Object.keys(adUnit)[0]; + const keyring = adUnit[adUnitCode]; + const keys = keyring.filter(kvPair => { + const key = Object.keys(kvPair)[0]; + // check if key is in default keys, if not, it's custom, we won't remove it. + const isCustom = defaultKeys.filter(defaultKey => key.indexOf(defaultKeyring[defaultKey]) === 0).length === 0; + // check if key explicitly allowed, if not, we'll remove it. + const found = isCustom || allowedKeys.find(allowedKey => { + const allowedKeyName = defaultKeyring[allowedKey]; + // we're looking to see if the key exactly starts with one of our default keys. + // (which hopefully means it's not custom) + const found = key.indexOf(allowedKeyName) === 0; + return found; + }); + keyDispositions[key] = !found; + return found; + }); + adUnit[adUnitCode] = keys; + }); + const removedKeys = Object.keys(keyDispositions).filter(d => keyDispositions[d]); + logInfo(`allowTargetingKeys - removed keys [ ${removedKeys.join(', ')} ]`); + // remove any empty targeting objects, as they're unnecessary. + const filteredTargeting = targeting.filter(adUnit => { + const adUnitCode = Object.keys(adUnit)[0]; + const keyring = adUnit[adUnitCode]; + return keyring.length > 0; + }); + return filteredTargeting + } + /** * Returns all ad server targeting for all ad units. * @param {string=} adUnitCode @@ -206,6 +248,11 @@ export function newTargeting(auctionManager) { }); }); + const allowedKeys = config.getConfig('targetingControls.allowTargetingKeys'); + if (Array.isArray(allowedKeys) && allowedKeys.length > 0) { + targeting = getAllowedTargetingKeyValues(targeting, allowedKeys); + } + targeting = flattenTargeting(targeting); const auctionKeysThreshold = config.getConfig('targetingControls.auctionKeyMaxChars'); @@ -240,13 +287,13 @@ export function newTargeting(auctionManager) { let targetingMap = Object.keys(targetingCopy).map(adUnitCode => { return { adUnitCode, - adUnitTargeting: targetingCopy[adUnitCode] + adserverTargeting: targetingCopy[adUnitCode] }; }).sort(sortByDealAndPriceBucketOrCpm()); // iterate through the targeting based on above list and transform the keys into the query-equivalent and count characters return targetingMap.reduce(function (accMap, currMap, index, arr) { - let adUnitQueryString = convertKeysToQueryForm(currMap.adUnitTargeting); + let adUnitQueryString = convertKeysToQueryForm(currMap.adserverTargeting); // for the last adUnit - trim last encoded ampersand from the converted query string if ((index + 1) === arr.length) { @@ -325,7 +372,10 @@ export function newTargeting(auctionManager) { Object.keys(targetingConfig).filter(customSlotMatching ? customSlotMatching(slot) : isAdUnitCodeMatchingSlot(slot)) .forEach(targetId => Object.keys(targetingConfig[targetId]).forEach(key => { - let valueArr = targetingConfig[targetId][key].split(','); + let valueArr = targetingConfig[targetId][key]; + if (typeof valueArr === 'string') { + valueArr = valueArr.split(','); + } valueArr = (valueArr.length > 1) ? [valueArr] : valueArr; valueArr.map((value) => { utils.logMessage(`Attempting to set key value for slot: ${slot.getSlotElementId()} key: ${key} value: ${value}`); diff --git a/src/utils.js b/src/utils.js index 88328ff10aa..9426308daf4 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,7 +1,6 @@ /* eslint-disable no-console */ import { config } from './config.js'; import clone from 'just-clone'; -import deepequal from 'deep-equal'; import find from 'core-js-pure/features/array/find.js'; import includes from 'core-js-pure/features/array/includes.js'; @@ -22,6 +21,7 @@ let consoleLogExists = Boolean(consoleExists && window.console.log); let consoleInfoExists = Boolean(consoleExists && window.console.info); let consoleWarnExists = Boolean(consoleExists && window.console.warn); let consoleErrorExists = Boolean(consoleExists && window.console.error); +var events = require('./events.js'); // this allows stubbing of utility functions that are used internally by other utility functions export const internal = { @@ -262,6 +262,7 @@ export function logError() { if (debugTurnedOn() && consoleErrorExists) { console.error.apply(console, decorateLog(arguments, 'ERROR:')); } + events.emit(CONSTANTS.EVENTS.AUCTION_DEBUG, {type: 'ERROR', arguments: arguments}); } function decorateLog(args, prefix) { @@ -1169,13 +1170,28 @@ export function buildUrl(obj) { } /** - * This function compares two objects for checking their equivalence. + * This function deeply compares two objects checking for their equivalence. * @param {Object} obj1 * @param {Object} obj2 * @returns {boolean} */ export function deepEqual(obj1, obj2) { - return deepequal(obj1, obj2); + if (obj1 === obj2) return true; + else if ((typeof obj1 === 'object' && obj1 !== null) && (typeof obj2 === 'object' && obj2 !== null)) { + if (Object.keys(obj1).length !== Object.keys(obj2).length) return false; + for (let prop in obj1) { + if (obj2.hasOwnProperty(prop)) { + if (!deepEqual(obj1[prop], obj2[prop])) { + return false; + } + } else { + return false; + } + } + return true; + } else { + return false; + } } export function mergeDeep(target, ...sources) { @@ -1201,3 +1217,43 @@ export function mergeDeep(target, ...sources) { return mergeDeep(target, ...sources); } + +/** + * returns a hash of a string using a fast algorithm + * source: https://stackoverflow.com/a/52171480/845390 + * @param str + * @param seed (optional) + * @returns {string} + */ +export function cyrb53Hash(str, seed = 0) { + // IE doesn't support imul + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul#Polyfill + let imul = function(opA, opB) { + if (isFn(Math.imul)) { + return Math.imul(opA, opB); + } else { + opB |= 0; // ensure that opB is an integer. opA will automatically be coerced. + // floating points give us 53 bits of precision to work with plus 1 sign bit + // automatically handled for our convienence: + // 1. 0x003fffff /*opA & 0x000fffff*/ * 0x7fffffff /*opB*/ = 0x1fffff7fc00001 + // 0x1fffff7fc00001 < Number.MAX_SAFE_INTEGER /*0x1fffffffffffff*/ + var result = (opA & 0x003fffff) * opB; + // 2. We can remove an integer coersion from the statement above because: + // 0x1fffff7fc00001 + 0xffc00000 = 0x1fffffff800001 + // 0x1fffffff800001 < Number.MAX_SAFE_INTEGER /*0x1fffffffffffff*/ + if (opA & 0xffc00000) result += (opA & 0xffc00000) * opB | 0; + return result | 0; + } + }; + + let h1 = 0xdeadbeef ^ seed; + let h2 = 0x41c6ce57 ^ seed; + for (let i = 0, ch; i < str.length; i++) { + ch = str.charCodeAt(i); + h1 = imul(h1 ^ ch, 2654435761); + h2 = imul(h2 ^ ch, 1597334677); + } + h1 = imul(h1 ^ (h1 >>> 16), 2246822507) ^ imul(h2 ^ (h2 >>> 13), 3266489909); + h2 = imul(h2 ^ (h2 >>> 16), 2246822507) ^ imul(h1 ^ (h1 >>> 13), 3266489909); + return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(); +} diff --git a/src/videoCache.js b/src/videoCache.js index 46bf74ee553..9f1fd7e4117 100644 --- a/src/videoCache.js +++ b/src/videoCache.js @@ -10,7 +10,8 @@ */ import { ajax } from './ajax.js'; -import { config } from '../src/config.js'; +import { config } from './config.js'; +import * as utils from './utils.js'; /** * @typedef {object} CacheableUrlBid @@ -70,6 +71,10 @@ function toStorageRequest(bid) { 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 !== '') { @@ -126,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/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/video/adUnit.json b/test/fixtures/video/adUnit.json index df55eb25d79..0773d7f3a62 100644 --- a/test/fixtures/video/adUnit.json +++ b/test/fixtures/video/adUnit.json @@ -1,7 +1,11 @@ { "code": "video1", - "sizes": [640,480], - "mediaType": "video", + "mediaTypes": { + "video": { + "context": "instream", + "playerSize": [640, 480] + } + }, "bids": [ { "bidder": "appnexus", 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/mock-server/expectations/request-response-pairs/banner/index.js b/test/mock-server/expectations/request-response-pairs/banner/index.js deleted file mode 100644 index b34af63cc45..00000000000 --- a/test/mock-server/expectations/request-response-pairs/banner/index.js +++ /dev/null @@ -1,97 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - * The expecation created here is replicating trafficSourceCode example in Prebid. - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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 - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - 'httpResponse': { - 'body': { - 'version': '3.0.0', - 'tags': [{ - 'uuid': '2c8c83a1deaf1a', - '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.500000, - 'cpm_publisher_currency': 0.500000, - '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': {} - }] - } - }] - }] - }, - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/currency/index.js b/test/mock-server/expectations/request-response-pairs/currency/index.js deleted file mode 100644 index d9bdc5af737..00000000000 --- a/test/mock-server/expectations/request-response-pairs/currency/index.js +++ /dev/null @@ -1,177 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - 'httpResponse': { - 'body': { - 'version': '3.0.0', - 'tags': [{ - 'uuid': '232f6ceccb3749', - '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.500000, - 'cpm_publisher_currency': 0.500000, - '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': {} - }] - } - }] - }, { - 'uuid': '3867e6fdb23eb6', - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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 - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/gdpr/index.js b/test/mock-server/expectations/request-response-pairs/gdpr/index.js deleted file mode 100644 index aa815820873..00000000000 --- a/test/mock-server/expectations/request-response-pairs/gdpr/index.js +++ /dev/null @@ -1,95 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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 - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - 'httpResponse': { - 'body': { - 'version': '3.0.0', - 'tags': [{ - 'uuid': '27c4cea6dfcad4', - 'tag_id': 13144370, - 'auction_id': '6784868202366971885', - 'nobid': false, - 'no_ad_url': 'http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fgdpr_hello_world.html%3Fpbjs_debug%3Dtrue&e=wqT_3QL0CWz0BAAAAwDWAAUBCKKt0fAFEO3ftM_qtayUXhj_EQEQASo2CQANAQARDQgoABkAAACA61HgPyEREgApEQkAMREb8GkwsqKiBjjtSEDtSEgAUABYnPFbYABotc95eACAAQGKAQCSAQNVU0SYAawCoAH6AagBAbABALgBAcABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3ODM5MTIwMik7AR0scicsIDk2ODQ2MDM1Nh4A9A4BkgLJAiF0ajlmS2dpdXNLNEtFTk9CbHk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRc3FLaUJsZ0FZUF9fX184UGFBQndBWGdCZ0FFQmlBRUJrQUVCbUFFQm9BRUJxQUVEc0FFQXVRRXBpNGlEQUFEZ1A4RUJLWXVJZ3dBQTREX0pBZWxBS28zZEV1OF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBTUFDQWNnQ0FkQUNBZGdDQWVBQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEcnJDdUNyb0RDVk5KVGpNNk5EY3pPZUFEX0JpSUJBQ1FCQUNZQkFIQkJBQUFBQQmDCHlRUQkJAQEYTmdFQVBFRQELCQEwRDRCQUNJQllNbHFRVQkTREFEd1B3Li6aAokBIWZnOFhHUTZNASRuUEZiSUFRb0FEEUhYRGdQem9KVTBsT016bzBOek01UVB3WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8EBlQUEuwgIvaHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3MvZ2V0dGluZy1zdGFydGVkLmh0bWzYAgDgAq2YSOoCWA068IF0ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvZ3B0L2dkcHJfaGVsbG9fd29ybGQuaHRtbD9wYmpzX2RlYnVnPXRydWWAAwGIAwGQAwCYAxegAwGqAwDAA6wCyAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzDb3wW5gEAKIECzEwLjc1Ljc0LjY5qAS_NrIEEggEEAQYrAIg-gEoASgCMAA4ArgEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM52gQCCADgBAHwBNOBly6IBQGYBQCgBf__bcwUAcAFAMkFaakU8D_SBQkJCQyIAADYBQHgBQHwBQH6BQQIABAAkAYAmAYAsgaWAUJPc3kwUXkBBixYaUFBQUJBRU5DMi0hswh0RjdhJQxfX185AQXwcV9fOXV6X092X3ZfZl9fMzNlOF9fOXZfbF83Xy1fX191Xy0zM2Q0dV8xdmY5OXlmbTEtN2V0cjN0cF84N3VlczJfWHVyX183OV9fM3ozXzlweFA3OGs4OXI3MzM3RXdfdi1fdi1iN0pDT05fQbgGAcEGAAW-KPC_0Ab1L9oGFgoQBRAdAVAQABgA4AYB8gYCCACABwGIBwCgBwE.&s=896d8d25ed5c73ed4b49adebaa58ba23ed6afa43', - '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.500000, - 'cpm_publisher_currency': 0.500000, - '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%2Fgdpr_hello_world.html%3Fpbjs_debug%3Dtrue&e=wqT_3QL8CWz8BAAAAwDWAAUBCKKt0fAFEO3ftM_qtayUXhj_EQEQASo2CQAFAQjgPxEFCDAA4D8ZAAAAgOtR4D8hERIAKREJADERG6gwsqKiBjjtSEDtSEgCUNOBly5YnPFbYABotc95eMu4BYABAYoBA1VTRJIBAQbwUpgBrAKgAfoBqAEBsAEAuAEBwAEEyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc4MzkxMjAyKTt1ZigncicsIDk2ODQ2MDM1Nh4A9A4BkgLJAiF0ajlmS2dpdXNLNEtFTk9CbHk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRc3FLaUJsZ0FZUF9fX184UGFBQndBWGdCZ0FFQmlBRUJrQUVCbUFFQm9BRUJxQUVEc0FFQXVRRXBpNGlEQUFEZ1A4RUJLWXVJZ3dBQTREX0pBZWxBS28zZEV1OF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBTUFDQWNnQ0FkQUNBZGdDQWVBQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEcnJDdUNyb0RDVk5KVGpNNk5EY3pPZUFEX0JpSUJBQ1FCQUNZQkFIQkJBQUFBQQmDCHlRUQkJAQEYTmdFQVBFRQELCQEwRDRCQUNJQllNbHFRVQkTREFEd1B3Li6aAokBIWZnOFhHUTZNASRuUEZiSUFRb0FEEUhYRGdQem9KVTBsT016bzBOek01UVB3WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8EBlQUEuwgIvaHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3MvZ2V0dGluZy1zdGFydGVkLmh0bWzYAgDgAq2YSOoCWA068IF0ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvZ3B0L2dkcHJfaGVsbG9fd29ybGQuaHRtbD9wYmpzX2RlYnVnPXRydWWAAwGIAwGQAwCYAxegAwGqAwDAA6wCyAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzDb3wW5gEAKIECzEwLjc1Ljc0LjY5qAS_NrIEEggEEAQYrAIg-gEoASgCMAA4ArgEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM52gQCCAHgBAHwBNOBly6IBQGYBQCgBf__bdQUAcAFAMkFabEU8D_SBQkJCQyIAADYBQHgBQHwBQH6BQQIABAAkAYAmAYAsgaWAUJPc3kwUXkBBixYaUFBQUJBRU5DMi0hswh0RjdhJQxfX185AQXwcV9fOXV6X092X3ZfZl9fMzNlOF9fOXZfbF83Xy1fX191Xy0zM2Q0dV8xdmY5OXlmbTEtN2V0cjN0cF84N3VlczJfWHVyX183OV9fM3ozXzlweFA3OGs4OXI3MzM3RXdfdi1fdi1iN0pDT05fQbgGAcEGAAW-KPA_0Ab1L9oGFgoQBRAdAVAQABgA4AYB8gYCCACABwGIBwCgBwE.&s=1ad011df80b035fdd957f6ae84e46bdeebae9f83'], - 'video_events': {} - }] - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/instream/index.js b/test/mock-server/expectations/request-response-pairs/instream/index.js deleted file mode 100644 index 2c6ca03875b..00000000000 --- a/test/mock-server/expectations/request-response-pairs/instream/index.js +++ /dev/null @@ -1,95 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - 'httpResponse': { - 'body': { - 'version': '3.0.0', - 'tags': [{ - 'uuid': '206465a8c326a5', - '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': 5.000000, - 'cpm_publisher_currency': 5.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' - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/ad_server_translation_request_1.js b/test/mock-server/expectations/request-response-pairs/longform/ad_server_translation_request_1.js deleted file mode 100644 index d92e64c6075..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/ad_server_translation_request_1.js +++ /dev/null @@ -1,577 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'minduration': 30, - 'maxduration': 30 - } - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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 - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/ad_server_translation_request_2.js b/test/mock-server/expectations/request-response-pairs/longform/ad_server_translation_request_2.js deleted file mode 100644 index ea77d211826..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/ad_server_translation_request_2.js +++ /dev/null @@ -1,289 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'minduration': 30, - 'maxduration': 30 - } - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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 - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/basic_w_requireExactDuration_request_1.js b/test/mock-server/expectations/request-response-pairs/longform/basic_w_requireExactDuration_request_1.js deleted file mode 100644 index 0c58bd6fb3e..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/basic_w_requireExactDuration_request_1.js +++ /dev/null @@ -1,606 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'minduration': 30, - 'maxduration': 30 - } - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 14.000010, - '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.000010, - 'cpm_publisher_currency': 13.000010, - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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 - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/basic_w_requireExactDuration_request_2.js b/test/mock-server/expectations/request-response-pairs/longform/basic_w_requireExactDuration_request_2.js deleted file mode 100644 index 38331688a9b..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/basic_w_requireExactDuration_request_2.js +++ /dev/null @@ -1,288 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'minduration': 30, - 'maxduration': 30 - } - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 13.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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 - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/basic_wo_brandCategoryExclusion_request_1.js b/test/mock-server/expectations/request-response-pairs/longform/basic_wo_brandCategoryExclusion_request_1.js deleted file mode 100644 index ee1a19d21b2..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/basic_wo_brandCategoryExclusion_request_1.js +++ /dev/null @@ -1,852 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'maxduration': 30 - } - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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' - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/basic_wo_brandCategoryExclusion_request_2.js b/test/mock-server/expectations/request-response-pairs/longform/basic_wo_brandCategoryExclusion_request_2.js deleted file mode 100644 index ce8bad3e9d7..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/basic_wo_brandCategoryExclusion_request_2.js +++ /dev/null @@ -1,312 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'maxduration': 30 - } - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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' - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/basic_wo_requireExactDuration_request_1.js b/test/mock-server/expectations/request-response-pairs/longform/basic_wo_requireExactDuration_request_1.js deleted file mode 100644 index fc2ad82fe5f..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/basic_wo_requireExactDuration_request_1.js +++ /dev/null @@ -1,620 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'maxduration': 30 - } - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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.000010, - 'cpm_publisher_currency': 13.000010, - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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 - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/basic_wo_requireExactDuration_request_2.js b/test/mock-server/expectations/request-response-pairs/longform/basic_wo_requireExactDuration_request_2.js deleted file mode 100644 index 751abfa14e4..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/basic_wo_requireExactDuration_request_2.js +++ /dev/null @@ -1,312 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'maxduration': 30 - } - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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' - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/bidder_settings_request_1.js b/test/mock-server/expectations/request-response-pairs/longform/bidder_settings_request_1.js deleted file mode 100644 index 4f11a203724..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/bidder_settings_request_1.js +++ /dev/null @@ -1,418 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'maxduration': 30 - } - }], - 'user': {}, - 'brand_category_uniqueness': true - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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 - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/bidder_settings_request_2.js b/test/mock-server/expectations/request-response-pairs/longform/bidder_settings_request_2.js deleted file mode 100644 index b69612d86b9..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/bidder_settings_request_2.js +++ /dev/null @@ -1,284 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'maxduration': 30 - } - }], - 'user': {}, - 'brand_category_uniqueness': true - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 13.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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' - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/price_gran_request_1.js b/test/mock-server/expectations/request-response-pairs/longform/price_gran_request_1.js deleted file mode 100644 index ffb03cc0563..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/price_gran_request_1.js +++ /dev/null @@ -1,620 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'maxduration': 30 - } - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 13.000010, - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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 - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/longform/price_gran_request_2.js b/test/mock-server/expectations/request-response-pairs/longform/price_gran_request_2.js deleted file mode 100644 index 5a716c6e8e9..00000000000 --- a/test/mock-server/expectations/request-response-pairs/longform/price_gran_request_2.js +++ /dev/null @@ -1,283 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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, - '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, - '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, - '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, - '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, - 'require_asset_url': true, - 'video': { - 'maxduration': 30 - } - }], - 'user': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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.000010, - 'cpm_publisher_currency': 13.000010, - '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.000010, - 'cpm_publisher_currency': 15.000010, - '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' - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/multiple-bidders/index-1.js b/test/mock-server/expectations/request-response-pairs/multiple-bidders/index-1.js deleted file mode 100644 index deca38b6022..00000000000 --- a/test/mock-server/expectations/request-response-pairs/multiple-bidders/index-1.js +++ /dev/null @@ -1,111 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - 'httpResponse': { - 'body': { - 'version': '3.0.0', - 'tags': [{ - 'uuid': '256e5e4b136d05', - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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 - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/multiple-bidders/index-2.js b/test/mock-server/expectations/request-response-pairs/multiple-bidders/index-2.js deleted file mode 100644 index ae09e4ec4a7..00000000000 --- a/test/mock-server/expectations/request-response-pairs/multiple-bidders/index-2.js +++ /dev/null @@ -1,177 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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 - }, { - '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': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - 'httpResponse': { - 'body': { - 'version': '3.0.0', - 'tags': [{ - 'uuid': '28ae233df319a1', - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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': {} - }] - } - }] - }, { - 'uuid': '375d249fda4d84', - 'tag_id': 13232354, - 'auction_id': '2793298983265666969', - '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_3QKGCKAGBAAAAwDWAAUBCNGcpvEFEJmPioiD1PLhJhi7_-bKzp3kuD8qNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMOLRpwY47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc5NzgxNzEzKTsBHSxyJywgOTc0OTQyMDQ2HgDw0JICtQIhZ2oxVmFnajgtTHdLRUx6SnZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWUtzR2FBQndCbmlhQklBQm1BR0lBV0tRQVFDWUFRQ2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCQXNyenVXOVg0RF9aQVFBQUFBQUFBUEFfNEFFQTlRRUFBQUFBbUFJQW9BSUF0UUlBQUFBQXZRSUFBQUFBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVA4AcSIdWdNSlUwbE9Nem8wTnpNNTRBUDRHWWdFQUpBRUFKZ0VBY0UJXQUBCERKQgUICQEYMkFRQThRUQkNAQEsUGdFQUlnRmd5V3BCERc0UEFfmgKJASF2QS1kUHc2OQEkblBGYklBUW9BRBVkDGtRRG8ykQAQUVBnWlMdTQBVEQwMQUFBVx0MAFkdDABhHQwAYx0MoGVBQS7YAgDgAq2YSOoCS2h0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5BRT0DgEvcGFnZXMvbXVsdGlwbGVfYmlkZGVycy5odG1sP3BianNfZGVidWc9dHJ1ZYADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDjEwMy43OS4xMDAuMTgwqASfRLIEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MznaBAIIAOAEAfAEvMm-LogFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBZn0IfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYM8gYCCACABwGIBwCgB0E.&s=acd26154fe24e1ce797e3016322901140c18ce65', - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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': 'https://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': '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-native-ads.html', - 'click_trackers': ['https://sin3-ib.adnxs.com/click?AAAAAAAAJEAAAAAAAAAkQAAAAAAAACRAAAAAAAAAJEAAAAAAAAAkQJmHAjGgysMmu79Z6eyQcT9RjileAAAAAOLoyQBtJAAAbSQAAAIAAAC8pM8FnPgWAAAAAABVU0QAVVNEAAEAAQBNXQAAAAABAQQCAAAAALoAxBbHxgAAAAA./bcr=AAAAAAAA8D8=/cnd=%21vA-dPwj8-LwKELzJvi4YnPFbIAQoADEAAAAAAAAkQDoJU0lOMzo0NzM5QPgZSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA./cca=OTMyNSNTSU4zOjQ3Mzk=/bn=89116/'] - }, - '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_3QKOCKAOBAAAAwDWAAUBCNGcpvEFEJmPioiD1PLhJhi7_-bKzp3kuD8qNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlC8yb4uWJzxW2AAaM26dXicuAWAAQGKAQNVU0SSAQEG8FKYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1Nzk3ODE3MTMpO3VmKCdyJywgOTc0OTQyMDQsIC4eAPDQkgK1AiFnajFWYWdqOC1Md0tFTHpKdmk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNHRHbkJsZ0FZS3NHYUFCd0JuaWFCSUFCbUFHSUFXS1FBUUNZQVFDZ0FRR29BUU93QVFDNUFmT3RhcVFBQUNSQXdRSHpyV3FrQUFBa1FNa0JBc3J6dVc5WDREX1pBUUFBQUFBQUFQQV80QUVBOVFFQUFBQUFtQUlBb0FJQXRRSUFBQUFBdlFJQUFBQUE0QUlBNkFJQS1BSUFnQU1CbUFNQnFBUDgBxIh1Z01KVTBsT016bzBOek01NEFQNEdZZ0VBSkFFQUpnRUFjRQldBQEIREpCBQgJARgyQVFBOFFRCQ0BASxQZ0VBSWdGZ3lXcEIRFzRQQV-aAokBIXZBLWRQdzY5ASRuUEZiSUFRb0FEFWQMa1FEbzKRABBRUGdaUx1NAFURDAxBQUFXHQwAWR0MAGEdDABjHQygZUFBLtgCAOACrZhI6gJLaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkFFPQOAS9wYWdlcy9tdWx0aXBsZV9iaWRkZXJzLmh0bWw_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQOMTAzLjc5LjEwMC4xODCoBJ9EsgQOCAAQARgAIAAoADAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczOdoEAggB4AQB8AS8yb4uiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmfQh-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8D_QBvUv2gYWChAJERkBUBAAGADgBgzyBgIIAIAHAYgHAKAHQQ..&s=2d3f9336af4da684d7733e29f53bbb80bf69a18c'], - 'id': 97494204 - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/native/index.js b/test/mock-server/expectations/request-response-pairs/native/index.js deleted file mode 100644 index 201e9834b68..00000000000 --- a/test/mock-server/expectations/request-response-pairs/native/index.js +++ /dev/null @@ -1,193 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - 'httpResponse': { - 'body': { - 'version': '3.0.0', - 'tags': [{ - 'uuid': '2b7ae9fa0e76be', - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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 - } - } - }] - }, { - 'uuid': '35598a5ad26f59', - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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 - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/expectations/request-response-pairs/outstream/index.js b/test/mock-server/expectations/request-response-pairs/outstream/index.js deleted file mode 100644 index ad2502aff2d..00000000000 --- a/test/mock-server/expectations/request-response-pairs/outstream/index.js +++ /dev/null @@ -1,164 +0,0 @@ -var app = require('../../../index'); - -/** - * This file will have the fixtures for request and response. Each one has to export two functions getRequest and getResponse. - * expectation directory will hold all the request reponse pairs of different types. middlewares added to the server will parse - * these files and return the response when expecation is met - * - */ - -/** - * This function will return the request object with all the entities method, path, body, header etc. - * - * @return {object} Request object - */ -exports.getRequest = function() { - return { - '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': {} - } - } - } -} - -/** - * This function will return the response object with all the entities method, path, body, header etc. - * - * @return {object} Response object - */ -exports.getResponse = function() { - return { - 'httpResponse': { - 'body': { - 'version': '3.0.0', - 'tags': [{ - 'uuid': '223e8549781f2e', - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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' - } - } - }] - }, { - 'uuid': '3acfd472dd4bdf', - '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.000000, - 'cpm_publisher_currency': 10.000000, - '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' - } - } - }] - }] - } - } - } -} diff --git a/test/mock-server/index.js b/test/mock-server/index.js deleted file mode 100644 index 9a97ca5e0a0..00000000000 --- a/test/mock-server/index.js +++ /dev/null @@ -1,37 +0,0 @@ -/* eslint-disable no-console */ -const express = require('express'); -const argv = require('yargs').argv; -const app = module.exports = express(); -const port = (argv.port) ? argv.port : 3000; -const bodyParser = require('body-parser'); -const renderCreative = require('./request-middlewares/prebid-request.js'); - -app.use(express.static(__dirname + '/content')); -app.use(bodyParser.text({type: 'text/plain'})); - -app.locals = { - 'port': port, - 'host': 'localhost' -}; - -// get type will be used to test prebid jsonp requests -app.get('/', renderCreative, (request, response) => { - response.send(); -}); - -// prebid make POST type request to ut endpoint so here we will match ut endpoint request. -app.post('/', renderCreative, (request, response) => { - response.send(); -}); - -app.listen(port, (err) => { - if (err) { - return console.log('something bad happened', err); - } - - console.log(`server is listening on ${port}`); -}); - -process.on('SIGTERM', function() { console.log('halt mock-server'); process.exit(0) }); - -process.on('SIGINT', function() { console.log('shutdown mock-server'); process.exit(0) }); diff --git a/test/mock-server/request-middlewares/prebid-request.js b/test/mock-server/request-middlewares/prebid-request.js deleted file mode 100644 index b14c3119247..00000000000 --- a/test/mock-server/request-middlewares/prebid-request.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * This middleware will be used to find matching request hitting the ut endpoint by prebid. - * As of now it only uses the request payload to compare with httpRequest.body defined in expectations dir. - * Matching headers or cookies can also be the use case. - */ - -const glob = require('glob'); -const path = require('path'); -const deepEqual = require('deep-equal'); - -module.exports = function (req, res, next) { - let reqBody; - try { - if (req.method === 'GET') { - reqBody = JSON.parse(req.query.q); - } else { - reqBody = JSON.parse(req.body); - } - } catch (e) { - // error - } - - // prebid uses uuid to match request response pairs. - // On each request new uuid is generated, so here i am grabbing the uuid from incoming request and adding it to matched response. - let uuidObj = {}; - if (reqBody && reqBody.uuid) { - uuidObj.response = reqBody.uuid; - delete reqBody.uuid; - } - - if (reqBody && reqBody.tags) { - uuidObj.tags = reqBody.tags.map((tag) => { - let uuid = tag.uuid; - delete tag.uuid; - return uuid; - }); - } - - // values within these request props are dynamically generated and aren't - // vital to check in these tests, so they are deleted rather than updating - // the request-response pairs continuously - ['sdk', 'referrer_detection', 'brand_category_uniqueness', 'gdpr_consent'].forEach(prop => { - if (reqBody && reqBody[prop]) { - delete reqBody[prop]; - } - }); - - // Parse all the expectation to find response for this request - glob.sync('./test/mock-server/expectations/**/*.js').some((file) => { - file = require(path.resolve(file)); - let expectedReqBody = JSON.parse(JSON.stringify(file.getRequest().httpRequest.body)); - // respond to all requests - // TODO send a 404 if resource not found - res.set({ - 'Access-Control-Allow-Credentials': 'true', - 'Access-Control-Allow-Origin': req.headers.origin - }); - - // As of now only body is compared. We can also add other request properties like headers, cookies if required - if (deepEqual(reqBody, expectedReqBody)) { - let response = file.getResponse().httpResponse.body; - if (Object.keys(uuidObj).length > 0) { - response.tags.forEach((tag, index) => { - tag.uuid = uuidObj.tags[index]; - }); - } - res.type('json'); - response = JSON.stringify(response); - res.write(response); - return true; - } - }); - - next(); -}; diff --git a/test/pages/banner.html b/test/pages/banner.html index e1859abdd85..75993cefb39 100644 --- a/test/pages/banner.html +++ b/test/pages/banner.html @@ -31,22 +31,20 @@ } }] } - //, { - // code: 'div-gpt-ad-1460505748561-1', - // mediaTypes: { - // banner: { - // sizes: [[300, 250], [300, 600]], - // } - // }, - // bids: [{ - // bidder: "appnexus", - // params: { - // accountId: 14062, - // siteId: 70608, - // zoneId: 498816 - // } - // }] - // } + ,{ + code: 'div-gpt-ad-1460505748561-1', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + bids: [{ + bidder: "appnexus", + params: { + placementId: 13144370 + } + }] + } ]; @@ -54,18 +52,18 @@ var googletag = googletag || {}; googletag.cmd = googletag.cmd || []; - googletag.cmd.push(() => { + googletag.cmd.push(function() { googletag.pubads().disableInitialLoad(); }); - pbjs.que.push(() => { + pbjs.que.push(function () { pbjs.addAdUnits(adUnits); pbjs.requestBids({ bidsBackHandler: sendAdServerRequest }); }); function sendAdServerRequest() { - googletag.cmd.push(() => { - pbjs.que.push(() => { + googletag.cmd.push(function () { + pbjs.que.push(function () { pbjs.setTargetingForGPTAsync('div-gpt-ad-1460505748561-0'); googletag.pubads().refresh(); }); @@ -74,7 +72,7 @@
diff --git a/test/pages/bidderSettings.html b/test/pages/bidderSettings.html index a4a718d6497..015ad3ca45f 100644 --- a/test/pages/bidderSettings.html +++ b/test/pages/bidderSettings.html @@ -1,125 +1,127 @@ + - - - + + + - + function sendAdserverRequest() { + if (pbjs.adserverRequestSent) return; + pbjs.adserverRequestSent = true; + googletag.cmd.push(function () { + pbjs.que.push(function () { + pbjs.setTargetingForGPTAsync(); + googletag.pubads().refresh(); + }); + }); + } - - googletag.pubads().enableSingleRequest(); - googletag.enableServices(); - }); - + -

Prebid.js Test

-
Div-1
-
+

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 index a7da17ca2f7..02b367b3c7c 100644 --- a/test/pages/consent_mgt_gdpr.html +++ b/test/pages/consent_mgt_gdpr.html @@ -1,206 +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 index 5214982f67c..7f196e60d5e 100644 --- a/test/pages/currency.html +++ b/test/pages/currency.html @@ -80,7 +80,7 @@ "currency": { "adServerCurrency": "GBP", "granularityMultiplier": 1, - "defaultRates": { "USD": { "GBP": 0.75 }} + "defaultRates": { "USD": { "GBP": 0.80 }} } }); pbjs.addAdUnits(adUnits); diff --git a/test/pages/instream.html b/test/pages/instream.html index be7aceb40db..c1e2358b754 100644 --- a/test/pages/instream.html +++ b/test/pages/instream.html @@ -49,6 +49,14 @@ }; pbjs.que.push(function(){ + pbjs.onEvent('auctionEnd', function() { + let pEl = document.createElement('p'); + pEl.innerText = 'PREBID HAS FINISHED'; + pEl.id = 'statusText'; + let parDiv = document.getElementById('event-window'); + parDiv.appendChild(pEl); + }); + pbjs.addAdUnits(videoAdUnit); pbjs.setConfig({ debug: true, @@ -57,7 +65,6 @@ } }); pbjs.requestBids({ - timeout : 700, bidsBackHandler : function(bids) { var videoUrl = pbjs.adServers.dfp.buildVideoUrl({ adUnit: videoAdUnit, @@ -70,36 +77,13 @@ } }); }); - - pbjs.bidderSettings = - { - standard: { - adserverTargeting: [ - { - key: "hb_bidder", - val: function (bidResponse) { - return bidResponse.bidderCode; - } - }, { - key: "hb_adid", - val: function (bidResponse) { - return bidResponse.adId; - } - }, { - key: "hb_pb", - val: function (bidResponse) { - return "10.00"; - } - }, { - key: "hb_size", - val: function (bidResponse) { - return bidResponse.size; - - } - } - ] + pbjs.bidderSettings = { + appnexus: { + bidCpmAdjustment: function() { + return 10.00; } - }; + } + }; @@ -107,6 +91,7 @@

Prebid Video -- video.js

+
diff --git a/test/pages/outstream.html b/test/pages/outstream.html index 2a0543095cd..262c15ed02a 100644 --- a/test/pages/outstream.html +++ b/test/pages/outstream.html @@ -62,7 +62,14 @@ pbjs.que.push(function () { pbjs.setConfig({ debug: true }); - pbjs.addAdUnits(outstreamVideoAdUnit); + pbjs.addAdUnits(outstreamVideoAdUnit); + pbjs.bidderSettings = { + appnexus: { + bidCpmAdjustment: function () { + return 10; + } + } + }; pbjs.requestBids({ bidsBackHandler: initAdServer }); }); diff --git a/test/pages/priceGranularity.html b/test/pages/priceGranularity.html index 588b11044fb..7eae83f673a 100644 --- a/test/pages/priceGranularity.html +++ b/test/pages/priceGranularity.html @@ -1,131 +1,133 @@ + - - - + + + - + - + googletag.pubads().enableSingleRequest(); + googletag.enableServices(); + }); + -

Prebid.js Test

-
Div-1
-
+

Prebid.js Test

+
Div-1
+
-
+
- + + \ No newline at end of file diff --git a/test/pages/sizeConfig.html b/test/pages/sizeConfig.html index b62b4a741ab..a4aef89e44a 100644 --- a/test/pages/sizeConfig.html +++ b/test/pages/sizeConfig.html @@ -1,142 +1,144 @@ + - - - + + + - + - + googletag.pubads().enableSingleRequest(); + googletag.enableServices(); + }); + -

Prebid.js Test

-
Div-1
-
+

Prebid.js Test

+
Div-1
+
-
+
- + + \ No newline at end of file diff --git a/test/pages/userSync.html b/test/pages/userSync.html index 43aeafd46e9..3d848906ae3 100644 --- a/test/pages/userSync.html +++ b/test/pages/userSync.html @@ -1,121 +1,123 @@ + - - - + + + - + function sendAdserverRequest() { + if (pbjs.adserverRequestSent) return; + pbjs.adserverRequestSent = true; + googletag.cmd.push(function () { + pbjs.que.push(function () { + pbjs.setTargetingForGPTAsync(); + googletag.pubads().refresh(); + }); + }); + } - - googletag.pubads().enableSingleRequest(); - googletag.enableServices(); - }); - + -

Prebid.js Test

-
Div-1
-
+

Prebid.js Test

+
Div-1
+
-
+
- + + \ No newline at end of file diff --git a/test/spec/AnalyticsAdapter_spec.js b/test/spec/AnalyticsAdapter_spec.js index 4afa430f81e..71fb9f87fa0 100644 --- a/test/spec/AnalyticsAdapter_spec.js +++ b/test/spec/AnalyticsAdapter_spec.js @@ -9,6 +9,7 @@ const BID_RESPONSE = CONSTANTS.EVENTS.BID_RESPONSE; const BID_WON = CONSTANTS.EVENTS.BID_WON; const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; const AD_RENDER_FAILED = CONSTANTS.EVENTS.AD_RENDER_FAILED; +const AUCTION_DEBUG = CONSTANTS.EVENTS.AUCTION_DEBUG; const ADD_AD_UNITS = CONSTANTS.EVENTS.ADD_AD_UNITS; const AnalyticsAdapter = require('src/AnalyticsAdapter').default; @@ -83,6 +84,17 @@ FEATURE: Analytics Adapters API expect(result).to.deep.equal({args: {call: 'adRenderFailed'}, eventType: 'adRenderFailed'}); }); + it('SHOULD call global when an auction debug event occurs', function () { + const eventType = AUCTION_DEBUG; + const args = { call: 'auctionDebug' }; + + adapter.enableAnalytics(); + events.emit(eventType, args); + + let result = JSON.parse(server.requests[0].requestBody); + expect(result).to.deep.equal({args: {call: 'auctionDebug'}, eventType: 'auctionDebug'}); + }); + it('SHOULD call global when an addAdUnits event occurs', function () { const eventType = ADD_AD_UNITS; const args = { call: 'addAdUnits' }; diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index 35a29727614..e35b1406fbf 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -740,6 +740,29 @@ describe('auctionmanager.js', function () { assert.equal(addedBid.renderer.url, 'renderer.js'); }); + it('installs publisher-defined backup renderers on bids', function () { + let renderer = { + url: 'renderer.js', + backupOnly: true, + render: (bid) => bid + }; + let bidRequests = [Object.assign({}, TEST_BID_REQS[0])]; + bidRequests[0].bids[0] = Object.assign({ renderer }, bidRequests[0].bids[0]); + makeRequestsStub.returns(bidRequests); + + let bids1 = Object.assign({}, + bids[0], + { + bidderCode: BIDDER_CODE, + mediaType: 'video-outstream', + } + ); + spec.interpretResponse.returns(bids1); + auction.callBids(); + const addedBid = auction.getBidsReceived().pop(); + assert.equal(addedBid.renderer.url, 'renderer.js'); + }); + it('bid for a regular unit and a video unit', function() { let renderer = { url: 'renderer.js', diff --git a/test/spec/e2e/banner/basic_banner_ad.spec.js b/test/spec/e2e/banner/basic_banner_ad.spec.js index fa2d5af142f..7088bd3eade 100644 --- a/test/spec/e2e/banner/basic_banner_ad.spec.js +++ b/test/spec/e2e/banner/basic_banner_ad.spec.js @@ -1,27 +1,28 @@ const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); +const { host, protocol, waitForElement, switchFrame } = require('../../../helpers/testing-utils'); const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/banner.html?pbjs_debug=true`; -const CREATIVE_IFRAME_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/header-bid-tag-0_0"]'; +const CREATIVE_IFRAME_ID = 'google_ads_iframe_/19968336/header-bid-tag-0_0'; +const CREATIVE_IFRAME_CSS_SELECTOR = 'iframe[id="' + CREATIVE_IFRAME_ID + '"]'; const EXPECTED_TARGETING_KEYS = { 'hb_format': 'banner', 'hb_source': 'client', - 'hb_pb': '0.60', - 'hb_bidder': 'rubicon', - 'hb_format_rubicon': 'banner', - 'hb_source_rubicon': 'client', - 'hb_pb_rubicon': '0.60', - 'hb_bidder_rubicon': 'rubicon' + 'hb_pb': '0.50', + 'hb_bidder': 'appnexus', + 'hb_format_appnexus': 'banner', + 'hb_source_appnexus': 'client', + 'hb_pb_appnexus': '0.50', + 'hb_bidder_appnexus': 'appnexus' }; describe('Prebid.js Banner Ad Unit Test', function () { + this.retries(3); before(function loadTestPage() { - browser.url(TEST_PAGE_URL).pause(3000); + browser.url(TEST_PAGE_URL); + browser.pause(3000); try { - browser.waitForExist(CREATIVE_IFRAME_CSS_SELECTOR, 2000); - const creativeIframe = $(CREATIVE_IFRAME_CSS_SELECTOR).value; - browser.frame(creativeIframe); + waitForElement(CREATIVE_IFRAME_CSS_SELECTOR, 3000); } catch (e) { // If creative Iframe didn't load, repeat the steps again! // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js @@ -29,21 +30,21 @@ describe('Prebid.js Banner Ad Unit Test', function () { } }); - // TODO: Add below test again. Removed the test since we are testing only for appnexus endpoint now and appnexus adapter does not set AdserverTargetting. + it('should load the targeting keys with correct values', function () { + const result = browser.execute(function () { + return window.pbjs.getAdserverTargeting('div-gpt-ad-1460505748561-1'); + }); + const targetingKeys = result['div-gpt-ad-1460505748561-1']; - // it('should load the targeting keys with correct values', function () { - // const result = browser.execute(function () { - // return window.top.pbjs.getAdserverTargeting('div-gpt-ad-1460505748561-1'); - // }); - // const targetingKeys = result.value['div-gpt-ad-1460505748561-1']; - - // expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); - // expect(targetingKeys.hb_adid).to.be.a('string'); - // expect(targetingKeys.hb_adid_rubicon).to.be.a('string'); - // expect(targetingKeys.hb_size).to.satisfy((size) => size === '300x250' || '300x600'); - // }); + expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); + expect(targetingKeys.hb_adid).to.be.a('string'); + expect(targetingKeys.hb_adid_appnexus).to.be.a('string'); + expect(targetingKeys.hb_size).to.satisfy((size) => size === '300x250' || '300x600'); + }); it('should render the Banner Ad on the page', function () { - expect(browser.isVisible('body > div[class="GoogleActiveViewElement"] > a > img')).to.be.true; + switchFrame(CREATIVE_IFRAME_CSS_SELECTOR, CREATIVE_IFRAME_ID); + const ele = $('body > div[class="GoogleActiveViewElement"] > a > img'); + expect(ele.isExisting()).to.be.true; }); }); diff --git a/test/spec/e2e/instream/basic_instream_video_ad.spec.js b/test/spec/e2e/instream/basic_instream_video_ad.spec.js index 034363685d2..b712f90bf63 100644 --- a/test/spec/e2e/instream/basic_instream_video_ad.spec.js +++ b/test/spec/e2e/instream/basic_instream_video_ad.spec.js @@ -1,12 +1,10 @@ const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); +const { host, protocol, waitForElement } = require('../../../helpers/testing-utils'); const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/instream.html?pbjs_debug=true`; -const CREATIVE_IFRAME_CSS_SELECTOR = 'div[class="VPAID-container"] > div > iframe'; +const ALERT_BOX_CSS_SELECTOR = 'div[id="event-window"] > p[id="statusText"]'; const EXPECTED_TARGETING_KEYS = { - hb_cache_id: '', - hb_uuid: '', hb_format: 'video', hb_source: 'client', hb_size: '640x480', @@ -20,13 +18,12 @@ const EXPECTED_TARGETING_KEYS = { }; describe('Prebid.js Instream Video Ad Test', function () { + this.retries(3); before(function loadTestPage() { - browser - .url(TEST_PAGE_URL) + browser.url(TEST_PAGE_URL); + browser.pause(5000); try { - browser.waitForExist(CREATIVE_IFRAME_CSS_SELECTOR, 5000); - // const creativeIframe = $(CREATIVE_IFRAME_CSS_SELECTOR).value; - // browser.frame(creativeIframe); + waitForElement(ALERT_BOX_CSS_SELECTOR, 3000); } catch (e) { // If creative Iframe didn't load, repeat the steps again! // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js @@ -34,19 +31,18 @@ describe('Prebid.js Instream Video Ad Test', function () { } }); - // it('should load the targeting keys with correct values', function () { - // const result = browser.execute(function () { - // console.log('pbjs::', window.top.pbjs); - // return window.top.pbjs.getAdserverTargeting('video1'); - // }); - // console.log('result:::', result); - // const targetingKeys = result.value['vid1']; - // expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); - // expect(targetingKeys.hb_adid).to.be.a('string'); - // expect(targetingKeys.hb_adid_appnexus).to.be.a('string'); - // }); + it('should load the targeting keys with correct values', function () { + const result = browser.execute(function () { + return window.top.pbjs.getAdserverTargeting('video1'); + }); - it('should render the instream ad on the page', function() { - expect(browser.isVisible(CREATIVE_IFRAME_CSS_SELECTOR)); + const targetingKeys = result['video1']; + expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); + expect(targetingKeys.hb_adid).to.be.a('string'); + expect(targetingKeys.hb_adid_appnexus).to.be.a('string'); + expect(targetingKeys.hb_uuid).to.be.a('string'); + expect(targetingKeys.hb_cache_id).to.be.a('string'); + expect(targetingKeys.hb_uuid_appnexus).to.be.a('string'); + expect(targetingKeys.hb_cache_id_appnexus).to.be.a('string'); }); }); diff --git a/test/spec/e2e/longform/basic_w_bidderSettings.spec.js b/test/spec/e2e/longform/basic_w_bidderSettings.spec.js index 684f5acab17..d3443558316 100644 --- a/test/spec/e2e/longform/basic_w_bidderSettings.spec.js +++ b/test/spec/e2e/longform/basic_w_bidderSettings.spec.js @@ -1,9 +1,6 @@ const includes = require('core-js-pure/features/array/includes.js'); const expect = require('chai').expect; -const testServer = require('../../../helpers/testing-utils'); - -const host = testServer.host; -const protocol = testServer.protocol; +const { host, protocol, waitForElement } = require('../../../helpers/testing-utils'); const validDurations = ['15s', '30s']; const validCats = ['Food', 'Retail Stores/Chains', 'Pet Food/Supplies', 'Travel/Hotels/Airlines', 'Automotive', 'Health Care Services']; @@ -14,20 +11,20 @@ const uuidRegex = /(\d|\w){8}-((\d|\w){4}-){3}(\d|\w){12}/; describe('longform ads not using requireExactDuration field', function() { this.retries(3); it('process the bids successfully', function() { - browser - .url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_w_bidderSettings.html?pbjs_debug=true') - .pause(10000); + browser.url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_w_bidderSettings.html?pbjs_debug=true'); + browser.pause(7000); const loadPrebidBtnXpath = '//*[@id="loadPrebidRequestBtn"]'; - browser.waitForExist(loadPrebidBtnXpath); - $(loadPrebidBtnXpath).click(); - browser.pause(3000); + waitForElement(loadPrebidBtnXpath, 3000); + const prebidBtn = $(loadPrebidBtnXpath); + prebidBtn.click(); + browser.pause(5000); const listOfCpmsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[2]'; const listOfCategoriesXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[3]'; const listOfDurationsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[4]'; - browser.waitForExist(listOfCpmsXpath); + waitForElement(listOfCpmsXpath, 3000); let listOfCpms = $$(listOfCpmsXpath); let listOfCats = $$(listOfCategoriesXpath); @@ -47,8 +44,8 @@ describe('longform ads not using requireExactDuration field', function() { it('formats the targeting keys properly', function () { const listOfKeyElementsXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[1]'; const listOfKeyValuesXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[2]'; - browser.waitForExist(listOfKeyElementsXpath); - browser.waitForExist(listOfKeyValuesXpath); + waitForElement(listOfKeyElementsXpath); + waitForElement(listOfKeyValuesXpath); let listOfKeyElements = $$(listOfKeyElementsXpath); let listOfKeyValues = $$(listOfKeyValuesXpath); diff --git a/test/spec/e2e/longform/basic_w_custom_adserver_translation.spec.js b/test/spec/e2e/longform/basic_w_custom_adserver_translation.spec.js index 175e5d041d9..9abe7295027 100644 --- a/test/spec/e2e/longform/basic_w_custom_adserver_translation.spec.js +++ b/test/spec/e2e/longform/basic_w_custom_adserver_translation.spec.js @@ -1,9 +1,6 @@ const includes = require('core-js-pure/features/array/includes.js'); const expect = require('chai').expect; -const testServer = require('../../../helpers/testing-utils'); - -const host = testServer.host; -const protocol = testServer.protocol; +const { host, protocol, waitForElement } = require('../../../helpers/testing-utils'); const validDurations = ['15s', '30s']; const validCats = ['Food', 'Retail Stores/Chains', 'Pet Food/Supplies', 'Travel/Hotels/Airlines', 'Automotive', 'Health Care Services']; @@ -14,20 +11,20 @@ const uuidRegex = /(\d|\w){8}-((\d|\w){4}-){3}(\d|\w){12}/; describe('longform ads using custom adserver translation file', function() { this.retries(3); it('process the bids successfully', function() { - browser - .url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_w_custom_adserver_translation.html?pbjs_debug=true') - .pause(10000); + browser.url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_w_custom_adserver_translation.html?pbjs_debug=true'); + browser.pause(7000); const loadPrebidBtnXpath = '//*[@id="loadPrebidRequestBtn"]'; - browser.waitForExist(loadPrebidBtnXpath); - $(loadPrebidBtnXpath).click(); - browser.pause(3000); + waitForElement(loadPrebidBtnXpath, 3000); + const prebidBtn = $(loadPrebidBtnXpath); + prebidBtn.click(); + browser.pause(5000); const listOfCpmsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[2]'; const listOfCategoriesXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[3]'; const listOfDurationsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[4]'; - browser.waitForExist(listOfCpmsXpath); + waitForElement(listOfCpmsXpath); let listOfCpms = $$(listOfCpmsXpath); let listOfCats = $$(listOfCategoriesXpath); @@ -47,8 +44,8 @@ describe('longform ads using custom adserver translation file', function() { it('formats the targeting keys properly', function () { const listOfKeyElementsXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[1]'; const listOfKeyValuesXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[2]'; - browser.waitForExist(listOfKeyElementsXpath); - browser.waitForExist(listOfKeyValuesXpath); + waitForElement(listOfKeyElementsXpath); + waitForElement(listOfKeyValuesXpath); let listOfKeyElements = $$(listOfKeyElementsXpath); let listOfKeyValues = $$(listOfKeyValuesXpath); diff --git a/test/spec/e2e/longform/basic_w_priceGran.spec.js b/test/spec/e2e/longform/basic_w_priceGran.spec.js index 294557193b4..5658595eef7 100644 --- a/test/spec/e2e/longform/basic_w_priceGran.spec.js +++ b/test/spec/e2e/longform/basic_w_priceGran.spec.js @@ -1,9 +1,6 @@ const includes = require('core-js-pure/features/array/includes.js'); const expect = require('chai').expect; -const testServer = require('../../../helpers/testing-utils'); - -const host = testServer.host; -const protocol = testServer.protocol; +const { host, protocol, waitForElement } = require('../../../helpers/testing-utils'); const validDurations = ['15s', '30s']; const validCats = ['Food', 'Retail Stores/Chains', 'Pet Food/Supplies', 'Travel/Hotels/Airlines', 'Automotive', 'Health Care Services']; @@ -14,20 +11,20 @@ const uuidRegex = /(\d|\w){8}-((\d|\w){4}-){3}(\d|\w){12}/; describe('longform ads not using requireExactDuration field', function() { this.retries(3); it('process the bids successfully', function() { - browser - .url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_w_priceGran.html?pbjs_debug=true') - .pause(10000); + browser.url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_w_priceGran.html?pbjs_debug=true'); + browser.pause(7000); const loadPrebidBtnXpath = '//*[@id="loadPrebidRequestBtn"]'; - browser.waitForExist(loadPrebidBtnXpath); - $(loadPrebidBtnXpath).click(); - browser.pause(3000); + waitForElement(loadPrebidBtnXpath); + const prebidBtn = $(loadPrebidBtnXpath); + prebidBtn.click(); + browser.pause(5000); const listOfCpmsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[2]'; const listOfCategoriesXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[3]'; const listOfDurationsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[4]'; - browser.waitForExist(listOfCpmsXpath); + waitForElement(listOfCpmsXpath); let listOfCpms = $$(listOfCpmsXpath); let listOfCats = $$(listOfCategoriesXpath); @@ -47,8 +44,8 @@ describe('longform ads not using requireExactDuration field', function() { it('formats the targeting keys properly', function () { const listOfKeyElementsXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[1]'; const listOfKeyValuesXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[2]'; - browser.waitForExist(listOfKeyElementsXpath); - browser.waitForExist(listOfKeyValuesXpath); + waitForElement(listOfKeyElementsXpath); + waitForElement(listOfKeyValuesXpath); let listOfKeyElements = $$(listOfKeyElementsXpath); let listOfKeyValues = $$(listOfKeyValuesXpath); diff --git a/test/spec/e2e/longform/basic_w_requireExactDuration.spec.js b/test/spec/e2e/longform/basic_w_requireExactDuration.spec.js index d92e5361ae3..886daa3e320 100644 --- a/test/spec/e2e/longform/basic_w_requireExactDuration.spec.js +++ b/test/spec/e2e/longform/basic_w_requireExactDuration.spec.js @@ -1,9 +1,6 @@ const includes = require('core-js-pure/features/array/includes.js'); const expect = require('chai').expect; -const testServer = require('../../../helpers/testing-utils'); - -const host = testServer.host; -const protocol = testServer.protocol; +const { host, protocol, waitForElement } = require('../../../helpers/testing-utils'); const validDurations = ['15s', '30s']; const validCats = ['Food', 'Retail Stores/Chains', 'Pet Food/Supplies', 'Travel/Hotels/Airlines', 'Automotive', 'Health Care Services']; @@ -14,20 +11,20 @@ const uuidRegex = /(\d|\w){8}-((\d|\w){4}-){3}(\d|\w){12}/; describe('longform ads using requireExactDuration field', function() { this.retries(3); it('process the bids successfully', function() { - browser - .url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_w_requireExactDuration.html?pbjs_debug=true') - .pause(10000); + browser.url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_w_requireExactDuration.html?pbjs_debug=true'); + browser.pause(7000); const loadPrebidBtnXpath = '//*[@id="loadPrebidRequestBtn"]'; - browser.waitForExist(loadPrebidBtnXpath); - $(loadPrebidBtnXpath).click(); - browser.pause(3000); + waitForElement(loadPrebidBtnXpath); + const prebidBtn = $(loadPrebidBtnXpath); + prebidBtn.click(); + browser.pause(5000); const listOfCpmsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[2]'; const listOfCategoriesXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[3]'; const listOfDurationsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[4]'; - browser.waitForExist(listOfCpmsXpath); + waitForElement(listOfCpmsXpath); let listOfCpms = $$(listOfCpmsXpath); let listOfCats = $$(listOfCategoriesXpath); @@ -47,8 +44,8 @@ describe('longform ads using requireExactDuration field', function() { it('formats the targeting keys properly', function () { const listOfKeyElementsXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[1]'; const listOfKeyValuesXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[2]'; - browser.waitForExist(listOfKeyElementsXpath); - browser.waitForExist(listOfKeyValuesXpath); + waitForElement(listOfKeyElementsXpath); + waitForElement(listOfKeyValuesXpath); let listOfKeyElements = $$(listOfKeyElementsXpath); let listOfKeyValues = $$(listOfKeyValuesXpath); diff --git a/test/spec/e2e/longform/basic_wo_brandCategoryExclusion.spec.js b/test/spec/e2e/longform/basic_wo_brandCategoryExclusion.spec.js index de3e334e755..e19f90b8c39 100644 --- a/test/spec/e2e/longform/basic_wo_brandCategoryExclusion.spec.js +++ b/test/spec/e2e/longform/basic_wo_brandCategoryExclusion.spec.js @@ -1,9 +1,6 @@ const includes = require('core-js-pure/features/array/includes.js'); const expect = require('chai').expect; -const testServer = require('../../../helpers/testing-utils'); - -const host = testServer.host; -const protocol = testServer.protocol; +const { host, protocol, waitForElement } = require('../../../helpers/testing-utils'); const validDurations = ['15s', '30s']; const validCpms = ['15.00', '14.00', '13.00', '10.00']; @@ -13,19 +10,19 @@ const uuidRegex = /(\d|\w){8}-((\d|\w){4}-){3}(\d|\w){12}/; describe('longform ads without using brandCategoryExclusion', function() { this.retries(3); it('process the bids successfully', function() { - browser - .url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_wo_brandCategoryExclusion.html?pbjs_debug=true') - .pause(10000); + browser.url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_wo_brandCategoryExclusion.html?pbjs_debug=true'); + browser.pause(7000); const loadPrebidBtnXpath = '//*[@id="loadPrebidRequestBtn"]'; - browser.waitForExist(loadPrebidBtnXpath); - $(loadPrebidBtnXpath).click(); - browser.pause(3000); + waitForElement(loadPrebidBtnXpath); + const prebidBtn = $(loadPrebidBtnXpath); + prebidBtn.click(); + browser.pause(5000); const listOfCpmsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[2]'; const listOfDurationsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[4]'; - browser.waitForExist(listOfCpmsXpath); + waitForElement(listOfCpmsXpath); let listOfCpms = $$(listOfCpmsXpath); let listOfDuras = $$(listOfDurationsXpath); @@ -42,8 +39,8 @@ describe('longform ads without using brandCategoryExclusion', function() { it('formats the targeting keys properly', function () { const listOfKeyElementsXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[1]'; const listOfKeyValuesXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[2]'; - browser.waitForExist(listOfKeyElementsXpath); - browser.waitForExist(listOfKeyValuesXpath); + waitForElement(listOfKeyElementsXpath); + waitForElement(listOfKeyValuesXpath); let listOfKeyElements = $$(listOfKeyElementsXpath); let listOfKeyValues = $$(listOfKeyValuesXpath); diff --git a/test/spec/e2e/longform/basic_wo_requireExactDuration.spec.js b/test/spec/e2e/longform/basic_wo_requireExactDuration.spec.js index 849eb5ade4d..cb1bcda93ff 100644 --- a/test/spec/e2e/longform/basic_wo_requireExactDuration.spec.js +++ b/test/spec/e2e/longform/basic_wo_requireExactDuration.spec.js @@ -1,9 +1,6 @@ const includes = require('core-js-pure/features/array/includes.js'); const expect = require('chai').expect; -const testServer = require('../../../helpers/testing-utils'); - -const host = testServer.host; -const protocol = testServer.protocol; +const { host, protocol, waitForElement } = require('../../../helpers/testing-utils'); const validDurations = ['15s', '30s']; const validCats = ['Food', 'Retail Stores/Chains', 'Pet Food/Supplies', 'Travel/Hotels/Airlines', 'Automotive', 'Health Care Services']; @@ -14,20 +11,20 @@ const uuidRegex = /(\d|\w){8}-((\d|\w){4}-){3}(\d|\w){12}/; describe('longform ads not using requireExactDuration field', function() { this.retries(3); it('process the bids successfully', function() { - browser - .url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_wo_requireExactDuration.html?pbjs_debug=true') - .pause(10000); + browser.url(protocol + '://' + host + ':9999/integrationExamples/longform/basic_wo_requireExactDuration.html?pbjs_debug=true'); + browser.pause(7000); const loadPrebidBtnXpath = '//*[@id="loadPrebidRequestBtn"]'; - browser.waitForExist(loadPrebidBtnXpath); - $(loadPrebidBtnXpath).click(); - browser.pause(3000); + waitForElement(loadPrebidBtnXpath); + const prebidBtn = $(loadPrebidBtnXpath); + prebidBtn.click(); + browser.pause(5000); const listOfCpmsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[2]'; const listOfCategoriesXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[3]'; const listOfDurationsXpath = '/html/body/div[1]/div/div/div/div[1]/div[2]/div/table/tbody/tr/td[4]'; - browser.waitForExist(listOfCpmsXpath); + waitForElement(listOfCpmsXpath); let listOfCpms = $$(listOfCpmsXpath); let listOfCats = $$(listOfCategoriesXpath); @@ -47,8 +44,8 @@ describe('longform ads not using requireExactDuration field', function() { it('formats the targeting keys properly', function () { const listOfKeyElementsXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[1]'; const listOfKeyValuesXpath = '/html/body/div[1]/div/div/div/div[2]/div[2]/div/table/tbody/tr/td[2]'; - browser.waitForExist(listOfKeyElementsXpath); - browser.waitForExist(listOfKeyValuesXpath); + waitForElement(listOfKeyElementsXpath); + waitForElement(listOfKeyValuesXpath); let listOfKeyElements = $$(listOfKeyElementsXpath); let listOfKeyValues = $$(listOfKeyValuesXpath); diff --git a/test/spec/e2e/modules/e2e_bidderSettings.spec.js b/test/spec/e2e/modules/e2e_bidderSettings.spec.js index d9f1d18725d..2c0ba484654 100644 --- a/test/spec/e2e/modules/e2e_bidderSettings.spec.js +++ b/test/spec/e2e/modules/e2e_bidderSettings.spec.js @@ -1,5 +1,5 @@ const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); +const { host, protocol, waitForElement, switchFrame } = require('../../../helpers/testing-utils'); const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/bidderSettings.html?pbjs_debug=true`; const CREATIVE_IFRAME_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/header-bid-tag-0_0"]'; @@ -24,12 +24,12 @@ const EXPECTED_TARGETING_KEYS = { } describe('Prebid.js Bidder Settings Ad Unit Test', function () { + this.retries(3); before(function loadTestPage() { - browser.url(TEST_PAGE_URL).pause(3000); + browser.url(TEST_PAGE_URL); + browser.pause(3000); try { - browser.waitForExist(CREATIVE_IFRAME_CSS_SELECTOR, 2000); - const creativeIframe = $(CREATIVE_IFRAME_CSS_SELECTOR).value; - browser.frame(creativeIframe); + waitForElement(CREATIVE_IFRAME_CSS_SELECTOR, 2000); } catch (e) { // If creative Iframe didn't load, repeat the steps again! // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js @@ -39,10 +39,10 @@ describe('Prebid.js Bidder Settings Ad Unit Test', function () { it('should load the targeting keys with correct values', function () { const result = browser.execute(function () { - return window.top.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); + return window.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); }); - const targetingKeys = result.value['/19968336/prebid_native_example_2']; + const targetingKeys = result['/19968336/prebid_native_example_2']; expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); expect(targetingKeys.hb_adid).to.be.a('string'); expect(targetingKeys.hb_native_body).to.be.a('string'); @@ -54,6 +54,8 @@ describe('Prebid.js Bidder Settings Ad Unit Test', function () { }); it('should render the Banner Ad on the page', function () { - expect(browser.isVisible('body > div[class="GoogleActiveViewElement"] > a > img')).to.be.true; + switchFrame(CREATIVE_IFRAME_CSS_SELECTOR); + const ele = $('body > div[class="GoogleActiveViewElement"] > a > img'); + expect(ele.isExisting()).to.be.true; }); }); diff --git a/test/spec/e2e/modules/e2e_consent_mgt_gdpr.spec.js b/test/spec/e2e/modules/e2e_consent_mgt_gdpr.spec.js index 1c11a5432ff..4e0e7da49ea 100644 --- a/test/spec/e2e/modules/e2e_consent_mgt_gdpr.spec.js +++ b/test/spec/e2e/modules/e2e_consent_mgt_gdpr.spec.js @@ -1,5 +1,5 @@ const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); +const { host, protocol, switchFrame, waitForElement } = require('../../../helpers/testing-utils'); const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/consent_mgt_gdpr.html?pbjs_debug=true`; const CREATIVE_IFRAME_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/header-bid-tag-0_0"]'; @@ -24,12 +24,12 @@ const EXPECTED_TARGETING_KEYS = { }; describe('Prebid.js GDPR Ad Unit Test', function () { + this.retries(3); before(function loadTestPage() { - browser.url(TEST_PAGE_URL).pause(3000); + browser.url(TEST_PAGE_URL); + browser.pause(3000); try { - browser.waitForExist(CREATIVE_IFRAME_CSS_SELECTOR, 2000); - const creativeIframe = $(CREATIVE_IFRAME_CSS_SELECTOR).value; - browser.frame(creativeIframe); + waitForElement(CREATIVE_IFRAME_CSS_SELECTOR, 2000); } catch (e) { // If creative Iframe didn't load, repeat the steps again! // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js @@ -39,10 +39,10 @@ describe('Prebid.js GDPR Ad Unit Test', function () { it('should load the targeting keys with correct values', function () { const result = browser.execute(function () { - return window.top.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); + return window.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); }); - const targetingKeys = result.value['/19968336/prebid_native_example_2']; + const targetingKeys = result['/19968336/prebid_native_example_2']; expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); expect(targetingKeys.hb_adid).to.be.a('string'); expect(targetingKeys.hb_native_body).to.be.a('string'); @@ -54,6 +54,8 @@ describe('Prebid.js GDPR Ad Unit Test', function () { }); it('should render the Banner Ad on the page', function () { - expect(browser.isVisible('body > div[class="GoogleActiveViewElement"] > a > img')).to.be.true; + switchFrame(CREATIVE_IFRAME_CSS_SELECTOR); + const ele = $('body > div[class="GoogleActiveViewElement"] > a > img'); + expect(ele.isExisting()).to.be.true; }); }); diff --git a/test/spec/e2e/modules/e2e_currency.spec.js b/test/spec/e2e/modules/e2e_currency.spec.js index 8692b4991bd..8d8da5c5d45 100644 --- a/test/spec/e2e/modules/e2e_currency.spec.js +++ b/test/spec/e2e/modules/e2e_currency.spec.js @@ -1,5 +1,5 @@ const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); +const { host, protocol, waitForElement, switchFrame } = require('../../../helpers/testing-utils'); const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/currency.html?pbjs_debug=true`; const CREATIVE_IFRAME_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/header-bid-tag-0_0"]'; @@ -7,7 +7,6 @@ const CREATIVE_IFRAME_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/hea const EXPECTED_TARGETING_KEYS = { hb_source: 'client', hb_source_appnexus: 'client', - hb_pb_appnexus: '7.50', hb_native_title_appn: 'This is a Prebid Native Creative', hb_native_linkurl: 'http://prebid.org/dev-docs/show-native-ads.html', hb_format: 'native', @@ -16,7 +15,6 @@ const EXPECTED_TARGETING_KEYS = { hb_bidder_appnexus: 'appnexus', hb_native_linkurl_ap: 'http://prebid.org/dev-docs/show-native-ads.html', hb_native_title: 'This is a Prebid Native Creative', - hb_pb: '7.50', hb_native_brand_appn: 'Prebid.org', hb_bidder: 'appnexus', hb_format_appnexus: 'native', @@ -24,12 +22,12 @@ const EXPECTED_TARGETING_KEYS = { } describe('Prebid.js Currency Ad Unit Test', function () { + this.retries(3); before(function loadTestPage() { - browser.url(TEST_PAGE_URL).pause(3000); + browser.url(TEST_PAGE_URL); + browser.pause(5000); try { - browser.waitForExist(CREATIVE_IFRAME_CSS_SELECTOR, 2000); - const creativeIframe = $(CREATIVE_IFRAME_CSS_SELECTOR).value; - browser.frame(creativeIframe); + waitForElement(CREATIVE_IFRAME_CSS_SELECTOR, 2000); } catch (e) { // If creative Iframe didn't load, repeat the steps again! // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js @@ -39,12 +37,14 @@ describe('Prebid.js Currency Ad Unit Test', function () { it('should load the targeting keys with correct values', function () { const result = browser.execute(function () { - return window.top.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); + return window.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); }); - const targetingKeys = result.value['/19968336/prebid_native_example_2']; + const targetingKeys = result['/19968336/prebid_native_example_2']; expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); expect(targetingKeys.hb_adid).to.be.a('string'); + expect(targetingKeys.hb_pb).to.be.a('string'); + expect(targetingKeys.hb_pb_appnexus).to.be.a('string'); expect(targetingKeys.hb_native_body).to.be.a('string'); expect(targetingKeys.hb_native_body_appne).to.be.a('string'); expect(targetingKeys.hb_native_icon).to.be.a('string'); @@ -54,6 +54,8 @@ describe('Prebid.js Currency Ad Unit Test', function () { }); it('should render the Banner Ad on the page', function () { - expect(browser.isVisible('body > div[class="GoogleActiveViewElement"] > a > img')).to.be.true; + switchFrame(CREATIVE_IFRAME_CSS_SELECTOR); + const ele = $('body > div[class="GoogleActiveViewElement"] > a > img'); + expect(ele.isExisting()).to.be.true; }); }); diff --git a/test/spec/e2e/modules/e2e_priceGranularity.spec.js b/test/spec/e2e/modules/e2e_priceGranularity.spec.js index 1042ab491fb..157961d69ea 100644 --- a/test/spec/e2e/modules/e2e_priceGranularity.spec.js +++ b/test/spec/e2e/modules/e2e_priceGranularity.spec.js @@ -1,5 +1,5 @@ const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); +const { host, protocol, switchFrame, waitForElement } = require('../../../helpers/testing-utils'); const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/priceGranularity.html?pbjs_debug=true`; const CREATIVE_IFRAME_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/header-bid-tag-0_0"]'; @@ -24,12 +24,12 @@ const EXPECTED_TARGETING_KEYS = { } describe('Prebid.js Price Granularity Ad Unit Test', function () { + this.retries(3); before(function loadTestPage() { - browser.url(TEST_PAGE_URL).pause(3000); + browser.url(TEST_PAGE_URL); + browser.pause(3000); try { - browser.waitForExist(CREATIVE_IFRAME_CSS_SELECTOR, 2000); - const creativeIframe = $(CREATIVE_IFRAME_CSS_SELECTOR).value; - browser.frame(creativeIframe); + waitForElement(CREATIVE_IFRAME_CSS_SELECTOR, 2000); } catch (e) { // If creative Iframe didn't load, repeat the steps again! // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js @@ -39,10 +39,10 @@ describe('Prebid.js Price Granularity Ad Unit Test', function () { it('should load the targeting keys with correct values', function () { const result = browser.execute(function () { - return window.top.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); + return window.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); }); - const targetingKeys = result.value['/19968336/prebid_native_example_2']; + const targetingKeys = result['/19968336/prebid_native_example_2']; expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); expect(targetingKeys.hb_adid).to.be.a('string'); expect(targetingKeys.hb_native_body).to.be.a('string'); @@ -54,6 +54,8 @@ describe('Prebid.js Price Granularity Ad Unit Test', function () { }); it('should render the Banner Ad on the page', function () { - expect(browser.isVisible('body > div[class="GoogleActiveViewElement"] > a > img')).to.be.true; + switchFrame(CREATIVE_IFRAME_CSS_SELECTOR); + const ele = $('body > div[class="GoogleActiveViewElement"] > a > img'); + expect(ele.isExisting()).to.be.true; }); }); diff --git a/test/spec/e2e/modules/e2e_sizeConfig.spec.js b/test/spec/e2e/modules/e2e_sizeConfig.spec.js index 1eb3fad8dea..a37e6d49122 100644 --- a/test/spec/e2e/modules/e2e_sizeConfig.spec.js +++ b/test/spec/e2e/modules/e2e_sizeConfig.spec.js @@ -1,5 +1,5 @@ const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); +const { host, protocol, switchFrame, waitForElement } = require('../../../helpers/testing-utils'); const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/sizeConfig.html?pbjs_debug=true`; const CREATIVE_IFRAME_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/header-bid-tag-0_0"]'; @@ -24,12 +24,12 @@ const EXPECTED_TARGETING_KEYS = { } describe('Prebid.js Size Config Ad Unit Test', function () { + this.retries(3); before(function loadTestPage() { - browser.url(TEST_PAGE_URL).pause(3000); + browser.url(TEST_PAGE_URL); + browser.pause(3000); try { - browser.waitForExist(CREATIVE_IFRAME_CSS_SELECTOR, 2000); - const creativeIframe = $(CREATIVE_IFRAME_CSS_SELECTOR).value; - browser.frame(creativeIframe); + waitForElement(CREATIVE_IFRAME_CSS_SELECTOR, 2000); } catch (e) { // If creative Iframe didn't load, repeat the steps again! // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js @@ -39,10 +39,10 @@ describe('Prebid.js Size Config Ad Unit Test', function () { it('should load the targeting keys with correct values', function () { const result = browser.execute(function () { - return window.top.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); + return window.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); }); - const targetingKeys = result.value['/19968336/prebid_native_example_2']; + const targetingKeys = result['/19968336/prebid_native_example_2']; expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); expect(targetingKeys.hb_adid).to.be.a('string'); expect(targetingKeys.hb_native_body).to.be.a('string'); @@ -54,6 +54,8 @@ describe('Prebid.js Size Config Ad Unit Test', function () { }); it('should render the Banner Ad on the page', function () { - expect(browser.isVisible('body > div[class="GoogleActiveViewElement"] > a > img')).to.be.true; + switchFrame(CREATIVE_IFRAME_CSS_SELECTOR); + const ele = $('body > div[class="GoogleActiveViewElement"] > a > img'); + expect(ele.isExisting()).to.be.true; }); }); diff --git a/test/spec/e2e/modules/e2e_userSync.spec.js b/test/spec/e2e/modules/e2e_userSync.spec.js index 3957f3cdfef..d945bfd3278 100644 --- a/test/spec/e2e/modules/e2e_userSync.spec.js +++ b/test/spec/e2e/modules/e2e_userSync.spec.js @@ -1,5 +1,5 @@ const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); +const { host, protocol, switchFrame, waitForElement } = require('../../../helpers/testing-utils'); const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/userSync.html?pbjs_debug=true`; const CREATIVE_IFRAME_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/header-bid-tag-0_0"]'; @@ -24,12 +24,12 @@ const EXPECTED_TARGETING_KEYS = { } describe('Prebid.js User Sync Ad Unit Test', function () { + this.retries(3); before(function loadTestPage() { - browser.url(TEST_PAGE_URL).pause(3000); + browser.url(TEST_PAGE_URL); + browser.pause(3000); try { - browser.waitForExist(CREATIVE_IFRAME_CSS_SELECTOR, 2000); - const creativeIframe = $(CREATIVE_IFRAME_CSS_SELECTOR).value; - browser.frame(creativeIframe); + waitForElement(CREATIVE_IFRAME_CSS_SELECTOR, 2000); } catch (e) { // If creative Iframe didn't load, repeat the steps again! // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js @@ -39,10 +39,10 @@ describe('Prebid.js User Sync Ad Unit Test', function () { it('should load the targeting keys with correct values', function () { const result = browser.execute(function () { - return window.top.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); + return window.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); }); - const targetingKeys = result.value['/19968336/prebid_native_example_2']; + const targetingKeys = result['/19968336/prebid_native_example_2']; expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); expect(targetingKeys.hb_adid).to.be.a('string'); expect(targetingKeys.hb_native_body).to.be.a('string'); @@ -54,6 +54,8 @@ describe('Prebid.js User Sync Ad Unit Test', function () { }); it('should render the Banner Ad on the page', function () { - expect(browser.isVisible('body > div[class="GoogleActiveViewElement"] > a > img')).to.be.true; + switchFrame(CREATIVE_IFRAME_CSS_SELECTOR); + const ele = $('body > div[class="GoogleActiveViewElement"] > a > img'); + expect(ele.isExisting()).to.be.true; }); }); diff --git a/test/spec/e2e/multi-bidder/e2e_multiple_bidders.spec.js b/test/spec/e2e/multi-bidder/e2e_multiple_bidders.spec.js new file mode 100644 index 00000000000..a67e2bd6db5 --- /dev/null +++ b/test/spec/e2e/multi-bidder/e2e_multiple_bidders.spec.js @@ -0,0 +1,67 @@ +const expect = require('chai').expect; +const { host, protocol, waitForElement, switchFrame } = require('../../../helpers/testing-utils'); + +const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/multiple_bidders.html?pbjs_debug=true`; +const CREATIVE_BANNER_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/prebid_multiformat_test_0"]'; + +const EXPECTED_TARGETING_KEYS = { + hb_source: 'client', + hb_source_adasta: 'client', + hb_pb_adasta: '10.00', + hb_native_title_adas: 'This is a Prebid Native Creative', + hb_native_linkurl: 'http://prebid.org/dev-docs/show-multi-format-ads.html', + hb_format: 'native', + hb_native_brand: 'Prebid.org', + hb_size: '0x0', + hb_bidder_adasta: 'adasta', + hb_native_linkurl_ad: 'http://prebid.org/dev-docs/show-multi-format-ads.html', + hb_native_title: 'This is a Prebid Native Creative', + hb_pb: '10.00', + hb_native_brand_adas: 'Prebid.org', + hb_bidder: 'adasta', + hb_format_adasta: 'native', + hb_size_adasta: '0x0' +}; + +describe('Prebid.js Multiple Bidder Ad Unit Test', function () { + this.retries(3); + before(function loadTestPage() { + browser.url(TEST_PAGE_URL); + browser.pause(5000); + try { + waitForElement(CREATIVE_BANNER_CSS_SELECTOR, 3000); + } catch (e) { + // If creative Iframe didn't load, repeat the steps again! + // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js + loadTestPage(); + } + }); + + it('should load the targeting keys with correct values', function () { + const result = browser.execute(function () { + return window.pbjs.getAdserverTargeting('div-banner-native-2'); + }); + + const targetingKeys = result['div-banner-native-2']; + expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); + expect(targetingKeys.hb_adid).to.be.a('string'); + expect(targetingKeys.hb_native_image).to.be.a('string'); + expect(targetingKeys.hb_native_image_adas).to.be.a('string'); + expect(targetingKeys.hb_adid_adasta).to.be.a('string'); + }); + + it('should render the Banner Ad on the page', function () { + switchFrame(CREATIVE_BANNER_CSS_SELECTOR); + let ele = $('body > div[class="GoogleActiveViewElement"] > a > img'); + expect(ele.isExisting()).to.be.true; + }); + + // it('should render the native ad on the page', function () { + // browser.switchToParentFrame(); + // waitForElement(CREATIVE_NATIVE_CSS_SELECTOR, 3000); + // switchFrame(CREATIVE_NATIVE_CSS_SELECTOR); + + // let ele = $('body > div[class="GoogleActiveViewElement"] > div[class="card"]'); + // expect(ele.isExisting()).to.be.true; + // }); +}); diff --git a/test/spec/e2e/multi-format/e2e_multiple_bidders.spec.js b/test/spec/e2e/multi-format/e2e_multiple_bidders.spec.js deleted file mode 100644 index 4ce750bdd96..00000000000 --- a/test/spec/e2e/multi-format/e2e_multiple_bidders.spec.js +++ /dev/null @@ -1,68 +0,0 @@ -const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); - -const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/multiple_bidders.html?pbjs_debug=true`; -const CREATIVE_BANNER_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/prebid_multiformat_test_0"]'; -const CREATIVE_NATIVE_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/prebid_multiformat_test_1"]'; - -const EXPECTED_TARGETING_KEYS = { - hb_source: 'client', - hb_source_appnexus: 'client', - hb_pb_appnexus: '10.00', - hb_native_title_appn: 'This is a Prebid Native Creative', - hb_native_linkurl: 'http://prebid.org/dev-docs/show-native-ads.html', - hb_format: 'native', - hb_native_brand: 'Prebid.org', - hb_size: '0x0', - hb_bidder_appnexus: 'appnexus', - hb_native_linkurl_ap: 'http://prebid.org/dev-docs/show-native-ads.html', - hb_native_title: 'This is a Prebid Native Creative', - hb_pb: '10.00', - hb_native_brand_appn: 'Prebid.org', - hb_bidder: 'appnexus', - hb_format_appnexus: 'native', - hb_size_appnexus: '0x0' -}; - -describe('Prebid.js Multiple Bidder Ad Unit Test', function () { - before(function loadTestPage() { - browser.url(TEST_PAGE_URL).pause(3000); - try { - browser.waitForExist(CREATIVE_BANNER_CSS_SELECTOR, 3000); - const creativeIframe = $(CREATIVE_BANNER_CSS_SELECTOR).value; - browser.frame(creativeIframe); - } catch (e) { - // If creative Iframe didn't load, repeat the steps again! - // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js - loadTestPage(); - } - }); - - it('should load the targeting keys with correct values', function () { - const result = browser.execute(function () { - return window.top.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); - }); - - const targetingKeys = result.value['/19968336/prebid_native_example_2']; - expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); - expect(targetingKeys.hb_adid).to.be.a('string'); - expect(targetingKeys.hb_native_body).to.be.a('string'); - expect(targetingKeys.hb_native_body_appne).to.be.a('string'); - expect(targetingKeys.hb_native_icon).to.be.a('string'); - expect(targetingKeys.hb_native_icon_appne).to.be.a('string'); - expect(targetingKeys.hb_native_image).to.be.a('string'); - expect(targetingKeys.hb_adid_appnexus).to.be.a('string'); - }); - - it('should render the Banner Ad on the page', function () { - expect(browser.isVisible('body > div[class="GoogleActiveViewElement"] > a > img')).to.be.true; - }); - - it('should render the native ad on the page', function () { - browser.frameParent(); - browser.waitForExist(CREATIVE_NATIVE_CSS_SELECTOR, 3000); - const creativeIframe = $(CREATIVE_NATIVE_CSS_SELECTOR).value; - browser.frame(creativeIframe); - expect(browser.isVisible('body > div[class="GoogleActiveViewElement"] > div[class="card"]')).to.be.true; - }); -}); diff --git a/test/spec/e2e/native/basic_native_ad.spec.js b/test/spec/e2e/native/basic_native_ad.spec.js index 8eb9a5940a0..418bcf271a3 100644 --- a/test/spec/e2e/native/basic_native_ad.spec.js +++ b/test/spec/e2e/native/basic_native_ad.spec.js @@ -1,5 +1,5 @@ const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); +const { host, protocol, switchFrame, waitForElement } = require('../../../helpers/testing-utils'); const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/native.html`; const CREATIVE_IFRAME_CSS_SELECTOR = 'iframe[id="google_ads_iframe_/19968336/prebid_native_example_1_0"]'; @@ -24,10 +24,12 @@ const EXPECTED_TARGETING_KEYS = { } describe('Prebid.js Native Ad Unit Test', function () { + this.retries(3); before(function loadTestPage() { - browser.url(TEST_PAGE_URL).pause(3000); + browser.url(TEST_PAGE_URL); + browser.pause(3000); try { - browser.waitForExist(CREATIVE_IFRAME_CSS_SELECTOR, 2000); + waitForElement(CREATIVE_IFRAME_CSS_SELECTOR, 2000); } catch (e) { // If creative Iframe didn't load, repeat the steps again! // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js @@ -37,10 +39,10 @@ describe('Prebid.js Native Ad Unit Test', function () { it('should load the targeting keys with correct values', function () { const result = browser.execute(function () { - return window.top.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); + return window.pbjs.getAdserverTargeting('/19968336/prebid_native_example_2'); }); - const targetingKeys = result.value['/19968336/prebid_native_example_2']; + const targetingKeys = result['/19968336/prebid_native_example_2']; expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); expect(targetingKeys.hb_adid).to.be.a('string'); expect(targetingKeys.hb_native_body).to.be.a('string'); @@ -52,8 +54,8 @@ describe('Prebid.js Native Ad Unit Test', function () { }); it('should render the native ad on the page', function () { - const creativeIframe = $(CREATIVE_IFRAME_CSS_SELECTOR).value; - browser.frame(creativeIframe); - expect(browser.isVisible('body > div[class="GoogleActiveViewElement"] > div[class="card"]')).to.be.true; + switchFrame(CREATIVE_IFRAME_CSS_SELECTOR); + const ele = $('body > div[class="GoogleActiveViewElement"] > div[class="card"]'); + expect(ele.isExisting()).to.be.true; }); }); diff --git a/test/spec/e2e/outstream/basic_outstream_video_ad.spec.js b/test/spec/e2e/outstream/basic_outstream_video_ad.spec.js index 15b0bb29309..0240b094f5e 100644 --- a/test/spec/e2e/outstream/basic_outstream_video_ad.spec.js +++ b/test/spec/e2e/outstream/basic_outstream_video_ad.spec.js @@ -1,5 +1,5 @@ const expect = require('chai').expect; -const { host, protocol } = require('../../../helpers/testing-utils'); +const { host, protocol, waitForElement, switchFrame } = require('../../../helpers/testing-utils'); const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/outstream.html`; const CREATIVE_IFRAME_CSS_SELECTOR = 'div[id="video_ad_unit_1"] > div:nth-child(2) > iframe:nth-child(1)'; @@ -20,13 +20,15 @@ const EXPECTED_TARGETING_KEYS = { }; describe('Prebid.js Outstream Video Ad Test', function () { + this.retries(3); before(function loadTestPage() { - browser - .url(TEST_PAGE_URL) - .scroll(0, 300) - .pause(3000); + browser.url(TEST_PAGE_URL); + browser.execute(function () { + return window.scrollBy(0, 300); + }); + browser.pause(3000); try { - browser.waitForExist(CREATIVE_IFRAME_CSS_SELECTOR, 5000); + waitForElement(CREATIVE_IFRAME_CSS_SELECTOR, 5000); } catch (e) { // If creative Iframe didn't load, repeat the steps again! // Due to some reason if the Ad server doesn't respond, the test case will time out after 60000 ms as defined in file wdio.conf.js @@ -39,15 +41,19 @@ describe('Prebid.js Outstream Video Ad Test', function () { return window.pbjs.getAdserverTargeting('video_ad_unit_2'); }); - const targetingKeys = result.value['video_ad_unit_2']; + const targetingKeys = result['video_ad_unit_2']; expect(targetingKeys).to.include(EXPECTED_TARGETING_KEYS); expect(targetingKeys.hb_adid).to.be.a('string'); expect(targetingKeys.hb_adid_appnexus).to.be.a('string'); }); it('should render the native ad on the page', function() { - const creativeIframe = $(CREATIVE_IFRAME_CSS_SELECTOR).value; - browser.frame(creativeIframe); - expect(browser.isVisible('body > div[class="video-js"] > video')); + // skipping test in Edge due to wdio bug: https://github.com/webdriverio/webdriverio/issues/3880 + // the iframe for the video does not have a name property and id is generated automatically... + if (browser.capabilities.browserName !== 'edge') { + switchFrame(CREATIVE_IFRAME_CSS_SELECTOR); + const ele = $('body > div[id*="an_video_ad_player"] > video'); + expect(ele.isExisting()).to.be.true; + } }); }); diff --git a/test/spec/integration/faker/googletag.js b/test/spec/integration/faker/googletag.js index a0ce04402f7..9d91bf315d9 100644 --- a/test/spec/integration/faker/googletag.js +++ b/test/spec/integration/faker/googletag.js @@ -43,18 +43,52 @@ export function makeSlot() { return slot; } -window.googletag = { - _slots: [], - pubads: function () { - var self = this; - return { - getSlots: function () { - return self._slots; - }, - - setSlots: function (slots) { - self._slots = slots; - } - }; - } -}; +export function emitEvent(eventName, params) { + (window.googletag._callbackMap[eventName] || []).forEach(eventCb => eventCb({...params, eventName})); +} + +export function enable() { + window.googletag = { + _slots: [], + _callbackMap: {}, + pubads: function () { + var self = this; + return { + getSlots: function () { + return self._slots; + }, + + setSlots: function (slots) { + self._slots = slots; + }, + + setTargeting: function(key, arrayOfValues) { + self._targeting[key] = Array.isArray(arrayOfValues) ? arrayOfValues : [arrayOfValues]; + }, + + getTargeting: function(key) { + return self._targeting[key] || []; + }, + + getTargetingKeys: function() { + return Object.getOwnPropertyNames(self._targeting); + }, + + clearTargeting: function() { + self._targeting = {}; + }, + + addEventListener: function (eventName, cb) { + self._callbackMap[eventName] = self._callbackMap[eventName] || []; + self._callbackMap[eventName].push(cb); + } + }; + } + }; +} + +export function disable() { + window.googletag = undefined; +} + +enable(); diff --git a/test/spec/modules/33acrossBidAdapter_spec.js b/test/spec/modules/33acrossBidAdapter_spec.js index d27cc99b5bc..d30659791ea 100644 --- a/test/spec/modules/33acrossBidAdapter_spec.js +++ b/test/spec/modules/33acrossBidAdapter_spec.js @@ -22,13 +22,11 @@ describe('33acrossBidAdapter:', function () { format: [ { w: 300, - h: 250, - ext: {} + h: 250 }, { w: 728, - h: 90, - ext: {} + h: 90 } ], ext: { @@ -56,7 +54,8 @@ describe('33acrossBidAdapter:', function () { }, regs: { ext: { - gdpr: 0 + gdpr: 0, + us_privacy: null } }, ext: { @@ -92,12 +91,30 @@ describe('33acrossBidAdapter:', function () { }); Object.assign(ttxRequest, { regs: { - ext: { gdpr } + ext: Object.assign( + {}, + ttxRequest.regs.ext, + { gdpr } + ) } }); return this; }; + this.withUspConsent = (consent) => { + Object.assign(ttxRequest, { + regs: { + ext: Object.assign( + {}, + ttxRequest.regs.ext, + { us_privacy: consent } + ) + } + }); + + return this; + }; + this.withSite = site => { Object.assign(ttxRequest, { site }); return this; @@ -111,13 +128,41 @@ describe('33acrossBidAdapter:', function () { return this; }; + this.withSchain = schain => { + Object.assign(ttxRequest, { + source: { + ext: { + schain + } + } + }); + + return this; + }; + + this.withFormatFloors = floors => { + const format = ttxRequest.imp[0].banner.format.map((fm, i) => { + return Object.assign(fm, { + ext: { + ttx: { + bidfloors: [ floors[i] ] + } + } + }) + }); + + ttxRequest.imp[0].banner.format = format; + + return this; + }; + this.build = () => ttxRequest; } function ServerRequestBuilder() { const serverRequest = { 'method': 'POST', - 'url': END_POINT, + 'url': `${END_POINT}?guid=${SITE_ID}`, 'data': null, 'options': { 'contentType': 'text/plain', @@ -320,7 +365,7 @@ describe('33acrossBidAdapter:', function () { context('when width or height of the element is zero', function() { it('try to use alternative values', function() { const ttxRequest = new TtxRequestBuilder() - .withSizes([{ w: 800, h: 2400, ext: {} }]) + .withSizes([{ w: 800, h: 2400 }]) .withViewability({amount: 25}) .build(); const serverRequest = new ServerRequestBuilder() @@ -454,6 +499,84 @@ describe('33acrossBidAdapter:', function () { }); }); + context('when us_privacy consent data exists', function() { + let bidderRequest; + + beforeEach(function() { + bidderRequest = { + uspConsent: 'foo' + } + }); + + it('returns corresponding server requests with us_privacy consent data', function() { + const ttxRequest = new TtxRequestBuilder() + .withUspConsent('foo') + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + const builtServerRequests = spec.buildRequests(bidRequests, bidderRequest); + + expect(builtServerRequests).to.deep.equal([serverRequest]); + }); + + it('returns corresponding test server requests with us_privacy consent data', function() { + sandbox.stub(config, 'getConfig').callsFake(() => { + return { + 'url': 'https://foo.com/hb/' + } + }); + + const ttxRequest = new TtxRequestBuilder() + .withUspConsent('foo') + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .withUrl('https://foo.com/hb/') + .build(); + const builtServerRequests = spec.buildRequests(bidRequests, bidderRequest); + + expect(builtServerRequests).to.deep.equal([serverRequest]); + }); + }); + + context('when us_privacy consent data does not exist', function() { + let bidderRequest; + + beforeEach(function() { + bidderRequest = {}; + }); + + it('returns corresponding server requests with default us_privacy data', function() { + const ttxRequest = new TtxRequestBuilder() + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + const builtServerRequests = spec.buildRequests(bidRequests, bidderRequest); + + expect(builtServerRequests).to.deep.equal([serverRequest]); + }); + + it('returns corresponding test server requests with default us_privacy consent data', function() { + sandbox.stub(config, 'getConfig').callsFake(() => { + return { + 'url': 'https://foo.com/hb/' + } + }); + + const ttxRequest = new TtxRequestBuilder() + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .withUrl('https://foo.com/hb/') + .build(); + const builtServerRequests = spec.buildRequests(bidRequests, bidderRequest); + + expect(builtServerRequests).to.deep.equal([serverRequest]); + }); + }); + context('when referer value is available', function() { it('returns corresponding server requests with site.page set', function() { const bidderRequest = { @@ -492,6 +615,125 @@ describe('33acrossBidAdapter:', function () { expect(builtServerRequests).to.deep.equal([serverRequest]); }); }); + + context('when there is schain object in the bidRequest', function() { + it('builds request with schain info in source', function() { + const schainValues = [ + { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'bidderA.com', + 'sid': '00001', + 'hp': 1 + } + ] + }, + { + 'ver': '1.0', + 'complete': 1, + }, + { + 'ver': '1.0', + 'complete': 1, + 'nodes': [] + }, + { + 'ver': '1.0', + 'complete': '1', + 'nodes': [ + { + 'asi': 'bidderA.com', + 'sid': '00001', + 'hp': 1 + } + ] + } + ]; + + schainValues.forEach((schain) => { + bidRequests[0].schain = schain; + + const ttxRequest = new TtxRequestBuilder() + .withSchain(schain) + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + + const builtServerRequests = spec.buildRequests(bidRequests, {}); + + expect(builtServerRequests).to.deep.equal([serverRequest]); + }); + }); + }); + + context('when there no schain object is passed', function() { + it('does not set source field', function() { + const ttxRequest = new TtxRequestBuilder() + .build(); + + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + + const builtServerRequests = spec.buildRequests(bidRequests, {}); + + expect(builtServerRequests).to.deep.equal([serverRequest]); + }); + }); + + context('when price floor module is not enabled in bidRequest', function() { + it('does not set any bidfloors in ttxRequest', function() { + const ttxRequest = new TtxRequestBuilder() + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + const builtServerRequests = spec.buildRequests(bidRequests, {}); + + expect(builtServerRequests).to.deep.equal([serverRequest]); + }); + }); + + context('when price floor module is enabled in bidRequest', function() { + it('does not set any bidfloors in ttxRequest if there is no floor', function() { + bidRequests[0].getFloor = () => ({}); + + const ttxRequest = new TtxRequestBuilder() + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + const builtServerRequests = spec.buildRequests(bidRequests, {}); + + expect(builtServerRequests).to.deep.equal([serverRequest]); + }); + + it('sets bidfloors in ttxRequest if there is a floor', function() { + bidRequests[0].getFloor = ({size, currency, mediaType}) => { + const floor = (size[0] === 300 && size[1] === 250) ? 1.0 : 0.10 + return ( + { + floor, + currency: 'USD' + } + ); + }; + + const ttxRequest = new TtxRequestBuilder() + .withFormatFloors([ 1.0, 0.10 ]) + .build(); + + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + const builtServerRequests = spec.buildRequests(bidRequests, {}); + + expect(builtServerRequests).to.deep.equal([serverRequest]); + }); + }); }); describe('interpretResponse', function() { @@ -693,11 +935,11 @@ describe('33acrossBidAdapter:', function () { const expectedSyncs = [ { type: 'iframe', - url: `${syncs[0].url}&gdpr_consent=undefined` + url: `${syncs[0].url}&gdpr_consent=undefined&us_privacy=undefined` }, { type: 'iframe', - url: `${syncs[1].url}&gdpr_consent=undefined` + url: `${syncs[1].url}&gdpr_consent=undefined&us_privacy=undefined` } ] @@ -713,11 +955,11 @@ describe('33acrossBidAdapter:', function () { const expectedSyncs = [ { type: 'iframe', - url: `${syncs[0].url}&gdpr_consent=undefined&gdpr=1` + url: `${syncs[0].url}&gdpr_consent=undefined&us_privacy=undefined&gdpr=1` }, { type: 'iframe', - url: `${syncs[1].url}&gdpr_consent=undefined&gdpr=1` + url: `${syncs[1].url}&gdpr_consent=undefined&us_privacy=undefined&gdpr=1` } ]; @@ -733,11 +975,11 @@ describe('33acrossBidAdapter:', function () { const expectedSyncs = [ { type: 'iframe', - url: `${syncs[0].url}&gdpr_consent=consent123A&gdpr=1` + url: `${syncs[0].url}&gdpr_consent=consent123A&us_privacy=undefined&gdpr=1` }, { type: 'iframe', - url: `${syncs[1].url}&gdpr_consent=consent123A&gdpr=1` + url: `${syncs[1].url}&gdpr_consent=consent123A&us_privacy=undefined&gdpr=1` } ]; @@ -753,11 +995,11 @@ describe('33acrossBidAdapter:', function () { const expectedSyncs = [ { type: 'iframe', - url: `${syncs[0].url}&gdpr_consent=undefined&gdpr=0` + url: `${syncs[0].url}&gdpr_consent=undefined&us_privacy=undefined&gdpr=0` }, { type: 'iframe', - url: `${syncs[1].url}&gdpr_consent=undefined&gdpr=0` + url: `${syncs[1].url}&gdpr_consent=undefined&us_privacy=undefined&gdpr=0` } ]; expect(syncResults).to.deep.equal(expectedSyncs); @@ -772,11 +1014,11 @@ describe('33acrossBidAdapter:', function () { const expectedSyncs = [ { type: 'iframe', - url: `${syncs[0].url}&gdpr_consent=consent123A` + url: `${syncs[0].url}&gdpr_consent=consent123A&us_privacy=undefined` }, { type: 'iframe', - url: `${syncs[1].url}&gdpr_consent=consent123A` + url: `${syncs[1].url}&gdpr_consent=consent123A&us_privacy=undefined` } ]; expect(syncResults).to.deep.equal(expectedSyncs); @@ -791,16 +1033,64 @@ describe('33acrossBidAdapter:', function () { const expectedSyncs = [ { type: 'iframe', - url: `${syncs[0].url}&gdpr_consent=consent123A&gdpr=0` + url: `${syncs[0].url}&gdpr_consent=consent123A&us_privacy=undefined&gdpr=0` + }, + { + type: 'iframe', + url: `${syncs[1].url}&gdpr_consent=consent123A&us_privacy=undefined&gdpr=0` + } + ]; + expect(syncResults).to.deep.equal(expectedSyncs); + }); + }); + + context('when there is no usPrivacy data', function() { + it('returns sync urls with undefined consent string as param', function() { + spec.buildRequests(bidRequests); + + const syncResults = spec.getUserSyncs(syncOptions, {}); + const expectedSyncs = [ + { + type: 'iframe', + url: `${syncs[0].url}&gdpr_consent=undefined&us_privacy=undefined` + }, + { + type: 'iframe', + url: `${syncs[1].url}&gdpr_consent=undefined&us_privacy=undefined` + } + ] + + expect(syncResults).to.deep.equal(expectedSyncs); + }) + }); + + context('when there is usPrivacy data', function() { + it('returns sync urls with consent string as param', function() { + spec.buildRequests(bidRequests); + + const syncResults = spec.getUserSyncs(syncOptions, {}, {}, 'foo'); + const expectedSyncs = [ + { + type: 'iframe', + url: `${syncs[0].url}&gdpr_consent=undefined&us_privacy=foo` }, { type: 'iframe', - url: `${syncs[1].url}&gdpr_consent=consent123A&gdpr=0` + url: `${syncs[1].url}&gdpr_consent=undefined&us_privacy=foo` } ]; + expect(syncResults).to.deep.equal(expectedSyncs); }); }); + + context('when user sync is invoked without a bid request phase', function() { + it('results in an empty syncs array', function() { + const syncResults = spec.getUserSyncs(syncOptions, {}, {}, 'foo'); + + expect(syncResults).to.deep.equal([]); + }); + }); }); }); }); diff --git a/test/spec/modules/a4gBidAdapter_spec.js b/test/spec/modules/a4gBidAdapter_spec.js new file mode 100644 index 00000000000..3dccbb28426 --- /dev/null +++ b/test/spec/modules/a4gBidAdapter_spec.js @@ -0,0 +1,173 @@ +import { expect } from 'chai'; +import { spec } from 'modules/a4gBidAdapter.js'; + +describe('a4gAdapterTests', function () { + describe('bidRequestValidity', function () { + it('bidRequest with zoneId and deliveryUrl params', function () { + expect(spec.isBidRequestValid({ + bidder: 'a4g', + params: { + zoneId: 59304, + deliveryUrl: 'http://dev01.ad4game.com/v1/bid' + } + })).to.equal(true); + }); + + it('bidRequest with only zoneId', function () { + expect(spec.isBidRequestValid({ + bidder: 'a4g', + params: { + zoneId: 59304 + } + })).to.equal(true); + }); + + it('bidRequest with only deliveryUrl', function () { + expect(spec.isBidRequestValid({ + bidder: 'a4g', + params: { + deliveryUrl: 'http://dev01.ad4game.com/v1/bid' + } + })).to.equal(false); + }); + }); + + describe('bidRequest', function () { + const DEFAULT_OPTION = { + refererInfo: { + referer: 'https://www.prebid.org', + canonicalUrl: 'https://www.prebid.org/the/link/to/the/page' + } + }; + + const bidRequests = [{ + 'bidder': 'a4g', + 'bidId': '51ef8751f9aead', + 'params': { + 'zoneId': 59304, + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 50], [300, 250], [300, 600]] + } + }, + 'sizes': [[320, 50], [300, 250], [300, 600]], + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757' + }, { + 'bidder': 'a4g', + 'bidId': '51ef8751f9aead', + 'params': { + 'zoneId': 59354, + 'deliveryUrl': '//dev01.ad4game.com/v1/bid' + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 50], [300, 250], [300, 600]] + } + }, + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757' + }]; + + it('bidRequest method', function () { + const request = spec.buildRequests(bidRequests, DEFAULT_OPTION); + expect(request.method).to.equal('GET'); + }); + + it('bidRequest url', function () { + const request = spec.buildRequests(bidRequests, DEFAULT_OPTION); + expect(request.url).to.match(new RegExp(`${bidRequests[1].params.deliveryUrl}`)); + }); + + it('bidRequest data', function () { + const request = spec.buildRequests(bidRequests, DEFAULT_OPTION); + expect(request.data).to.exist; + }); + + it('bidRequest zoneIds', function () { + const request = spec.buildRequests(bidRequests, DEFAULT_OPTION); + expect(request.data.zoneId).to.equal('59304;59354'); + }); + + it('bidRequest gdpr consent', function () { + const consentString = 'consentString'; + const bidderRequest = { + bidderCode: 'a4g', + auctionId: '18fd8b8b0bd757', + bidderRequestId: '418b37f85e772c', + timeout: 3000, + gdprConsent: { + consentString: consentString, + gdprApplies: true + }, + refererInfo: { + referer: 'https://www.prebid.org', + canonicalUrl: 'https://www.prebid.org/the/link/to/the/page' + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequest); + + expect(request.data.gdpr).to.exist; + expect(request.data.gdpr.applies).to.exist.and.to.be.true; + expect(request.data.gdpr.consent).to.exist.and.to.equal(consentString); + }); + }); + + describe('interpretResponse', function () { + const bidRequest = [{ + 'bidder': 'a4g', + 'bidId': '51ef8751f9aead', + 'params': { + 'zoneId': 59304, + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 50], [300, 250], [300, 600]] + } + }, + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757' + }]; + + const bidResponse = { + body: [{ + 'id': 'div-gpt-ad-1460505748561-0', + 'ad': 'test ad', + 'width': 320, + 'height': 250, + 'cpm': 5.2 + }], + headers: {} + }; + + it('required keys', function () { + const result = spec.interpretResponse(bidResponse, bidRequest); + + let requiredKeys = [ + 'requestId', + 'creativeId', + 'adId', + 'cpm', + 'width', + 'height', + 'currency', + 'netRevenue', + 'ttl', + 'ad' + ]; + + let resultKeys = Object.keys(result[0]); + resultKeys.forEach(function(key) { + expect(requiredKeys.indexOf(key) !== -1).to.equal(true); + }); + }) + }); +}); diff --git a/test/spec/modules/ablidaBidAdapter_spec.js b/test/spec/modules/ablidaBidAdapter_spec.js index ca4fd4ab0be..73109d8cf16 100644 --- a/test/spec/modules/ablidaBidAdapter_spec.js +++ b/test/spec/modules/ablidaBidAdapter_spec.js @@ -1,6 +1,7 @@ import {assert, expect} from 'chai'; import {spec} from 'modules/ablidaBidAdapter.js'; import {newBidder} from 'src/adapters/bidderFactory.js'; +import * as utils from 'src/utils.js'; const ENDPOINT_URL = 'https://bidder.ablida.net/prebid'; @@ -8,17 +9,23 @@ describe('ablidaBidAdapter', function () { const adapter = newBidder(spec); describe('isBidRequestValid', function () { let bid = { + adUnitCode: 'adunit-code', + auctionId: '69e8fef8-5105-4a99-b011-d5669f3bc7f0', + bidRequestsCount: 1, bidder: 'ablida', + bidderRequestId: '14d2939272a26a', + bidderRequestsCount: 1, + bidderWinsCount: 0, + bidId: '1234asdf1234', + mediaTypes: {banner: {sizes: [[300, 250]]}}, params: { placementId: 123 }, - adUnitCode: 'adunit-code', sizes: [ [300, 250] ], - bidId: '1234asdf1234', - bidderRequestId: '1234asdf1234asdf', - auctionId: '69e8fef8-5105-4a99-b011-d5669f3bc7f0' + src: 'client', + transactionId: '4781e6ac-93c4-42ba-86fe-ab5f278863cf' }; it('should return true where required params found', function () { expect(spec.isBidRequestValid(bid)).to.equal(true); @@ -27,22 +34,29 @@ describe('ablidaBidAdapter', function () { describe('buildRequests', function () { let bidRequests = [ { + adUnitCode: 'adunit-code', + auctionId: '69e8fef8-5105-4a99-b011-d5669f3bc7f0', + bidId: '23beaa6af6cdde', + bidRequestsCount: 1, bidder: 'ablida', + bidderRequestId: '14d2939272a26a', + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: {banner: {sizes: [[300, 250]]}}, params: { placementId: 123 }, sizes: [ [300, 250] ], - adUnitCode: 'adunit-code', - bidId: '23beaa6af6cdde', - bidderRequestId: '14d2939272a26a', - auctionId: '69e8fef8-5105-4a99-b011-d5669f3bc7f0', + src: 'client', + transactionId: '4781e6ac-93c4-42ba-86fe-ab5f278863cf' } ]; let bidderRequests = { refererInfo: { + canonicalUrl: '', numIframes: 0, reachedTop: true, referer: 'http://example.com', @@ -61,42 +75,77 @@ describe('ablidaBidAdapter', function () { method: 'POST', url: ENDPOINT_URL, data: { + adapterVersion: 5, + bidId: '2b8c4de0116e54', + categories: undefined, + device: 'desktop', + gdprConsent: undefined, + jaySupported: true, + mediaTypes: {banner: {sizes: [[300, 250]]}}, placementId: 'testPlacementId', width: 300, height: 200, - bidId: '2b8c4de0116e54', - jaySupported: true, - device: 'desktop', referer: 'www.example.com' } }; let serverResponse = { body: [{ - requestId: '2b8c4de0116e54', + ad: '', cpm: 1.00, - width: 300, - height: 250, creativeId: '2b8c4de0116e54', currency: 'EUR', + height: 250, + mediaType: 'banner', + meta: {}, netRevenue: true, + nurl: 'https://example.com/some-tracker', + originalCpm: '0.10', + originalCurrency: 'EUR', + requestId: '2b8c4de0116e54', ttl: 3000, - ad: '' + width: 300 }] }; it('should get the correct bid response', function () { let expectedResponse = [{ - requestId: '2b8c4de0116e54', + ad: '', cpm: 1.00, - width: 300, - height: 250, creativeId: '2b8c4de0116e54', currency: 'EUR', + height: 250, + mediaType: 'banner', + meta: {}, netRevenue: true, + nurl: 'https://example.com/some-tracker', + originalCpm: '0.10', + originalCurrency: 'EUR', + requestId: '2b8c4de0116e54', ttl: 3000, - ad: '' + width: 300 }]; let result = spec.interpretResponse(serverResponse, bidRequest[0]); expect(Object.keys(result)).to.deep.equal(Object.keys(expectedResponse)); }); }); + + describe('onBidWon', function() { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + + it('Should not trigger pixel if bid does not contain nurl', function() { + const result = spec.onBidWon({}); + expect(utils.triggerPixel.callCount).to.equal(0) + }) + + it('Should trigger pixel if bid nurl', function() { + const result = spec.onBidWon({ + nurl: 'https://example.com/some-tracker' + }); + expect(utils.triggerPixel.callCount).to.equal(1) + }) + }) }); diff --git a/test/spec/modules/adWMGAnalyticsAdapter_spec.js b/test/spec/modules/adWMGAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..ab8336c7126 --- /dev/null +++ b/test/spec/modules/adWMGAnalyticsAdapter_spec.js @@ -0,0 +1,176 @@ +import adWMGAnalyticsAdapter from 'modules/adWMGAnalyticsAdapter.js'; +import { expect } from 'chai'; +import { server } from 'test/mocks/xhr.js'; +let adapterManager = require('src/adapterManager').default; +let events = require('src/events'); +let constants = require('src/constants.json'); + +describe('adWMG Analytics', function () { + let timestamp = new Date() - 256; + let auctionId = '5018eb39-f900-4370-b71e-3bb5b48d324f'; + let timeout = 1500; + + let bidTimeoutArgs = [ + { + bidId: '2baa51527bd015', + bidder: 'bidderA', + adUnitCode: '/19968336/header-bid-tag-0', + auctionId: '66529d4c-8998-47c2-ab3e-5b953490b98f' + }, + { + bidId: '6fe3b4c2c23092', + bidder: 'bidderB', + adUnitCode: '/19968336/header-bid-tag-0', + auctionId: '66529d4c-8998-47c2-ab3e-5b953490b98f' + } + ]; + + const bidResponse = { + bidderCode: 'bidderA', + adId: '208750227436c1', + mediaTypes: ['banner'], + cpm: 0.015, + auctionId: auctionId, + responseTimestamp: 1509369418832, + requestTimestamp: 1509369418389, + bidder: 'bidderA', + timeToRespond: 443, + size: '300x250', + width: 300, + height: 250, + }; + + let wonRequest = { + 'adId': '4587fec4900b81', + 'mediaType': 'banner', + 'requestId': '4587fec4900b81', + 'cpm': 1.962, + 'creativeId': 2126, + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 302, + 'auctionId': '914bedad-b145-4e46-ba58-51365faea6cb', + 'statusMessage': 'Bid available', + 'responseTimestamp': 1530628534437, + 'requestTimestamp': 1530628534219, + 'bidder': 'bidderB', + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'sizes': [[300, 250]], + 'size': [300, 250], + }; + + let expectedBidWonData = { + publisher_id: '5abd0543ba45723db49d97ea', + site: 'test.com', + ad_unit_size: ['300,250'], + ad_unit_type: ['banner'], + c_timeout: 1500, + events: [ + { + status: 'bidWon', + bids: [ + { + bidder: 'bidderB', + auction_id: '914bedad-b145-4e46-ba58-51365faea6cb', + ad_unit_code: 'div-gpt-ad-1438287399331-0', + transaction_id: '', + bid_size: ['300,250'], + bid_type: ['banner'], + time_ms: 256, + cur: 'USD', + price: '1.96', + cur_native: '', + price_native: '' + } + ] + } + ] + } + + let adUnits = [{ + code: 'ad-slot-1', + sizes: [[300, 250]], + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [ + { + bidder: 'bidderA', + params: { + placement: '1000' + } + }, + { + bidder: 'bidderB', + params: { + placement: '56656' + } + } + ] + }]; + + after(function () { + adWMGAnalyticsAdapter.disableAnalytics(); + }); + + describe('main test flow', function () { + beforeEach(function () { + sinon.stub(events, 'getEvents').returns([]); + }); + + afterEach(function () { + events.getEvents.restore(); + }); + + it('should catch all events', function () { + sinon.spy(adWMGAnalyticsAdapter, 'track'); + + adapterManager.registerAnalyticsAdapter({ + code: 'adWMG', + adapter: adWMGAnalyticsAdapter + }); + + adapterManager.enableAnalytics({ + provider: 'adWMG', + options: { + site: 'test.com', + publisher_id: '5abd0543ba45723db49d97ea' + } + }); + + events.emit(constants.EVENTS.AUCTION_INIT, {timestamp, auctionId, timeout, adUnits}); + events.emit(constants.EVENTS.BID_REQUESTED, {}); + events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + events.emit(constants.EVENTS.NO_BID, {}); + events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeoutArgs); + events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(constants.EVENTS.BID_WON, wonRequest); + sinon.assert.callCount(adWMGAnalyticsAdapter.track, 7); + }); + + it('should be two xhr requests', function () { + events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(constants.EVENTS.BID_WON, wonRequest); + expect(server.requests.length).to.equal(2); + }); + + it('second request should be bidWon', function () { + events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(constants.EVENTS.BID_WON, wonRequest); + expect(JSON.parse(server.requests[1].requestBody).events[0].status).to.equal(expectedBidWonData.events[0].status); + }); + + it('check bidWon data', function () { + events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(constants.EVENTS.BID_WON, wonRequest); + let realBidWonData = JSON.parse(server.requests[1].requestBody); + expect(realBidWonData.publisher_id).to.equal(expectedBidWonData.publisher_id); + expect(realBidWonData.site).to.equal(expectedBidWonData.site); + expect(realBidWonData.ad_unit_type[0]).to.equal(expectedBidWonData.ad_unit_type[0]); + expect(realBidWonData.ad_unit_size[0]).to.equal(expectedBidWonData.ad_unit_size[0]); + expect(realBidWonData.events[0].bids[0].bidder).to.equal(expectedBidWonData.events[0].bids[0].bidder); + }); + }); +}); diff --git a/test/spec/modules/adagioBidAdapter_spec.js b/test/spec/modules/adagioBidAdapter_spec.js index 8996b288576..a18cd797d68 100644 --- a/test/spec/modules/adagioBidAdapter_spec.js +++ b/test/spec/modules/adagioBidAdapter_spec.js @@ -1,665 +1,645 @@ +import find from 'core-js-pure/features/array/find.js'; import { expect } from 'chai'; -import { adagioScriptFromLocalStorageCb, spec } from 'modules/adagioBidAdapter.js'; -import { newBidder } from 'src/adapters/bidderFactory.js'; -import * as utils from 'src/utils.js'; - -describe('adagioAdapter', () => { - let utilsMock; - const adapter = newBidder(spec); - const ENDPOINT = 'https://mp.4dex.io/prebid'; - const VERSION = '2.2.1'; +import { _features, internal as adagio, adagioScriptFromLocalStorageCb, getAdagioScript, storage, spec, ENDPOINT, VERSION } from '../../../modules/adagioBidAdapter.js'; +import { loadExternalScript } from '../../../src/adloader.js'; +import * as utils from '../../../src/utils.js'; +import { config } from 'src/config.js'; + +const BidRequestBuilder = function BidRequestBuilder(options) { + const defaults = { + request: { + auctionId: '4fd1ca2d-846c-4211-b9e5-321dfe1709c9', + adUnitCode: 'adunit-code', + bidder: 'adagio' + }, + params: { + organizationId: '1000', + placement: 'PAVE_ATF', + site: 'SITE-NAME', + adUnitElementId: 'gpt-adunit-code' + }, + sizes: [[300, 250], [300, 600]], + }; + + const request = { + ...defaults.request, + ...options + }; + + this.withParams = (options) => { + request.params = { + ...defaults.params, + ...options + }; + return this; + }; + + this.build = () => request; +}; + +const BidderRequestBuilder = function BidderRequestBuilder(options) { + const defaults = { + bidderCode: 'adagio', + auctionId: '4fd1ca2d-846c-4211-b9e5-321dfe1709c9', + bidderRequestId: '7g36s867Tr4xF90X', + timeout: 3000, + refererInfo: { + numIframes: 0, + reachedTop: true, + referer: 'http://test.io/index.html?pbjs_debug=true' + } + }; - beforeEach(function() { - localStorage.removeItem('adagioScript'); - utilsMock = sinon.mock(utils); - }); + const request = { + ...defaults, + ...options + }; - afterEach(function() { - utilsMock.restore(); - }); + this.build = () => request; +}; - describe('inherited functions', () => { - it('exists and is a function', () => { - expect(adapter.callBids).to.exist.and.to.be.a('function'); - }); - }); +describe('Adagio bid adapter', () => { + let adagioMock; + let utilsMock; + let sandbox; + + const fixtures = { + getElementById(width, height, x, y) { + const obj = { + x: x || 800, + y: y || 300, + width: width || 300, + height: height || 250, + }; - describe('isBidRequestValid', () => { - let sandbox; - beforeEach(function () { - sandbox = sinon.sandbox.create(); - let element = { - x: 0, - y: 0, - width: 200, - height: 300, + return { + ...obj, getBoundingClientRect: () => { return { - width: element.width, - height: element.height, - left: element.x, - top: element.y, - right: element.x + element.width, - bottom: element.y + element.height + width: obj.width, + height: obj.height, + left: obj.x, + top: obj.y, + right: obj.x + obj.width, + bottom: obj.y + obj.height }; } }; - sandbox.stub(document, 'getElementById').withArgs('banner-atf').returns(element); - }); + } + }; - afterEach(function () { - sandbox.restore(); - }); + // safeFrame implementation + const $sf = { + ext: { + geom: function() {} + } + }; + + beforeEach(() => { + window.ADAGIO = {}; + window.ADAGIO.adUnits = {}; + window.ADAGIO.pbjsAdUnits = []; + window.ADAGIO.queue = []; + window.ADAGIO.versions = {}; + window.ADAGIO.versions.adagioBidderAdapter = VERSION; + window.ADAGIO.pageviewId = 'dda61753-4059-4f75-b0bf-3f60bd2c4d9a'; + + adagioMock = sinon.mock(adagio); + utilsMock = sinon.mock(utils); - let bid = { - 'bidder': 'adagio', - 'params': { - organizationId: '0', - placement: 'PAVE_ATF', - site: 'SITE-NAME', - pagetype: 'ARTICLE', - adUnitElementId: 'banner-atf' - }, - 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250], [300, 600]], - 'bidId': 'c180kg4267tyqz', - 'bidderRequestId': '8vfscuixrovn8i', - 'auctionId': 'lel4fhp239i9km', - }; + sandbox = sinon.sandbox.create(); + }); - let bidWithMediaTypes = { - 'bidder': 'adagio', - 'params': { - organizationId: '0', - placement: 'PAVE_ATF', - site: 'SITE-NAME', - pagetype: 'ARTICLE', - adUnitElementId: 'banner-atf' - }, - 'adUnitCode': 'adunit-code-2', - 'mediaTypes': { - banner: { - sizes: [[300, 250]], - } - }, - sizes: [[300, 600]], - 'bidId': 'c180kg4267tyqz', - 'bidderRequestId': '8vfscuixrovn8i', - 'auctionId': 'lel4fhp239i9km', - } + afterEach(() => { + window.ADAGIO = undefined; - it('should return true when required params found', () => { - expect(spec.isBidRequestValid(bid)).to.equal(true); - expect(window.top.ADAGIO.adUnits['adunit-code'].printNumber).to.equal(1); - }) + adagioMock.restore(); + utilsMock.restore(); - it('should compute a printNumber for the new bid request on same adUnitCode and same pageviewId', () => { - spec.isBidRequestValid(bid); - expect(window.top.ADAGIO.adUnits).ok; - expect(window.top.ADAGIO.adUnits['adunit-code']).ok; - expect(window.top.ADAGIO.adUnits['adunit-code'].printNumber).to.equal(2); + sandbox.restore(); + }); - spec.isBidRequestValid(bid); - expect(window.top.ADAGIO.adUnits['adunit-code'].printNumber).to.equal(3); + describe('isBidRequestValid()', function() { + it('should return true when required params have been found', function() { + const bid = new BidRequestBuilder().withParams().build(); - window.top.ADAGIO.pageviewId = 123; - spec.isBidRequestValid(bid); - expect(window.top.ADAGIO.adUnits['adunit-code'].printNumber).to.equal(1); + expect(spec.isBidRequestValid(bid)).to.equal(true); }); - it('should return false when organization params is not passed', () => { - let bidTest = Object.assign({}, bid); - delete bidTest.params.organizationId; - expect(spec.isBidRequestValid(bidTest)).to.equal(false); - }); + it('should return false if bid.params is missing', function() { + sandbox.spy(utils, 'logWarn'); + const bid01 = new BidRequestBuilder().build(); - it('should return false when site params is not passed', () => { - let bidTest = Object.assign({}, bid); - delete bidTest.params.site; - expect(spec.isBidRequestValid(bidTest)).to.equal(false); + expect(spec.isBidRequestValid(bid01)).to.equal(false); + sinon.assert.callCount(utils.logWarn, 1); }); - it('should return false when placement params is not passed', () => { - let bidTest = Object.assign({}, bid); - delete bidTest.params.placement; - expect(spec.isBidRequestValid(bidTest)).to.equal(false); - }); + it('should return false when a required param is missing', function() { + const bid01 = new BidRequestBuilder({ params: { + organizationId: '1000', + placement: 'PAVE_ATF' + }}).build(); + + const bid02 = new BidRequestBuilder({ params: { + organizationId: '1000', + site: 'SITE-NAME' + }}).build(); - it('should return false when adUnit element id params is not passed', () => { - let bidTest = Object.assign({}, bid); - delete bidTest.params.adUnitElementId; - expect(spec.isBidRequestValid(bidTest)).to.equal(false); + const bid03 = new BidRequestBuilder({ params: { + placement: 'PAVE_ATF', + site: 'SITE-NAME' + }}).build(); + + expect(spec.isBidRequestValid(bid01)).to.equal(false); + expect(spec.isBidRequestValid(bid02)).to.equal(false); + expect(spec.isBidRequestValid(bid03)).to.equal(false); }); - it('should return false if not in the window.top', () => { - sandbox.stub(utils, 'getWindowTop').throws(); + it('should return false when refererInfo.reachedTop is false', function() { + sandbox.spy(utils, 'logWarn'); + sandbox.stub(adagio, 'getRefererInfo').returns({ reachedTop: false }); + const bid = new BidRequestBuilder().withParams().build(); + expect(spec.isBidRequestValid(bid)).to.equal(false); + sinon.assert.callCount(utils.logWarn, 1); + sinon.assert.calledWith(utils.logWarn, 'Adagio: the main page url is unreachabled.'); }); - it('should expose ADAGIO.pbjsAdUnits in window', () => { - spec.isBidRequestValid(bidWithMediaTypes); + it('should log warning and enqueue the bid object in ADAGIO.queue when isBidRequestValid is false', function() { + sandbox.stub(Date, 'now').returns(12345); + sandbox.spy(utils, 'logWarn'); + sandbox.spy(adagio, 'enqueue'); + + const bid = new BidRequestBuilder({'params': { + organizationId: '1000', + placement: 'PAVE_ATF' + }}).build(); + + const expectedEnqueued = { + action: 'pb-dbg', + ts: 12345, + data: { bid } + }; + spec.isBidRequestValid(bid); - expect(window.top.ADAGIO.pbjsAdUnits).ok; - expect(window.top.ADAGIO.pbjsAdUnits).to.have.lengthOf(2); - const adUnitWithMediaTypeSizes = window.top.ADAGIO.pbjsAdUnits.filter((aU) => aU.code === 'adunit-code-2')[0]; - const adUnitWithSizes = window.top.ADAGIO.pbjsAdUnits.filter((aU) => aU.code === 'adunit-code')[0]; - expect(adUnitWithMediaTypeSizes.sizes).to.eql([[300, 250]]); - expect(adUnitWithSizes.sizes).to.eql([[300, 250], [300, 600]]); + + sinon.assert.calledWith(adagio.enqueue, expectedEnqueued); + sinon.assert.callCount(utils.logWarn, 1); }); - }); - describe('buildRequests', () => { - const sandbox = sinon.createSandbox(); + describe('Store ADAGIO global in window.top or window.self depending on context', function() { + const bid01 = new BidRequestBuilder({ + adUnitCode: 'adunit-code-01', + sizes: [[300, 250], [300, 600]] + }).withParams().build(); - const banner300x250 = { - x: 0, - y: 0, - width: 300, - height: 250, - getBoundingClientRect: () => { - return { - width: banner300x250.width, - height: banner300x250.height, - left: banner300x250.x, - top: banner300x250.y, - right: banner300x250.x + banner300x250.width, - bottom: banner300x250.y + banner300x250.height - }; - }, - }; + const bid02 = new BidRequestBuilder({ + adUnitCode: 'adunit-code-02', + mediaTypes: { + banner: { sizes: [[300, 250]] } + }, + }).withParams().build(); - const banner300x600 = { - x: 0, - y: 0, - width: 300, - height: 600, - getBoundingClientRect: () => { - return { - width: banner300x600.width, - height: banner300x600.height, - left: banner300x600.x, - top: banner300x600.y, - right: banner300x600.x + banner300x600.width, - bottom: banner300x600.y + banner300x600.height - }; - }, - }; + const bid03 = new BidRequestBuilder({ + adUnitCode: 'adunit-code-02', + mediaTypes: { + banner: { sizes: [[300, 600]] } + }, + }).withParams().build(); + + const expected = [ + { + code: 'adunit-code-01', + sizes: [[300, 250], [300, 600]], + mediaTypes: {}, + bids: [{ + bidder: 'adagio', + params: { + organizationId: '1000', + placement: 'PAVE_ATF', + site: 'SITE-NAME', + adUnitElementId: 'gpt-adunit-code', + environment: 'desktop' + } + }], + auctionId: '4fd1ca2d-846c-4211-b9e5-321dfe1709c9', + pageviewId: 'dda61753-4059-4f75-b0bf-3f60bd2c4d9a', + printNumber: 1, + }, + { + code: 'adunit-code-02', + sizes: [[300, 600]], + mediaTypes: { + banner: { sizes: [[300, 600]] } + }, + bids: [{ + bidder: 'adagio', + params: { + organizationId: '1000', + placement: 'PAVE_ATF', + site: 'SITE-NAME', + adUnitElementId: 'gpt-adunit-code', + environment: 'desktop' + } + }], + auctionId: '4fd1ca2d-846c-4211-b9e5-321dfe1709c9', + pageviewId: 'dda61753-4059-4f75-b0bf-3f60bd2c4d9a', + printNumber: 2, + } + ]; - const computedStyleBlock = { - display: 'block' - }; + it('should store bids config once by bid in window.top if it accessible', function() { + sandbox.stub(adagio, 'getCurrentWindow').returns(window.top); - const computedStyleNone = { - display: 'none' - }; + // replace by the values defined in beforeEach + window.top.ADAGIO = { + ...window.ADAGIO + } - const stubs = { - topGetElementById: undefined, - topGetComputedStyle: undefined - } + spec.isBidRequestValid(bid01); + spec.isBidRequestValid(bid02); + spec.isBidRequestValid(bid03); - top.ADAGIO = top.ADAGIO || {}; - top.ADAGIO.adUnits = top.ADAGIO.adUnits || {}; - top.ADAGIO.pbjsAdUnits = top.ADAGIO.pbjsAdUnits || []; + expect(find(window.top.ADAGIO.pbjsAdUnits, aU => aU.code === 'adunit-code-01')).to.deep.eql(expected[0]); + expect(find(window.top.ADAGIO.pbjsAdUnits, aU => aU.code === 'adunit-code-02')).to.deep.eql(expected[1]); + }); - beforeEach(function () { - stubs.topGetElementById = sandbox.stub(top.document, 'getElementById'); - stubs.topGetComputedStyle = sandbox.stub(top, 'getComputedStyle'); + it('should store bids config once by bid in current window', function() { + sandbox.stub(adagio, 'getCurrentWindow').returns(window.self); - stubs.topGetElementById.withArgs('banner-atf-123').returns(banner300x250); - stubs.topGetElementById.withArgs('banner-atf-456').returns(banner300x600); - stubs.topGetElementById.withArgs('does-not-exist').returns(null); - stubs.topGetComputedStyle.returns(computedStyleBlock); - }); + spec.isBidRequestValid(bid01); + spec.isBidRequestValid(bid02); + spec.isBidRequestValid(bid03); - afterEach(function () { - sandbox.restore(); + expect(find(window.ADAGIO.pbjsAdUnits, aU => aU.code === 'adunit-code-01')).to.deep.eql(expected[0]); + expect(find(window.ADAGIO.pbjsAdUnits, aU => aU.code === 'adunit-code-02')).to.deep.eql(expected[1]); + }); }); + }); - after(function() { - sandbox.reset(); - }) - - let bidRequests = [ - { - 'bidder': 'adagio', - 'params': { - organizationId: '123', - site: 'ADAGIO-123', - placement: 'PAVE_ATF-123', - pagetype: 'ARTICLE', - adUnitElementId: 'banner-atf-123' - }, - 'adUnitCode': 'adunit-code1', - 'sizes': [[300, 250], [300, 600]], - 'bidId': 'c180kg4267tyqz', - 'bidderRequestId': '8vfscuixrovn8i', - 'auctionId': 'lel4fhp239i9km', - }, - { - 'bidder': 'adagio', - 'params': { - organizationId: '123', - site: 'ADAGIO-123', - placement: 'PAVE_ATF-123', - pagetype: 'ARTICLE', - adUnitElementId: 'banner-atf-123' - }, - 'adUnitCode': 'adunit-code2', - 'sizes': [[300, 250], [300, 600]], - 'bidId': 'c180kg4267tyqz', - 'bidderRequestId': '8vfscuixrovn8i', - 'auctionId': 'lel4fhp239i9km', - }, - { - 'bidder': 'adagio', - 'params': { - organizationId: '456', - site: 'ADAGIO-456', - placement: 'PAVE_ATF-456', - pagetype: 'ARTICLE', - adUnitElementId: 'banner-atf-456' - }, - 'adUnitCode': 'adunit-code3', - 'mediaTypes': { - banner: { - sizes: [[300, 250]] - } - }, - 'sizes': [[300, 250], [300, 600]], - 'bidId': 'c180kg4267tyqz', - 'bidderRequestId': '8vfscuixrovn8i', - 'auctionId': 'lel4fhp239i9km', - } + describe('buildRequests()', function() { + const expectedDataKeys = [ + 'id', + 'organizationId', + 'secure', + 'device', + 'site', + 'pageviewId', + 'adUnits', + 'regs', + 'schain', + 'prebidVersion', + 'adapterVersion', + 'featuresVersion' ]; - const bidRequestsWithPostBid = [ - { - 'bidder': 'adagio', - 'params': { - organizationId: '456', - site: 'ADAGIO-456', - placement: 'PAVE_ATF-456', - pagetype: 'ARTICLE', - adUnitElementId: 'banner-atf-456', - postBid: true - }, - 'adUnitCode': 'adunit-code3', - 'sizes': [[300, 250], [300, 600]], - 'bidId': 'c180kg4267tyqz', - 'bidderRequestId': '8vfscuixrovn8i', - 'auctionId': 'lel4fhp239i9km', - } - ]; + it('groups requests by organizationId', function() { + const bid01 = new BidRequestBuilder().withParams().build(); + const bid02 = new BidRequestBuilder().withParams().build(); + const bid03 = new BidRequestBuilder().withParams({ + organizationId: '1002' + }).build(); - let consentString = 'theConsentString'; - let bidderRequest = { - 'bidderCode': 'adagio', - 'auctionId': '12jejebn', - 'bidderRequestId': 'hehehehbeheh', - 'timeout': 3000, - 'gdprConsent': { - consentString: consentString, - gdprApplies: true, - allowAuctionWithoutConsent: true, - apiVersion: 1, - }, - 'refererInfo': { - 'numIframes': 0, - 'reachedTop': true, - 'referer': 'http://test.io/index.html?pbjs_debug=true' - } - }; + const bidderRequest = new BidderRequestBuilder().build(); - let bidderRequestTCF2 = { - 'bidderCode': 'adagio', - 'auctionId': '12jejebn', - 'bidderRequestId': 'hehehehbeheh', - 'timeout': 3000, - 'gdprConsent': { - consentString: consentString, - vendorData: { - tcString: consentString, - gdprApplies: true - }, - gdprApplies: true, - apiVersion: 2 - }, - 'refererInfo': { - 'numIframes': 0, - 'reachedTop': true, - 'referer': 'http://test.io/index.html?pbjs_debug=true' - } - }; + const requests = spec.buildRequests([bid01, bid02, bid03], bidderRequest); - it('groups requests by siteId', () => { - const requests = spec.buildRequests(bidRequests, bidderRequest); expect(requests).to.have.lengthOf(2); - expect(requests[0].data.organizationId).to.equal('123'); + expect(requests[0].data.organizationId).to.equal('1000'); expect(requests[0].data.adUnits).to.have.lengthOf(2); - expect(requests[1].data.organizationId).to.equal('456'); + expect(requests[1].data.organizationId).to.equal('1002'); expect(requests[1].data.adUnits).to.have.lengthOf(1); }); - it('sends bid request to ENDPOINT_PB via POST', () => { - const requests = spec.buildRequests(bidRequests, bidderRequest); - expect(requests).to.have.lengthOf(2); - const request = requests[0]; - expect(request.method).to.equal('POST'); - expect(request.url).to.equal(ENDPOINT); - expect(request.data.prebidVersion).to.equal('$prebid.version$'); - }); + it('should send bid request to ENDPOINT_PB via POST', function() { + sandbox.stub(adagio, 'getDevice').returns({ a: 'a' }); + sandbox.stub(adagio, 'getSite').returns({ domain: 'adagio.io', 'page': 'https://adagio.io/hb' }); + sandbox.stub(adagio, 'getPageviewId').returns('1234-567'); + sandbox.stub(adagio, 'getFeatures').returns({}); - it('features params "adunit_position" must be empty if adUnitElement is not found in the DOM', () => { - const requests = spec.buildRequests([Object.assign({}, bidRequests[0], {params: {adUnitElementId: 'does-not-exist'}})], bidderRequest); - const request = requests[0]; - expect(request.data.adUnits[0].features).to.exist; - expect(request.data.adUnits[0].features.adunit_position).to.deep.equal(''); - }); + const bid01 = new BidRequestBuilder().withParams().build(); + const bidderRequest = new BidderRequestBuilder().build(); - it('features params "adunit_position" should be computed even if DOM element is display:none', () => { - stubs.topGetComputedStyle.returns(computedStyleNone); - const requests = spec.buildRequests([Object.assign({}, bidRequests[0])], bidderRequest); - let request = requests[0]; - expect(request.data.adUnits[0].features).to.exist; - expect(request.data.adUnits[0].features.adunit_position).to.equal('0x0'); - }); + const requests = spec.buildRequests([bid01], bidderRequest); - it('features params "viewport" should be computed even if window.innerWidth is not supported', () => { - sandbox.stub(top, 'innerWidth').value(undefined); - const requests = spec.buildRequests([Object.assign({}, bidRequests[0])], bidderRequest); - let request = requests[0]; - expect(request.data.adUnits[0].features).to.exist; - expect(request.data.adUnits[0].features.viewport_dimensions).to.match(/^[\d]+x[\d]+$/); + expect(requests).to.have.lengthOf(1); + expect(requests[0].method).to.equal('POST'); + expect(requests[0].url).to.equal(ENDPOINT); + expect(requests[0].options.contentType).to.eq('text/plain'); + expect(requests[0].data).to.have.all.keys(expectedDataKeys); }); - it('AdUnit requested should have the correct sizes array depending on the config', () => { - const requests = spec.buildRequests(bidRequests, bidderRequest); - expect(requests[1].data.adUnits[0]).to.have.property('mediaTypes'); - }); + it('should enqueue computed features for collect usage', function() { + sandbox.stub(Date, 'now').returns(12345); - it('features params must be an object if featurejs is loaded', () => { - let requests = spec.buildRequests(bidRequests, bidderRequest); - let request = requests[0]; - expect(request.data.adUnits[0].features).to.exist; + for (const prop in _features) { + sandbox.stub(_features, prop).returns(''); + } + + adagioMock.expects('enqueue').withExactArgs({ + action: 'features', + ts: 12345, + data: { + 'gpt-adunit-code': { + features: {}, + version: '1' + } + } + }).atLeast(1); + + const bid01 = new BidRequestBuilder().withParams().build(); + const bidderRequest = new BidderRequestBuilder().build(); + + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests[0].data).to.have.all.keys(expectedDataKeys); + + adagioMock.verify(); }); - it('outerAdUnitElementId must be added when PostBid param has been set', () => { - top.ADAGIO = top.ADAGIO || {}; - top.ADAGIO.pbjsAdUnits = []; + it('should filter some props in case refererDetection.reachedTop is false', function() { + const bid01 = new BidRequestBuilder().withParams().build(); + const bidderRequest = new BidderRequestBuilder({ + refererInfo: { + numIframes: 2, + reachedTop: false, + referer: 'http://example.com/iframe1.html', + stack: [ + null, + 'http://example.com/iframe1.html', + 'http://example.com/iframe2.html' + ], + canonicalUrl: '' + } + }).build(); - top.ADAGIO.pbjsAdUnits.push({ - code: bidRequestsWithPostBid[0].adUnitCode, - sizes: bidRequestsWithPostBid[0].sizes, - bids: [{ - bidder: bidRequestsWithPostBid[0].bidder, - params: bidRequestsWithPostBid[0].params + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests).to.have.lengthOf(1); + expect(requests[0].data).to.have.all.keys(expectedDataKeys); + expect(requests[0].data.adUnits[0].features).to.exist; + expect(requests[0].data.adUnits[0].features.url).to.not.exist; + }); + + describe('with sChain', function() { + const schain = { + ver: '1.0', + complete: 1, + nodes: [{ + asi: 'ssp.test', + sid: '00001', + hp: 1 }] + }; + + it('should add the schain if available at bidder level', function() { + const bid01 = new BidRequestBuilder({ schain }).withParams().build(); + const bidderRequest = new BidderRequestBuilder().build(); + + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests[0].data).to.have.all.keys(expectedDataKeys); + expect(requests[0].data.schain).to.deep.equal(schain); }); - let requests = spec.buildRequests(bidRequestsWithPostBid, bidderRequest); - let request = requests[0]; - expect(request.data.adUnits[0].features).to.exist; - expect(request.data.adUnits[0].params.outerAdUnitElementId).to.exist; - top.ADAGIO.pbjsAdUnits = undefined; - }); - it('generates a pageviewId if missing', () => { - window.top.ADAGIO = window.top.ADAGIO || {}; - delete window.top.ADAGIO.pageviewId; + it('Schain should not be added to the request', function() { + const bid01 = new BidRequestBuilder().withParams().build(); + const bidderRequest = new BidderRequestBuilder().build(); - const requests = spec.buildRequests(bidRequests, bidderRequest); - expect(requests).to.have.lengthOf(2); + const requests = spec.buildRequests([bid01], bidderRequest); - expect(requests[0].data.pageviewId).to.exist.and.to.not.equal('_').and.to.not.equal(''); - expect(requests[0].data.pageviewId).to.equal(requests[1].data.pageviewId); + expect(requests[0].data.schain).to.not.exist; + }); }); - it('uses an existing pageviewId if present', () => { - window.top.ADAGIO = window.top.ADAGIO || {}; - window.top.ADAGIO.pageviewId = 'abc'; + describe('with GDPR', function() { + const bid01 = new BidRequestBuilder().withParams().build(); - const requests = spec.buildRequests(bidRequests, bidderRequest); - expect(requests).to.have.lengthOf(2); + const consentString = 'BOJ/P2HOJ/P2HABABMAAAAAZ+A=='; - expect(requests[0].data.pageviewId).to.equal('abc'); - expect(requests[1].data.pageviewId).to.equal('abc'); - }); + const gdprConsentBuilderTCF1 = function gdprConsentBuilderTCF1(applies, allows) { + return { + consentString, + gdprApplies: applies, + allowAuctionWithoutConsent: allows, + apiVersion: 1 + }; + }; - it('should send the printNumber in features object', () => { - window.top.ADAGIO = window.top.ADAGIO || {}; - window.top.ADAGIO.pageviewId = 'abc'; - window.top.ADAGIO.adUnits['adunit-code1'] = { - pageviewId: 'abc', - printNumber: 2 + const gdprConsentBuilderTCF2 = function gdprConsentBuilderTCF2(applies) { + return { + consentString, + gdprApplies: applies, + apiVersion: 2 + }; }; - const requests = spec.buildRequests([bidRequests[0]], bidderRequest); - const request = requests[0]; - expect(request.data.adUnits[0].features.print_number).to.equal('2'); - }); - it('organizationId param key must be a string', () => { - const requests = spec.buildRequests([Object.assign({}, bidRequests[0], {params: {organizationId: 1010}})], bidderRequest); - const request = requests[0]; - expect(request.data.adUnits[0].params).to.exist; - expect(request.data.adUnits[0].params.organizationId).to.deep.equal('1010'); - expect(request.data.organizationId).to.exist; - expect(request.data.organizationId).to.deep.equal('1010'); - }); + context('When GDPR applies', function() { + it('send data.gdpr object to the server from TCF v.1.1 cmp', function() { + const bidderRequest = new BidderRequestBuilder({ + gdprConsent: gdprConsentBuilderTCF1(true, true) + }).build(); + + const expected = { + consentString, + allowAuctionWithoutConsent: 1, + consentRequired: 1, + apiVersion: 1 + }; - it('GDPR consent is applied', () => { - const requests = spec.buildRequests(bidRequests, bidderRequest); - expect(requests).to.have.lengthOf(2); - const request = requests[0]; - expect(request.data.gdpr).to.exist; - expect(request.data.gdpr.consentString).to.exist.and.to.equal(consentString); - expect(request.data.gdpr.consentRequired).to.exist.and.to.equal(1); - expect(request.data.gdpr.apiVersion).to.exist.and.to.equal(1); - }); + const requests = spec.buildRequests([bid01], bidderRequest); - it('GDPR consent is applied w/ TCF2', () => { - const requests = spec.buildRequests(bidRequests, bidderRequestTCF2); - expect(requests).to.have.lengthOf(2); - const request = requests[0]; - expect(request.data.gdpr).to.exist; - expect(request.data.gdpr.consentString).to.exist.and.to.equal(consentString); - expect(request.data.gdpr.consentRequired).to.exist.and.to.equal(1); - expect(request.data.gdpr.apiVersion).to.exist.and.to.equal(2); - }); + expect(requests[0].data.regs.gdpr).to.deep.equal(expected); + }); - it('GDPR consent is not applied', () => { - bidderRequest.gdprConsent.gdprApplies = false; - const requests = spec.buildRequests(bidRequests, bidderRequest); - expect(requests).to.have.lengthOf(2); - const request = requests[0]; - expect(request.data.gdpr).to.exist; - expect(request.data.gdpr.consentString).to.exist.and.to.equal(consentString); - expect(request.data.gdpr.consentRequired).to.exist.and.to.equal(0); - expect(request.data.gdpr.apiVersion).to.exist.and.to.equal(1); - }); + it('send data.gdpr object to the server from TCF v.2 cmp', function() { + const bidderRequest = new BidderRequestBuilder({ + gdprConsent: gdprConsentBuilderTCF2(true) + }).build(); - it('GDPR consent is not applied w/ TCF2', () => { - bidderRequestTCF2.gdprConsent.gdprApplies = false; - const requests = spec.buildRequests(bidRequests, bidderRequestTCF2); - expect(requests).to.have.lengthOf(2); - const request = requests[0]; - expect(request.data.gdpr).to.exist; - expect(request.data.gdpr.consentString).to.exist.and.to.equal(consentString); - expect(request.data.gdpr.consentRequired).to.exist.and.to.equal(0); - expect(request.data.gdpr.apiVersion).to.exist.and.to.equal(2); - }); - - it('GDPR consent is undefined', () => { - delete bidderRequest.gdprConsent.consentString; - delete bidderRequest.gdprConsent.gdprApplies; - delete bidderRequest.gdprConsent.allowAuctionWithoutConsent; - const requests = spec.buildRequests(bidRequests, bidderRequest); - expect(requests).to.have.lengthOf(2); - const request = requests[0]; - expect(request.data.gdpr).to.exist; - expect(request.data.gdpr).to.not.have.property('consentString'); - expect(request.data.gdpr).to.not.have.property('gdprApplies'); - expect(request.data.gdpr).to.not.have.property('allowAuctionWithoutConsent'); - expect(request.data.gdpr.apiVersion).to.exist.and.to.equal(1); - }); - - it('GDPR consent is undefined w/ TCF2', () => { - delete bidderRequestTCF2.gdprConsent.consentString; - delete bidderRequestTCF2.gdprConsent.gdprApplies; - delete bidderRequestTCF2.gdprConsent.vendorData; - const requests = spec.buildRequests(bidRequests, bidderRequestTCF2); - expect(requests).to.have.lengthOf(2); - const request = requests[0]; - expect(request.data.gdpr).to.exist; - expect(request.data.gdpr).to.not.have.property('consentString'); - expect(request.data.gdpr).to.not.have.property('gdprApplies'); - expect(request.data.gdpr.apiVersion).to.exist.and.to.equal(2); - }); + const expected = { + consentString, + consentRequired: 1, + apiVersion: 2 + }; - it('GDPR consent bidderRequest does not have gdprConsent', () => { - delete bidderRequest.gdprConsent; - const requests = spec.buildRequests(bidRequests, bidderRequest); - expect(requests).to.have.lengthOf(2); - const request = requests[0]; - expect(request.data.gdpr).to.exist; - expect(request.data.gdpr).to.be.empty; - }); + const requests = spec.buildRequests([bid01], bidderRequest); - it('should expose version in window', () => { - expect(window.top.ADAGIO).ok; - expect(window.top.ADAGIO.versions).ok; - expect(window.top.ADAGIO.versions.adagioBidderAdapter).to.eq(VERSION); - }); + expect(requests[0].data.regs.gdpr).to.deep.equal(expected); + }); + }); + + context('When GDPR does not applies', function() { + it('send data.gdpr object to the server from TCF v.1.1 cmp', function() { + const bidderRequest = new BidderRequestBuilder({ + gdprConsent: gdprConsentBuilderTCF1(false, true) + }).build(); + + const expected = { + consentString, + allowAuctionWithoutConsent: 1, + consentRequired: 0, + apiVersion: 1 + }; + + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests[0].data.regs.gdpr).to.deep.equal(expected); + }); - it('should returns an empty array if the bidder cannot access to window top (based on refererInfo.reachedTop)', () => { - const requests = spec.buildRequests(bidRequests, { - ...bidderRequest, - refererInfo: { reachedTop: false } + it('send data.gdpr object to the server from TCF v.2 cmp', function() { + const bidderRequest = new BidderRequestBuilder({ + gdprConsent: gdprConsentBuilderTCF2(false) + }).build(); + + const expected = { + consentString, + consentRequired: 0, + apiVersion: 2 + }; + + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests[0].data.regs.gdpr).to.deep.equal(expected); + }); + }); + + context('When GDPR is undefined in bidderRequest', function() { + it('send an empty data.gdpr to the server', function() { + const bidderRequest = new BidderRequestBuilder().build(); + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests[0].data.regs.gdpr).to.be.empty; + }); }); - expect(requests).to.be.empty; }); - it('Should add the schain if available at bidder level', () => { - const bidRequest = Object.assign({}, bidRequests[0], { - schain: { - ver: '1.0', - complete: 1, - nodes: [{ - asi: 'ssp.test', - sid: '00001', - hp: 1 - }] - } + describe('with COPPA', function() { + const bid01 = new BidRequestBuilder().withParams().build(); + + it('should send the Coppa "required" flag set to "1" in the request', function () { + const bidderRequest = new BidderRequestBuilder().build(); + + sinon.stub(config, 'getConfig') + .withArgs('coppa') + .returns(true); + + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests[0].data.regs.coppa.required).to.equal(1); + + config.getConfig.restore(); }); + }); - const requests = spec.buildRequests([bidRequest], bidderRequest); - const request = requests[0]; + describe('without COPPA', function() { + const bid01 = new BidRequestBuilder().withParams().build(); - expect(request.data.schain).to.exist; - expect(request.data.schain).to.deep.equal({ - ver: '1.0', - complete: 1, - nodes: [{ - asi: 'ssp.test', - sid: '00001', - hp: 1 - }] + it('should send the Coppa "required" flag set to "0" in the request', function () { + const bidderRequest = new BidderRequestBuilder().build(); + + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests[0].data.regs.coppa.required).to.equal(0); }); }); - it('Schain should not be added to the request', () => { - const requests = spec.buildRequests([bidRequests[0]], bidderRequest); - const request = requests[0]; - expect(request.data.schain).to.not.exist; + describe('with USPrivacy', function() { + const bid01 = new BidRequestBuilder().withParams().build(); + + const consent = 'Y11N' + + it('should send the USPrivacy "ccpa.uspConsent" in the request', function () { + const bidderRequest = new BidderRequestBuilder({ + uspConsent: consent + }).build(); + + const requests = spec.buildRequests([bid01], bidderRequest); + + expect(requests[0].data.regs.ccpa.uspConsent).to.equal(consent); + }); }); - }); - describe('interpretResponse', () => { - const sandbox = sinon.createSandbox(); + describe('without USPrivacy', function() { + const bid01 = new BidRequestBuilder().withParams().build(); - let serverResponse = { - body: { - data: { - pred: 1 - }, - bids: [ - { - ad: '
', - cpm: 1, - creativeId: 'creativeId', - currency: 'EUR', - height: 250, - netRevenue: true, - requestId: 'c180kg4267tyqz', - ttl: 360, - width: 300 - } - ] - } - }; + it('should have an empty "ccpa" field in the request', function () { + const bidderRequest = new BidderRequestBuilder().build(); - let emptyBodyServerResponse = { - body: null - }; + const requests = spec.buildRequests([bid01], bidderRequest); - let withoutBidsArrayServerResponse = { - body: { - bids: [] - } - }; + expect(requests[0].data.regs.ccpa).to.be.empty; + }); + }); + }); - let serverResponseWhichThrowsException = { + describe('interpretResponse()', function() { + let serverResponse = { body: { data: { pred: 1 }, - bids: { - foo: 'bar' - } + bids: [{ + ad: '
', + cpm: 1, + creativeId: 'creativeId', + currency: 'EUR', + height: 250, + netRevenue: true, + requestId: 'c180kg4267tyqz', + ttl: 360, + width: 300 + }] } }; let bidRequest = { - 'data': { - 'adUnits': [ - { - 'bidder': 'adagio', - 'params': { - organizationId: '456', - site: 'ADAGIO-456', - placement: 'PAVE_ATF-456', - adUnitElementId: 'banner-atf-456', - pagetype: 'ARTICLE', - category: 'NEWS', - subcategory: 'SPORT', - environment: 'SITE-MOBILE' - }, - 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250], [300, 600]], - 'bidId': 'c180kg4267tyqz', - 'bidderRequestId': '8vfscuixrovn8i', - 'auctionId': 'lel4fhp239i9km', - 'pageviewId': 'd8c4fl2k39i0wn', - } - ] + data: { + adUnits: [{ + bidder: 'adagio', + params: { + organizationId: '1000', + placement: 'PAVE_ATF', + site: 'SITE-NAME', + adUnitElementId: 'gpt-adunit-code', + pagetype: 'ARTICLE', + category: 'NEWS', + subcategory: 'SPORT', + environment: 'desktop' + }, + adUnitCode: 'adunit-code', + mediaTypes: { + banner: { sizes: [[300, 250], [300, 600]] } + }, + bidId: 'c180kg4267tyqz', + bidderRequestId: '8vfscuixrovn8i', + auctionId: 'lel4fhp239i9km', + pageviewId: 'd8c4fl2k39i0wn', + }] } }; - afterEach(function() { - sandbox.restore(); - }); + it('should return an empty response array if body is empty', function() { + expect(spec.interpretResponse({ + body: null + }, bidRequest)).to.be.an('array').length(0); - it('Should returns empty response if body is empty', () => { - expect(spec.interpretResponse(emptyBodyServerResponse, bidRequest)).to.be.an('array').length(0); - expect(spec.interpretResponse({body: {}}, bidRequest)).to.be.an('array').length(0); + expect(spec.interpretResponse({ + body: {} + }, bidRequest)).to.be.an('array').length(0); }); - it('Should returns empty response if bids array is empty', () => { - expect(spec.interpretResponse({withoutBidsArrayServerResponse}, bidRequest)).to.be.an('array').length(0); + it('should return an empty response array if bids array is empty', function() { + expect(spec.interpretResponse({ + body: { + bids: [] + } + }, bidRequest)).to.be.an('array').length(0); }); - it('should get correct bid response', () => { + it('should handle properly a correct bid response', function() { let expectedResponse = [{ ad: '
', cpm: 1, @@ -670,87 +650,512 @@ describe('adagioAdapter', () => { requestId: 'c180kg4267tyqz', ttl: 360, width: 300, - placement: 'PAVE_ATF-456', - site: 'ADAGIO-456', + placement: 'PAVE_ATF', + site: 'SITE-NAME', pagetype: 'ARTICLE', category: 'NEWS', subcategory: 'SPORT', - environment: 'SITE-MOBILE' + environment: 'desktop' }]; + expect(spec.interpretResponse(serverResponse, bidRequest)).to.be.an('array'); expect(spec.interpretResponse(serverResponse, bidRequest)).to.deep.equal(expectedResponse); }); - it('Should populate ADAGIO queue with ssp-data', () => { - spec.interpretResponse(serverResponse, bidRequest); - expect(window.top.ADAGIO).ok; - expect(window.top.ADAGIO.queue).to.be.an('array'); - }); + it('should populate ADAGIO queue with ssp-data', function() { + sandbox.stub(Date, 'now').returns(12345); + + adagioMock.expects('enqueue').withExactArgs({ + action: 'ssp-data', + ts: 12345, + data: serverResponse.body.data + }).once(); - it('Should not populate ADAGIO queue with ssp-data if not in top window', () => { - utils.getWindowTop().ADAGIO.queue = []; - sandbox.stub(utils, 'getWindowTop').throws(); spec.interpretResponse(serverResponse, bidRequest); - expect(window.top.ADAGIO).ok; - expect(window.top.ADAGIO.queue).to.be.an('array'); - expect(window.top.ADAGIO.queue).empty; + + adagioMock.verify(); }); - it('should return an empty response even if an exception is ', () => { - expect(spec.interpretResponse(serverResponseWhichThrowsException, bidRequest)).to.be.an('array').length(0); + it('should properly try-catch an exception and return an empty array', function() { + sandbox.stub(adagio, 'enqueue').throws(); + utilsMock.expects('logError').once(); + + expect(spec.interpretResponse(serverResponse, bidRequest)).to.be.an('array').length(0); + + utilsMock.verify(); }); }); - describe('getUserSyncs', () => { + describe('getUserSyncs()', function() { const syncOptions = { - 'iframeEnabled': 'true' - } - const serverResponses = [ - { + syncEnabled: false + }; + + it('should handle user syncs if data is in the server response ', function() { + const serverResponses = [{ body: { userSyncs: [ - { - t: 'i', - u: 'https://test.url.com/setuid' - }, - { - t: 'p', - u: 'https://test.url.com/setuid' - } + { t: 'i', u: 'https://test.url.com/setuid' }, + { t: 'p', u: 'https://test.url.com/setuid' } ] } - } - ]; - - const emptyServerResponses = [ - { - body: '' - } - ]; + }]; - it('should handle correctly user syncs', () => { let result = spec.getUserSyncs(syncOptions, serverResponses); - let emptyResult = spec.getUserSyncs(syncOptions, emptyServerResponses); + expect(result[0].type).to.equal('iframe'); expect(result[0].url).contain('setuid'); + expect(result[1].type).to.equal('image'); - expect(emptyResult).to.equal(false); + expect(result[1].url).contain('setuid'); + }); + + it('should return false if data is not in server response', function() { + const serverResponse = [{ body: '' }]; + const result = spec.getUserSyncs(syncOptions, serverResponse); + expect(result).to.equal(false); }); }); - describe('adagioScriptFromLocalStorageCb', () => { + describe('Adagio features', function() { + it('should return all expected features when all expected bidder params are available', function() { + sandbox.stub(window.top.document, 'getElementById').returns( + fixtures.getElementById() + ); + sandbox.stub(window.top, 'getComputedStyle').returns({ display: 'block' }); + + const bidRequest = new BidRequestBuilder({ + 'mediaTypes': { + banner: { sizes: [[300, 250]] } + } + }).withParams().build(); + + const bidderRequest = new BidderRequestBuilder().build(); + + const result = adagio.getFeatures(bidRequest, bidderRequest); + + expect(result.adunit_position).to.match(/^[\d]+x[\d]+$/); + expect(result.page_dimensions).to.match(/^[\d]+x[\d]+$/); + expect(result.viewport_dimensions).to.match(/^[\d]+x[\d]+$/); + expect(result.print_number).to.be.a('String'); + expect(result.dom_loading).to.be.a('String'); + expect(result.user_timestamp).to.be.a('String'); + expect(result.url).to.be.a('String'); + expect(result.device).to.be.a('String'); + expect(result.os).to.be.a('String'); + expect(result.browser).to.be.a('String'); + }); + + it('should return all expected features when `adUnitElementId` param is not available', function() { + const bidRequest = new BidRequestBuilder({ + params: { + organizationId: '1000', + placement: 'PAVE_ATF', + site: 'SITE-NAME' + }, + 'mediaTypes': { + banner: { sizes: [[300, 250]] } + } + }).build(); + + const bidderRequest = new BidderRequestBuilder().build(); + + const result = adagio.getFeatures(bidRequest, bidderRequest); + + expect(result.adunit_position).to.not.exist; + expect(result.page_dimensions).to.be.a('String'); + expect(result.viewport_dimensions).to.be.a('String'); + expect(result.print_number).to.be.a('String'); + expect(result.dom_loading).to.be.a('String'); + expect(result.user_timestamp).to.be.a('String'); + expect(result.url).to.be.a('String'); + expect(result.device).to.be.a('String'); + expect(result.os).to.be.a('String'); + expect(result.browser).to.be.a('String'); + }); + + it('should not return feature with an empty value', function() { + sandbox.stub(_features, 'getDomLoadingDuration').returns(''); + sandbox.stub(_features, 'getUrl').returns(''); + sandbox.stub(_features, 'getBrowser').returns(''); + + const bidRequest = new BidRequestBuilder({ + 'mediaTypes': { + banner: { sizes: [[300, 250]] } + } + }).withParams().build(); + + const bidderRequest = new BidderRequestBuilder().build(); + + const result = adagio.getFeatures(bidRequest, bidderRequest); + + expect(result.adunit_position).to.not.exist; + expect(result.page_dimensions).to.exist; + expect(result.viewport_dimensions).to.exist; + expect(result.print_number).to.exist; + expect(result.dom_loading).to.not.exist; + expect(result.user_timestamp).to.exist; + expect(result.url).to.not.exist; + expect(result.device).to.exist; + expect(result.os).to.exist; + expect(result.browser).to.not.exist; + }); + + describe('getPageDimensions feature', function() { + afterEach(() => { + delete window.$sf; + }); + + it('should not compute the page dimensions in cross-origin iframe', function() { + sandbox.stub(utils, 'getWindowTop').throws(); + const result = _features.getPageDimensions(); + expect(result).to.eq(''); + }); + + it('should not compute the page dimensions even with safeFrame api', function() { + window.$sf = $sf; + const result = _features.getPageDimensions(); + expect(result).to.eq(''); + }); + + it('should not compute the page dimensions if is not in the DOM', function() { + sandbox.stub(window.top.document, 'querySelector').withArgs('body').returns(null); + const result = _features.getPageDimensions(); + expect(result).to.eq(''); + }); + + it('should compute the page dimensions based on body and viewport dimensions', function() { + sandbox.stub(window.top.document, 'querySelector').withArgs('body').returns({ scrollWidth: 1360, offsetWidth: 1280, scrollHeight: 2000, offsetHeight: 1000 }); + const result = _features.getPageDimensions(); + expect(result).to.eq('1360x2000'); + }); + }); + + describe('getViewPortDimensions feature', function() { + afterEach(() => { + delete window.$sf; + }); + + it('should not compute the viewport dimensions in cross-origin iframe', function() { + sandbox.stub(utils, 'getWindowTop').throws(); + const result = _features.getViewPortDimensions(); + expect(result).to.eq(''); + }); + + it('should compute the viewport dimensions in cross-origin iframe w/ safeFrame api', function() { + window.$sf = $sf; + sandbox.stub(window.$sf.ext, 'geom').returns({ + win: {t: 23, r: 1920, b: 1200, l: 0, w: 1920, h: 1177}, + self: {t: 210, r: 1159, b: 460, l: 859, w: 300, h: 250}, + }); + const result = _features.getViewPortDimensions(); + expect(result).to.eq('1920x1177'); + }); + + it('should not compute the viewport dimensions if safeFrame api is misimplemented', function() { + window.$sf = { + ext: { geom: 'nothing' } + }; + const result = _features.getViewPortDimensions(); + expect(result).to.eq(''); + }); + + it('should not compute the viewport dimensions if is not in the DOM', function() { + const querySelectorSpy = sandbox.spy(() => null); + sandbox.stub(utils, 'getWindowTop').returns({ + location: { href: 'https://mytest.io' }, + document: { querySelector: querySelectorSpy } + }); + const result = _features.getViewPortDimensions(); + expect(result).to.eq(''); + }); + + it('should compute the viewport dimensions based on window', function() { + sandbox.stub(utils, 'getWindowTop').returns({ + location: { href: 'https://mytest.io' }, + innerWidth: 960, + innerHeight: 3000 + }); + const result = _features.getViewPortDimensions(); + expect(result).to.eq('960x3000'); + }); + + it('should compute the viewport dimensions based on body', function() { + const querySelectorSpy = sandbox.spy(() => ({ clientWidth: 1024, clientHeight: 2000 })); + sandbox.stub(utils, 'getWindowTop').returns({ + location: { href: 'https://mytest.io' }, + document: { querySelector: querySelectorSpy } + }); + const result = _features.getViewPortDimensions(); + expect(result).to.eq('1024x2000'); + }); + }); + + describe('getSlotPosition feature', function() { + let getElementByIdStub; + let getComputedStyleStub; + + beforeEach(() => { + getElementByIdStub = sandbox.stub(window.top.document, 'getElementById'); + getElementByIdStub.returns(fixtures.getElementById()); + getComputedStyleStub = sandbox.stub(window.top, 'getComputedStyle'); + getComputedStyleStub.returns({ display: 'block' }); + }); + + afterEach(() => { + delete window.$sf; + getElementByIdStub.restore(); + getComputedStyleStub.restore(); + }); + + it('should not compute the slot position in cross-origin iframe', function() { + sandbox.stub(utils, 'getWindowTop').throws(); + const result = _features.getSlotPosition({ adUnitElementId: 'gpt-adunit-code', postBid: false }); + expect(result).to.eq(''); + }); + + it('should compute the slot position in cross-origin iframe w/ safeFrame api', function() { + window.$sf = $sf; + sandbox.stub(window.$sf.ext, 'geom').returns({ + win: {t: 23, r: 1920, b: 1200, l: 0, w: 1920, h: 1177}, + self: {t: 210, r: 1159, b: 460, l: 859, w: 300, h: 250}, + }); + const result = _features.getSlotPosition({ adUnitElementId: 'gpt-adunit-code', postBid: false }); + expect(result).to.eq('210x859'); + }); + + it('should not compute the slot position if safeFrame api is misimplemented', function() { + window.$sf = { + ext: { geom: 'nothing' } + }; + utilsMock.expects('logWarn').once(); + const result = _features.getSlotPosition({ adUnitElementId: 'gpt-adunit-code', postBid: false }); + expect(result).to.eq(''); + utilsMock.verify(); + }); + + it('should not compute the slot position due to unreachable adUnitElementId', function() { + getElementByIdStub.returns(null); + const result = _features.getSlotPosition({ adUnitElementId: 'gpt-adunit-code', postBid: false }); + expect(result).to.eq(''); + }); + + it('should use a quick switch to display slot and compute position', function() { + getComputedStyleStub.returns({ display: 'none' }); + const result = _features.getSlotPosition({ adUnitElementId: 'gpt-adunit-code', postBid: false }); + expect(result).to.eq('800x300'); + }); + + it('should compute the slot position based on window.top w/o postBid param', function() { + const result = _features.getSlotPosition({ adUnitElementId: 'gpt-adunit-code', postBid: false }); + expect(result).to.eq('800x300'); + }); + + it.skip('should compute the slot position inside the parent window (window.top) when safeFrame is not available and postBid params is `true`', function() { + const result = _features.getSlotPosition({ adUnitElementId: 'gpt-adunit-code', postBid: true }); + // expect(result).to.eq('800x300'); + }); + }); + }); + + describe('optional params auto detection', function() { + it('should auto detect environment', function() { + const getDeviceStub = sandbox.stub(_features, 'getDevice'); + + getDeviceStub.returns(5); + expect(adagio.autoDetectEnvironment()).to.eq('tablet'); + + getDeviceStub.returns(4); + expect(adagio.autoDetectEnvironment()).to.eq('mobile'); + + getDeviceStub.returns(2); + expect(adagio.autoDetectEnvironment()).to.eq('desktop'); + }); + + it('should auto detect adUnitElementId when GPT is used', function() { + sandbox.stub(utils, 'getGptSlotInfoForAdUnitCode').withArgs('banner').returns({divId: 'gpt-banner'}); + expect(adagio.autoDetectAdUnitElementId('banner')).to.eq('gpt-banner'); + }); + }); + + describe('print number handling', function() { + it('should return 1 if no adunit-code found. This means it is the first auction', function() { + sandbox.stub(adagio, 'getPageviewId').returns('abc-def'); + expect(adagio.computePrintNumber('adunit-code')).to.eql(1); + }); + + it('should increment the adunit print number when the adunit-code has already been used for an other auction', function() { + sandbox.stub(adagio, 'getPageviewId').returns('abc-def'); + + window.top.ADAGIO.adUnits['adunit-code'] = { + pageviewId: 'abc-def', + printNumber: 1, + }; + + expect(adagio.computePrintNumber('adunit-code')).to.eql(2); + }); + }); + + describe('site information using refererDetection or window.top', function() { + it('should returns domain, page and window.referrer in a window.top context', function() { + sandbox.stub(utils, 'getWindowTop').returns({ + location: { + hostname: 'test.io', + href: 'https://test.io/article/a.html' + }, + document: { + referrer: 'https://google.com' + } + }); + + const bidderRequest = new BidderRequestBuilder({ + refererInfo: { + numIframes: 0, + reachedTop: true, + referer: 'http://test.io/index.html?pbjs_debug=true' + } + }).build(); + + expect(adagio.getSite(bidderRequest)).to.deep.equal({ + domain: 'test.io', + page: 'https://test.io/article/a.html', + referrer: 'https://google.com' + }); + }); + + it('should returns domain and page in a cross-domain w/ top domain reached context', function() { + sandbox.stub(utils, 'getWindowTop').throws(); + + const info = { + numIframes: 0, + reachedTop: true, + referer: 'http://level.io/', + stack: [ + 'http://level.io/', + 'http://example.com/iframe1.html', + 'http://example.com/iframe2.html' + ], + canonicalUrl: '' + }; + + const bidderRequest = new BidderRequestBuilder({ + refererInfo: info + }).build(); + + expect(adagio.getSite(bidderRequest)).to.deep.equal({ + domain: 'level.io', + page: 'http://level.io/', + referrer: '' + }); + }); + + it('should not return anything in a cross-domain w/o top domain reached and w/o ancestor context', function() { + sandbox.stub(utils, 'getWindowTop').throws(); + + const info = { + numIframes: 2, + reachedTop: false, + referer: 'http://example.com/iframe1.html', + stack: [ + null, + 'http://example.com/iframe1.html', + 'http://example.com/iframe2.html' + ], + canonicalUrl: '' + }; + + const bidderRequest = new BidderRequestBuilder({ + refererInfo: info + }).build(); + + expect(adagio.getSite(bidderRequest)).to.deep.equal({ + domain: '', + page: '', + referrer: '' + }); + }); + + it('should return domain only in a cross-domain w/o top domain reached and w/ ancestors context', function() { + sandbox.stub(utils, 'getWindowTop').throws(); + + const info = { + numIframes: 2, + reachedTop: false, + referer: 'http://example.com/iframe1.html', + stack: [ + 'http://mytest.com/', + 'http://example.com/iframe1.html', + 'http://example.com/iframe2.html' + ], + canonicalUrl: '' + }; + + const bidderRequest = new BidderRequestBuilder({ + refererInfo: info + }).build(); + + expect(adagio.getSite(bidderRequest)).to.deep.equal({ + domain: 'mytest.com', + page: '', + referrer: '' + }); + }); + }); + + describe('adagioScriptFromLocalStorageCb()', function() { const VALID_HASH = 'Lddcw3AADdQDrPtbRJkKxvA+o1CtScGDIMNRpHB3NnlC/FYmy/9RKXelKrYj/sjuWusl5YcOpo+lbGSkk655i8EKuDiOvK6ae/imxSrmdziIp+S/TA6hTFJXcB8k1Q9OIp4CMCT52jjXgHwX6G0rp+uYoCR25B1jHaHnpH26A6I='; const INVALID_HASH = 'invalid'; const VALID_SCRIPT_CONTENT = 'var _ADAGIO=function(){};(_ADAGIO)();\n'; const INVALID_SCRIPT_CONTENT = 'var _ADAGIO=function(){//corrupted};(_ADAGIO)();\n'; const ADAGIO_LOCALSTORAGE_KEY = 'adagioScript'; + beforeEach(function() { + localStorage.removeItem(ADAGIO_LOCALSTORAGE_KEY); + }); + + describe('getAdagioScript', function() { + it('should run storage.getDataFromLocalStorage callback and call adagioScriptFromLocalStorageCb() ', function() { + sandbox.spy(adagio, 'adagioScriptFromLocalStorageCb'); + const getDataFromLocalStorageStub = sandbox.stub(storage, 'getDataFromLocalStorage').callsArg(1); + localStorage.setItem(ADAGIO_LOCALSTORAGE_KEY, '// hash: ' + VALID_HASH + '\n' + VALID_SCRIPT_CONTENT); + + getAdagioScript(); + + sinon.assert.callCount(getDataFromLocalStorageStub, 1); + sinon.assert.callCount(adagio.adagioScriptFromLocalStorageCb, 1); + }); + + it('should load external script if the user consent', function() { + sandbox.stub(storage, 'localStorageIsEnabled').callsArgWith(0, true); + getAdagioScript(); + + expect(loadExternalScript.called).to.be.true; + }); + + it('should not load external script if the user does not consent', function() { + sandbox.stub(storage, 'localStorageIsEnabled').callsArgWith(0, false); + getAdagioScript(); + + expect(loadExternalScript.called).to.be.false; + }); + + it('should remove the localStorage key if exists and the user does not consent', function() { + sandbox.stub(storage, 'localStorageIsEnabled').callsArgWith(0, false); + localStorage.setItem(ADAGIO_LOCALSTORAGE_KEY, 'the script'); + + getAdagioScript(); + + expect(loadExternalScript.called).to.be.false; + expect(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)).to.be.null; + }) + }); + it('should verify valid hash with valid script', function () { localStorage.setItem(ADAGIO_LOCALSTORAGE_KEY, '// hash: ' + VALID_HASH + '\n' + VALID_SCRIPT_CONTENT); - utilsMock.expects('logInfo').withExactArgs('Start Adagio script').once(); - utilsMock.expects('logWarn').withExactArgs('No hash found in Adagio script').never(); - utilsMock.expects('logWarn').withExactArgs('Invalid Adagio script found').never(); + utilsMock.expects('logInfo').withExactArgs('Adagio: start script.').once(); + utilsMock.expects('logWarn').withExactArgs('Adagio: no hash found.').never(); + utilsMock.expects('logWarn').withExactArgs('Adagio: invalid script found.').never(); adagioScriptFromLocalStorageCb(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)); @@ -761,9 +1166,9 @@ describe('adagioAdapter', () => { it('should verify valid hash with invalid script', function () { localStorage.setItem(ADAGIO_LOCALSTORAGE_KEY, '// hash: ' + VALID_HASH + '\n' + INVALID_SCRIPT_CONTENT); - utilsMock.expects('logInfo').withExactArgs('Start Adagio script').never(); - utilsMock.expects('logWarn').withExactArgs('No hash found in Adagio script').never(); - utilsMock.expects('logWarn').withExactArgs('Invalid Adagio script found').once(); + utilsMock.expects('logInfo').withExactArgs('Adagio: start script').never(); + utilsMock.expects('logWarn').withExactArgs('Adagio: no hash found.').never(); + utilsMock.expects('logWarn').withExactArgs('Adagio: invalid script found.').once(); adagioScriptFromLocalStorageCb(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)); @@ -774,9 +1179,9 @@ describe('adagioAdapter', () => { it('should verify invalid hash with valid script', function () { localStorage.setItem(ADAGIO_LOCALSTORAGE_KEY, '// hash: ' + INVALID_HASH + '\n' + VALID_SCRIPT_CONTENT); - utilsMock.expects('logInfo').withExactArgs('Start Adagio script').never(); - utilsMock.expects('logWarn').withExactArgs('No hash found in Adagio script').never(); - utilsMock.expects('logWarn').withExactArgs('Invalid Adagio script found').once(); + utilsMock.expects('logInfo').withExactArgs('Adagio: start script').never(); + utilsMock.expects('logWarn').withExactArgs('Adagio: no hash found.').never(); + utilsMock.expects('logWarn').withExactArgs('Adagio: invalid script found.').once(); adagioScriptFromLocalStorageCb(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)); @@ -787,14 +1192,21 @@ describe('adagioAdapter', () => { it('should verify missing hash', function () { localStorage.setItem(ADAGIO_LOCALSTORAGE_KEY, VALID_SCRIPT_CONTENT); - utilsMock.expects('logInfo').withExactArgs('Start Adagio script').never(); - utilsMock.expects('logWarn').withExactArgs('No hash found in Adagio script').once(); - utilsMock.expects('logWarn').withExactArgs('Invalid Adagio script found').never(); + utilsMock.expects('logInfo').withExactArgs('Adagio: start script').never(); + utilsMock.expects('logWarn').withExactArgs('Adagio: no hash found.').once(); + utilsMock.expects('logWarn').withExactArgs('Adagio: invalid script found.').never(); adagioScriptFromLocalStorageCb(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)); expect(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)).to.be.null; utilsMock.verify(); }); + + it('should return false if content script does not exist in localStorage', function() { + sandbox.spy(utils, 'logWarn'); + expect(adagioScriptFromLocalStorageCb(null)).to.be.undefined; + sinon.assert.callCount(utils.logWarn, 1); + sinon.assert.calledWith(utils.logWarn, 'Adagio: script not found.'); + }); }); }); diff --git a/test/spec/modules/adbutlerBidAdapter_spec.js b/test/spec/modules/adbutlerBidAdapter_spec.js index a9b56ade79e..6dedce321d8 100644 --- a/test/spec/modules/adbutlerBidAdapter_spec.js +++ b/test/spec/modules/adbutlerBidAdapter_spec.js @@ -13,7 +13,10 @@ describe('AdButler adapter', function () { zoneID: '210093', keyword: 'red', minCPM: '1.00', - maxCPM: '5.00' + maxCPM: '5.00', + extra: { + foo: 'bar', + } }, placementCode: '/19968336/header-bid-tag-1', mediaTypes: { @@ -93,6 +96,13 @@ describe('AdButler adapter', function () { expect(requestURL).to.have.string(';kw=red;'); }); + it('should set the extra parameter', () => { + let requests = spec.buildRequests(bidRequests); + let requestURL = requests[0].url; + + expect(requestURL).to.have.string(';foo=bar;'); + }); + it('should increment the count for the same zone', function () { let bidRequests = [ { diff --git a/test/spec/modules/adformBidAdapter_spec.js b/test/spec/modules/adformBidAdapter_spec.js index 9233ca1dd7a..360979659de 100644 --- a/test/spec/modules/adformBidAdapter_spec.js +++ b/test/spec/modules/adformBidAdapter_spec.js @@ -2,6 +2,7 @@ import {assert, expect} from 'chai'; import {spec} from 'modules/adformBidAdapter.js'; import { BANNER, VIDEO } from 'src/mediaTypes.js'; import { config } from 'src/config.js'; +import { createEidsArray } from 'modules/userId/eids.js'; describe('Adform adapter', function () { let serverResponse, bidRequest, bidResponses; @@ -129,25 +130,43 @@ describe('Adform adapter', function () { assert.equal(parsedUrl.query.pt, 'gross'); }); - describe('gdpr', function () { + it('should pass extended ids', function () { + bids[0].userIdAsEids = createEidsArray({ + tdid: 'TTD_ID_FROM_USER_ID_MODULE', + pubcid: 'pubCommonId_FROM_USER_ID_MODULE' + }); + let request = spec.buildRequests(bids); + let eids = parseUrl(request.url).query.eids; + + assert.equal(eids, 'eyJhZHNlcnZlci5vcmciOnsiVFREX0lEX0ZST01fVVNFUl9JRF9NT0RVTEUiOlsxXX0sInB1YmNpZC5vcmciOnsicHViQ29tbW9uSWRfRlJPTV9VU0VSX0lEX01PRFVMRSI6WzFdfX0%3D'); + assert.deepEqual(JSON.parse(atob(decodeURIComponent(eids))), { + 'adserver.org': { + 'TTD_ID_FROM_USER_ID_MODULE': [1] + }, + 'pubcid.org': { + 'pubCommonId_FROM_USER_ID_MODULE': [1] + } + }); + }); + + describe('user privacy', function () { it('should send GDPR Consent data to adform if gdprApplies', function () { - let resultBids = JSON.parse(JSON.stringify(bids[0])); let request = spec.buildRequests([bids[0]], {gdprConsent: {gdprApplies: true, consentString: 'concentDataString'}}); let parsedUrl = parseUrl(request.url).query; - assert.equal(parsedUrl.gdpr, 'true'); + assert.equal(parsedUrl.gdpr, '1'); assert.equal(parsedUrl.gdpr_consent, 'concentDataString'); }); - it('should not send GDPR Consent data to adform if gdprApplies is false or undefined', function () { - let resultBids = JSON.parse(JSON.stringify(bids[0])); + it('should not send GDPR Consent data to adform if gdprApplies is undefined', function () { let request = spec.buildRequests([bids[0]], {gdprConsent: {gdprApplies: false, consentString: 'concentDataString'}}); let parsedUrl = parseUrl(request.url).query; - assert.ok(!parsedUrl.gdpr); - assert.ok(!parsedUrl.gdpr_consent); + assert.equal(parsedUrl.gdpr, '0'); + assert.equal(parsedUrl.gdpr_consent, 'concentDataString'); request = spec.buildRequests([bids[0]], {gdprConsent: {gdprApplies: undefined, consentString: 'concentDataString'}}); + parsedUrl = parseUrl(request.url).query; assert.ok(!parsedUrl.gdpr); assert.ok(!parsedUrl.gdpr_consent); }); @@ -163,6 +182,13 @@ describe('Adform adapter', function () { request = spec.buildRequests([bids[0]]); assert.ok(!request.gdpr); }); + + it('should send CCPA Consent data to adform', function () { + const request = spec.buildRequests([bids[0]], {uspConsent: '1YA-'}); + const parsedUrl = parseUrl(request.url).query; + + assert.equal(parsedUrl.us_privacy, '1YA-'); + }); }); }); @@ -247,14 +273,14 @@ describe('Adform adapter', function () { for (let i = 0; i < result.length; i++) { assert.equal(result[i].gdpr, true); assert.equal(result[i].gdpr_consent, 'ERW342EIOWT34234KMGds'); - }; + } bidRequest.gdpr = undefined; result = spec.interpretResponse(serverResponse, bidRequest); for (let i = 0; i < result.length; i++) { assert.ok(!result[i].gdpr); assert.ok(!result[i].gdpr_consent); - }; + } }); it('should set a renderer only for an outstream context', function () { @@ -302,13 +328,13 @@ describe('Adform adapter', function () { serverResponse.body = [serverResponse.body[0]]; bidRequest.bids = [bidRequest.bids[0]]; - bidRequest.bids[0].sizes = [['300', '250'], ['250', '300'], ['300', '600'], ['600', '300']] + bidRequest.bids[0].sizes = [['300', '250'], ['250', '300'], ['300', '600'], ['600', '300']]; let result = spec.interpretResponse(serverResponse, bidRequest); assert.equal(result[0].width, 300); assert.equal(result[0].height, 600); }); - }) + }); }); beforeEach(function () { diff --git a/test/spec/modules/adformOpenRTBBidAdapter_spec.js b/test/spec/modules/adformOpenRTBBidAdapter_spec.js index 77dbc17cdb2..05788183e29 100644 --- a/test/spec/modules/adformOpenRTBBidAdapter_spec.js +++ b/test/spec/modules/adformOpenRTBBidAdapter_spec.js @@ -3,6 +3,7 @@ import {assert, expect} from 'chai'; import {spec} from 'modules/adformOpenRTBBidAdapter.js'; import { NATIVE } from 'src/mediaTypes.js'; import { config } from 'src/config.js'; +import { createEidsArray } from 'modules/userId/eids.js'; describe('AdformOpenRTB adapter', function () { let serverResponse, bidRequest, bidResponses; @@ -43,7 +44,7 @@ describe('AdformOpenRTB adapter', function () { assert.ok(request.data); }); - describe('gdpr', function () { + describe('user privacy', function () { it('should send GDPR Consent data to adform if gdprApplies', function () { let validBidRequests = [{ bidId: 'bidId', params: { siteId: 'siteId', test: 1 } }]; let bidderRequest = { gdprConsent: { gdprApplies: true, consentString: 'consentDataString' }, refererInfo: { referer: 'page' } }; @@ -60,9 +61,25 @@ describe('AdformOpenRTB adapter', function () { let request = JSON.parse(spec.buildRequests(validBidRequests, bidderRequest).data); assert.equal(typeof request.regs.ext.gdpr, 'number'); + assert.equal(request.regs.ext.gdpr, 1); }); - it('should not send GDPR Consent data to adform if gdprApplies is false or undefined', function () { + it('should send CCPA Consent data to adform', function () { + let validBidRequests = [{ bidId: 'bidId', params: { siteId: 'siteId', test: 1 } }]; + let bidderRequest = { uspConsent: '1YA-', refererInfo: { referer: 'page' } }; + let request = JSON.parse(spec.buildRequests(validBidRequests, bidderRequest).data); + + assert.equal(request.regs.ext.us_privacy, '1YA-'); + + bidderRequest = { uspConsent: '1YA-', gdprConsent: { gdprApplies: true, consentString: 'consentDataString' }, refererInfo: { referer: 'page' } }; + request = JSON.parse(spec.buildRequests(validBidRequests, bidderRequest).data); + + assert.equal(request.regs.ext.us_privacy, '1YA-'); + assert.equal(request.user.ext.consent, 'consentDataString'); + assert.equal(request.regs.ext.gdpr, 1); + }); + + it('should not send GDPR Consent data to adform if gdprApplies is undefined', function () { let validBidRequests = [{ bidId: 'bidId', params: { siteId: 'siteId' } @@ -70,6 +87,12 @@ describe('AdformOpenRTB adapter', function () { let bidderRequest = {gdprConsent: {gdprApplies: false, consentString: 'consentDataString'}, refererInfo: { referer: 'page' }}; let request = JSON.parse(spec.buildRequests(validBidRequests, bidderRequest).data); + assert.equal(request.user.ext.consent, 'consentDataString'); + assert.equal(request.regs.ext.gdpr, 0); + + bidderRequest = {gdprConsent: {consentString: 'consentDataString'}, refererInfo: { referer: 'page' }}; + request = JSON.parse(spec.buildRequests(validBidRequests, bidderRequest).data); + assert.equal(request.user, undefined); assert.equal(request.regs, undefined); }); @@ -144,6 +167,23 @@ describe('AdformOpenRTB adapter', function () { }); }); + it('should pass extended ids', function () { + let validBidRequests = [{ + bidId: 'bidId', + params: {}, + userIdAsEids: createEidsArray({ + tdid: 'TTD_ID_FROM_USER_ID_MODULE', + pubcid: 'pubCommonId_FROM_USER_ID_MODULE' + }) + }]; + + let request = JSON.parse(spec.buildRequests(validBidRequests, { refererInfo: { referer: 'page' } }).data); + assert.deepEqual(request.user.ext.eids, [ + { source: 'adserver.org', uids: [ { id: 'TTD_ID_FROM_USER_ID_MODULE', atype: 1, ext: { rtiPartner: 'TDID' } } ] }, + { source: 'pubcid.org', uids: [ { id: 'pubCommonId_FROM_USER_ID_MODULE', atype: 1 } ] } + ]); + }); + it('should send currency if defined', function () { config.setConfig({ currency: { adServerCurrency: 'EUR' } }); let validBidRequests = [{ params: {} }]; diff --git a/test/spec/modules/adheseBidAdapter_spec.js b/test/spec/modules/adheseBidAdapter_spec.js index 7392ecd8f4e..4d888db269d 100644 --- a/test/spec/modules/adheseBidAdapter_spec.js +++ b/test/spec/modules/adheseBidAdapter_spec.js @@ -17,9 +17,10 @@ let minimalBid = function() { } }; -let bidWithParams = function(data) { +let bidWithParams = function(data, userId) { let bid = minimalBid(); bid.params.data = data; + bid.userId = userId; return bid; }; @@ -70,34 +71,54 @@ describe('AdheseAdapter', function () { } }; + it('should include requested slots', function () { + let req = spec.buildRequests([ minimalBid() ], bidderRequest); + + expect(JSON.parse(req.data).slots).to.deep.include({ 'slotname': '_main_page_-leaderboard' }); + }); + it('should include all extra bid params', function () { let req = spec.buildRequests([ bidWithParams({ 'ag': '25' }) ], bidderRequest); - expect(req.url).to.contain('/sl_main_page_-leaderboard/ag25'); + expect(JSON.parse(req.data).parameters).to.deep.include({ 'ag': [ '25' ] }); }); it('should include duplicate bid params once', function () { let req = spec.buildRequests([ bidWithParams({ 'ag': '25' }), bidWithParams({ 'ag': '25', 'ci': 'gent' }) ], bidderRequest); - expect(req.url).to.contain('/sl_main_page_-leaderboard/ag25/cigent'); + expect(JSON.parse(req.data).parameters).to.deep.include({'ag': ['25']}).and.to.deep.include({ 'ci': [ 'gent' ] }); }); it('should split multiple target values', function () { let req = spec.buildRequests([ bidWithParams({ 'ci': 'london' }), bidWithParams({ 'ci': 'gent' }) ], bidderRequest); - expect(req.url).to.contain('/sl_main_page_-leaderboard/cilondon;gent'); + expect(JSON.parse(req.data).parameters).to.deep.include({ 'ci': [ 'london', 'gent' ] }); + }); + + it('should filter out empty params', function () { + let req = spec.buildRequests([ bidWithParams({ 'aa': [], 'bb': null, 'cc': '', 'dd': [ '', '' ], 'ee': [ 0, 1, null ], 'ff': 0, 'gg': [ 'x', 'y', '' ] }) ], bidderRequest); + + let params = JSON.parse(req.data).parameters; + expect(params).to.not.have.any.keys('aa', 'bb', 'cc', 'dd'); + expect(params).to.deep.include({ 'ee': [ 0, 1 ], 'ff': [ 0 ], 'gg': [ 'x', 'y' ] }); }); it('should include gdpr consent param', function () { let req = spec.buildRequests([ minimalBid() ], bidderRequest); - expect(req.url).to.contain('/xtCONSENT_STRING'); + expect(JSON.parse(req.data).parameters).to.deep.include({ 'xt': [ 'CONSENT_STRING' ] }); }); it('should include referer param in base64url format', function () { let req = spec.buildRequests([ minimalBid() ], bidderRequest); - expect(req.url).to.contain('/xfaHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc3ViamVjdHM_X2Q9MQ'); + expect(JSON.parse(req.data).parameters).to.deep.include({ 'xf': [ 'aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc3ViamVjdHM_X2Q9MQ' ] }); + }); + + it('should include id5 id as /x5 param', function () { + let req = spec.buildRequests([ bidWithParams({}, { 'id5id': { 'uid': 'ID5-1234567890' } }) ], bidderRequest); + + expect(JSON.parse(req.data).parameters).to.deep.include({ 'x5': [ 'ID5-1234567890' ] }); }); it('should include bids', function () { @@ -106,6 +127,18 @@ describe('AdheseAdapter', function () { expect(req.bids).to.deep.equal([ bid ]); }); + + it('should make a POST request', function () { + let req = spec.buildRequests([ minimalBid() ], bidderRequest); + + expect(req.method).to.equal('POST'); + }); + + it('should request the json endpoint', function () { + let req = spec.buildRequests([ minimalBid() ], bidderRequest); + + expect(req.url).to.equal('https://ads-demo.adhese.com/json'); + }); }); describe('interpretResponse', () => { @@ -155,6 +188,8 @@ describe('AdheseAdapter', function () { netRevenue: NET_REVENUE, ttl: TTL, adhese: { + origin: 'APPNEXUS', + originInstance: '', originData: { adType: 'leaderboard', seatbid: [ @@ -199,7 +234,11 @@ describe('AdheseAdapter', function () { mediaType: 'video', netRevenue: NET_REVENUE, ttl: TTL, - adhese: { originData: {} } + adhese: { + origin: 'RUBICON', + originInstance: '', + originData: {} + } }]; expect(spec.interpretResponse(sspVideoResponse, bidRequest)).to.deep.equal(expectedResponse); }); @@ -251,6 +290,8 @@ describe('AdheseAdapter', function () { requestId: BID_ID, ad: '', adhese: { + origin: '', + originInstance: '', originData: { adFormat: 'largeleaderboard', adId: '742898', @@ -310,6 +351,8 @@ describe('AdheseAdapter', function () { requestId: BID_ID, vastXml: '', adhese: { + origin: '', + originInstance: '', originData: { adFormat: '', adId: '742470', diff --git a/test/spec/modules/adkernelBidAdapter_spec.js b/test/spec/modules/adkernelBidAdapter_spec.js index ef95febf13d..87504aa46af 100644 --- a/test/spec/modules/adkernelBidAdapter_spec.js +++ b/test/spec/modules/adkernelBidAdapter_spec.js @@ -2,6 +2,7 @@ import {expect} from 'chai'; import {spec} from 'modules/adkernelBidAdapter.js'; import * as utils from 'src/utils.js'; import {NATIVE, BANNER, VIDEO} from 'src/mediaTypes'; +import {config} from 'src/config.js'; describe('Adkernel adapter', function () { const bid1_zone1 = { @@ -170,12 +171,13 @@ describe('Adkernel adapter', function () { nurl: 'https://rtb.com/win?i=ZjKoPYSFI3Y_0', adm: '', w: 300, - h: 250 + h: 250, + dealid: 'deal' }] }], cur: 'USD', ext: { - adk_usersync: ['https://adk.sync.com/sync'] + adk_usersync: [{type: 1, url: 'https://adk.sync.com/sync'}] } }, videoBidResponse = { id: '47ce4badcf7482', @@ -194,7 +196,7 @@ describe('Adkernel adapter', function () { }, usersyncOnlyResponse = { id: 'nobid1', ext: { - adk_usersync: ['https://adk.sync.com/sync'] + adk_usersync: [{type: 2, url: 'https://adk.sync.com/sync'}] } }, nativeResponse = { id: '56fbc713-b737-4651-9050-13376aed9818', @@ -228,13 +230,22 @@ describe('Adkernel adapter', function () { cur: 'USD' }; + var sandbox; + beforeEach(function () { + sandbox = sinon.sandbox.create(); + }); + + afterEach(function () { + sandbox.restore(); + }); + function buildBidderRequest(url = 'https://example.com/index.html', params = {}) { - return Object.assign({}, params, {refererInfo: {referer: url, reachedTop: true}, timeout: 3000}); + return Object.assign({}, params, {refererInfo: {referer: url, reachedTop: true}, timeout: 3000, bidderCode: 'adkernel'}); } const DEFAULT_BIDDER_REQUEST = buildBidderRequest(); function buildRequest(bidRequests, bidderRequest = DEFAULT_BIDDER_REQUEST, dnt = true) { - let dntmock = sinon.stub(utils, 'getDNT').callsFake(() => dnt); + let dntmock = sandbox.stub(utils, 'getDNT').callsFake(() => dnt); let pbRequests = spec.buildRequests(bidRequests, bidderRequest); dntmock.restore(); let rtbRequests = pbRequests.map(r => JSON.parse(r.data)); @@ -306,6 +317,7 @@ describe('Adkernel adapter', function () { it('should fill device with caller macro', function () { expect(bidRequest).to.have.property('device'); expect(bidRequest.device).to.have.property('ip', 'caller'); + expect(bidRequest.device).to.have.property('ipv6', 'caller'); expect(bidRequest.device).to.have.property('ua', 'caller'); expect(bidRequest.device).to.have.property('dnt', 1); }); @@ -403,6 +415,84 @@ describe('Adkernel adapter', function () { }); }); + describe('User sync request signals', function() { + it('should respect syncEnabled option', function() { + config.setConfig({ + userSync: { + syncEnabled: false, + filterSettings: { + all: { + bidders: '*', + filter: 'include' + } + } + } + }); + let [pbRequests, bidRequests] = buildRequest([bid1_zone1]); + expect(bidRequests).to.have.length(1); + expect(bidRequests[0]).to.not.have.property('ext'); + }); + + it('should respect all config node', function() { + config.setConfig({ + userSync: { + syncEnabled: true, + filterSettings: { + all: { + bidders: '*', + filter: 'include' + } + } + } + }); + let [pbRequests, bidRequests] = buildRequest([bid1_zone1]); + expect(bidRequests).to.have.length(1); + expect(bidRequests[0].ext).to.have.property('adk_usersync', 1); + }); + + it('should respect exclude filter', function() { + config.setConfig({ + userSync: { + syncEnabled: true, + filterSettings: { + image: { + bidders: '*', + filter: 'include' + }, + iframe: { + bidders: ['adkernel'], + filter: 'exclude' + } + } + } + }); + let [pbRequests, bidRequests] = buildRequest([bid1_zone1]); + expect(bidRequests).to.have.length(1); + expect(bidRequests[0].ext).to.have.property('adk_usersync', 2); + }); + + it('should respect total exclusion', function() { + config.setConfig({ + userSync: { + syncEnabled: true, + filterSettings: { + image: { + bidders: ['adkernel'], + filter: 'exclude' + }, + iframe: { + bidders: ['adkernel'], + filter: 'exclude' + } + } + } + }); + let [pbRequests, bidRequests] = buildRequest([bid1_zone1]); + expect(bidRequests).to.have.length(1); + expect(bidRequests[0]).to.not.have.property('ext'); + }); + }); + describe('responses processing', function () { it('should return fully-initialized banner bid-response', function () { let [pbRequests, _] = buildRequest([bid1_zone1]); @@ -416,6 +506,7 @@ describe('Adkernel adapter', function () { expect(resp).to.have.property('ttl'); expect(resp).to.have.property('mediaType', BANNER); expect(resp).to.have.property('ad'); + expect(resp).to.have.property('dealId', 'deal'); expect(resp.ad).to.have.string(''); }); @@ -444,12 +535,18 @@ describe('Adkernel adapter', function () { }); it('should perform usersync', function () { - let syncs = spec.getUserSyncs({iframeEnabled: false}, [{body: bidResponse1}]); + let syncs = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, []); expect(syncs).to.have.length(0); - syncs = spec.getUserSyncs({iframeEnabled: true}, [{body: bidResponse1}]); + syncs = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false}, [{body: bidResponse1}]); + expect(syncs).to.have.length(0); + syncs = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [{body: bidResponse1}]); expect(syncs).to.have.length(1); expect(syncs[0]).to.have.property('type', 'iframe'); expect(syncs[0]).to.have.property('url', 'https://adk.sync.com/sync'); + syncs = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [{body: usersyncOnlyResponse}]); + expect(syncs).to.have.length(1); + expect(syncs[0]).to.have.property('type', 'image'); + expect(syncs[0]).to.have.property('url', 'https://adk.sync.com/sync'); }); }); diff --git a/test/spec/modules/adnowBidAdapter_spec.js b/test/spec/modules/adnowBidAdapter_spec.js new file mode 100644 index 00000000000..a8013e3fa04 --- /dev/null +++ b/test/spec/modules/adnowBidAdapter_spec.js @@ -0,0 +1,163 @@ +import { expect } from 'chai'; +import { spec } from 'modules/adnowBidAdapter.js'; + +describe('adnowBidAdapter', function () { + describe('isBidRequestValid', function () { + it('Should return true', function() { + expect(spec.isBidRequestValid({ + bidder: 'adnow', + params: { + codeId: 12345 + } + })).to.equal(true); + }); + + it('Should return false when required params is not passed', function() { + expect(spec.isBidRequestValid({ + bidder: 'adnow', + params: {} + })).to.equal(false); + }); + }); + + describe('buildRequests', function() { + it('Common settings', function() { + const bidRequestData = [{ + bidId: 'bid12345', + params: { + codeId: 12345 + } + }]; + + const req = spec.buildRequests(bidRequestData); + const reqData = req[0].data; + + expect(reqData) + .to.match(/Id=12345/) + .to.match(/mediaType=native/) + .to.match(/out=prebid/) + .to.match(/requestid=bid12345/) + .to.match(/d_user_agent=.+/); + }); + + it('Banner sizes', function () { + const bidRequestData = [{ + bidId: 'bid12345', + params: { + codeId: 12345 + }, + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + } + }]; + + const req = spec.buildRequests(bidRequestData); + const reqData = req[0].data; + + expect(reqData).to.match(/sizes=300x250/); + }); + + it('Native sizes', function () { + const bidRequestData = [{ + bidId: 'bid12345', + params: { + codeId: 12345 + }, + mediaTypes: { + native: { + image: { + sizes: [100, 100] + } + } + } + }]; + + const req = spec.buildRequests(bidRequestData); + const reqData = req[0].data; + + expect(reqData) + .to.match(/width=100/) + .to.match(/height=100/); + }); + }); + + describe('interpretResponse', function() { + const request = { + bidRequest: { + bidId: 'bid12345' + } + }; + + it('Response with native bid', function() { + const response = { + currency: 'USD', + cpm: 0.5, + native: { + title: 'Title', + body: 'Body', + sponsoredBy: 'AdNow', + clickUrl: '//click.url', + image: { + url: '//img.url', + height: 200, + width: 200 + } + }, + meta: { + mediaType: 'native' + } + }; + + const bids = spec.interpretResponse({ body: response }, request); + expect(bids).to.be.an('array').that.is.not.empty; + + const bid = bids[0]; + expect(bid).to.have.keys('requestId', 'cpm', 'currency', 'native', 'creativeId', 'netRevenue', 'meta', 'ttl'); + + const nativePart = bid.native; + + expect(nativePart.title).to.be.equal('Title'); + expect(nativePart.body).to.be.equal('Body'); + expect(nativePart.clickUrl).to.be.equal('//click.url'); + expect(nativePart.image.url).to.be.equal('//img.url'); + expect(nativePart.image.height).to.be.equal(200); + expect(nativePart.image.width).to.be.equal(200); + }); + + it('Response with banner bid', function() { + const response = { + currency: 'USD', + cpm: 0.5, + ad: '
Banner
', + meta: { + mediaType: 'banner' + } + }; + + const bids = spec.interpretResponse({ body: response }, request); + expect(bids).to.be.an('array').that.is.not.empty; + + const bid = bids[0]; + expect(bid).to.have.keys( + 'requestId', 'cpm', 'currency', 'ad', 'creativeId', 'netRevenue', 'meta', 'ttl', 'width', 'height' + ); + + expect(bid.ad).to.be.equal('
Banner
'); + }); + + it('Response with no bid should return an empty array', function() { + const noBidResponses = [ + false, + {}, + {body: false}, + {body: {}} + ]; + + noBidResponses.forEach(response => { + return expect(spec.interpretResponse(response, request)).to.be.an('array').that.is.empty; + }); + }); + }); +}); diff --git a/test/spec/modules/adoceanBidAdapter_spec.js b/test/spec/modules/adoceanBidAdapter_spec.js index 1c3383be5aa..2b4b7d711e1 100644 --- a/test/spec/modules/adoceanBidAdapter_spec.js +++ b/test/spec/modules/adoceanBidAdapter_spec.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { spec } from 'modules/adoceanBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; +import { deepClone } from 'src/utils.js'; describe('AdoceanAdapter', function () { const adapter = newBidder(spec); @@ -20,7 +21,11 @@ describe('AdoceanAdapter', function () { 'emiter': 'myao.adocean.pl' }, 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250]], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + } + }, 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', @@ -51,7 +56,11 @@ describe('AdoceanAdapter', function () { 'emiter': 'myao.adocean.pl' }, 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250]], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, 'bidId': '30b31c1838de1e', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', @@ -64,7 +73,11 @@ describe('AdoceanAdapter', function () { 'emiter': 'myao.adocean.pl' }, 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250]], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 200], [600, 250]] + } + }, 'bidId': '30b31c1838de1f', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', @@ -78,12 +91,12 @@ describe('AdoceanAdapter', function () { } }; - it('should send two requests if slave is duplicated', () => { + it('should send two requests if slave is duplicated', function () { const nrOfRequests = spec.buildRequests(bidRequests, bidderRequest).length; expect(nrOfRequests).to.equal(2); }); - it('should add bidIdMap with correct slaveId => bidId mapping', () => { + it('should add bidIdMap with correct slaveId => bidId mapping', function () { const requests = spec.buildRequests(bidRequests, bidderRequest); for (let i = 0; i < bidRequests.length; i++) { expect(requests[i]).to.exist; @@ -108,6 +121,19 @@ describe('AdoceanAdapter', function () { expect(request.url).to.include('gdpr=1'); expect(request.url).to.include('gdpr_consent=' + bidderRequest.gdprConsent.consentString); }); + + it('should attach sizes information to url', function () { + let requests = spec.buildRequests(bidRequests, bidderRequest); + expect(requests[0].url).to.include('aosspsizes=myaozpniqismex~300x250_300x600'); + expect(requests[1].url).to.include('aosspsizes=myaozpniqismex~300x200_600x250'); + + const differentSlavesBids = deepClone(bidRequests); + differentSlavesBids[1].params.slaveId = 'adoceanmyaowafpdwlrks'; + requests = spec.buildRequests(differentSlavesBids, bidderRequest); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.include('aosspsizes=myaozpniqismex~300x250_300x600-myaowafpdwlrks~300x200_600x250'); + expect((requests[0].url.match(/aosspsizes=/g) || []).length).to.equal(1); + }); }) describe('interpretResponse', function () { diff --git a/test/spec/modules/adpartnerBidAdapter_spec.js b/test/spec/modules/adpartnerBidAdapter_spec.js new file mode 100644 index 00000000000..d30ef7ebf71 --- /dev/null +++ b/test/spec/modules/adpartnerBidAdapter_spec.js @@ -0,0 +1,234 @@ +import {expect} from 'chai'; +import {spec, ENDPOINT_PROTOCOL, ENDPOINT_DOMAIN, ENDPOINT_PATH} from 'modules/adpartnerBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'adpartner'; + +describe('AdpartnerAdapter', function () { + const adapter = newBidder(spec); + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.be.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + it('should return true when required params found', function () { + let validRequest = { + 'params': { + 'unitId': 123 + } + }; + expect(spec.isBidRequestValid(validRequest)).to.equal(true); + }); + + it('should return true when required params is srting', function () { + let validRequest = { + 'params': { + 'unitId': '456' + } + }; + expect(spec.isBidRequestValid(validRequest)).to.equal(true); + }); + + it('should return false when required params are not passed', function () { + let validRequest = { + 'params': { + 'unknownId': 123 + } + }; + expect(spec.isBidRequestValid(validRequest)).to.equal(false); + }); + + it('should return false when required params is 0', function () { + let validRequest = { + 'params': { + 'unitId': 0 + } + }; + expect(spec.isBidRequestValid(validRequest)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + let validEndpoint = ENDPOINT_PROTOCOL + '://' + ENDPOINT_DOMAIN + ENDPOINT_PATH + '?tag=123,456&sizes=300x250|300x600,728x90&referer=https%3A%2F%2Ftest.domain'; + + let validRequest = [ + { + 'bidder': BIDDER_CODE, + 'params': { + 'unitId': 123 + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e' + }, + { + 'bidder': BIDDER_CODE, + 'params': { + 'unitId': '456' + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '22aidtbx5eabd9' + } + ]; + + let bidderRequest = { + refererInfo: { + referer: 'https://test.domain' + } + }; + + it('bidRequest HTTP method', function () { + const request = spec.buildRequests(validRequest, bidderRequest); + expect(request.method).to.equal('POST'); + }); + + it('bidRequest url', function () { + const request = spec.buildRequests(validRequest, bidderRequest); + expect(request.url).to.equal(validEndpoint); + }); + + it('bidRequest data', function () { + const request = spec.buildRequests(validRequest, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload[0].unitId).to.equal(123); + expect(payload[0].sizes).to.deep.equal([[300, 250], [300, 600]]); + expect(payload[0].bidId).to.equal('30b31c1838de1e'); + expect(payload[1].unitId).to.equal(456); + expect(payload[1].sizes).to.deep.equal([[728, 90]]); + expect(payload[1].bidId).to.equal('22aidtbx5eabd9'); + }); + }); + + describe('joinSizesToString', function () { + it('success convert sizes list to string', function () { + const sizesStr = spec.joinSizesToString([[300, 250], [300, 600]]); + expect(sizesStr).to.equal('300x250|300x600'); + }); + }); + + describe('interpretResponse', function () { + const bidRequest = { + 'method': 'POST', + 'url': ENDPOINT_PROTOCOL + '://' + ENDPOINT_DOMAIN + ENDPOINT_PATH + '?tag=123,456&code=adunit-code-1,adunit-code-2&bid=30b31c1838de1e,22aidtbx5eabd9&sizes=300x250|300x600,728x90&referer=https%3A%2F%2Ftest.domain', + 'data': '[{"unitId": 13144370,"adUnitCode": "div-gpt-ad-1460505748561-0","sizes": [[300, 250], [300, 600]],"bidId": "2bdcb0b203c17d","referer": "https://test.domain/index.html"},{"unitId": 13144370,"adUnitCode":"div-gpt-ad-1460505748561-1","sizes": [[768, 90]],"bidId": "3dc6b8084f91a8","referer": "https://test.domain/index.html"}]' + }; + + const bidResponse = { + body: { + 'div-gpt-ad-1460505748561-0': + { + 'ad': '
ad
', + 'width': 300, + 'height': 250, + 'creativeId': '8:123456', + 'syncs': [ + {'type': 'image', 'url': 'https://test.domain/tracker_1.gif'}, + {'type': 'image', 'url': 'https://test.domain/tracker_2.gif'}, + {'type': 'image', 'url': 'https://test.domain/tracker_3.gif'} + ], + 'winNotification': [ + { + 'method': 'POST', + 'path': '/hb/bid_won?test=1', + 'data': { + 'ad': [ + {'dsp': 8, 'id': 800008, 'cost': 1.0e-5, 'nurl': 'https://test.domain/'} + ], + 'unit_id': 1234, + 'site_id': 123 + } + } + ], + 'cpm': 0.01, + 'currency': 'USD', + 'netRevenue': true + } + }, + headers: {} + }; + + it('result is correct', function () { + const result = spec.interpretResponse(bidResponse, bidRequest); + expect(result[0].requestId).to.equal('2bdcb0b203c17d'); + expect(result[0].cpm).to.equal(0.01); + expect(result[0].width).to.equal(300); + expect(result[0].height).to.equal(250); + expect(result[0].creativeId).to.equal('8:123456'); + expect(result[0].currency).to.equal('USD'); + expect(result[0].ttl).to.equal(60); + expect(result[0].winNotification[0]).to.deep.equal({'method': 'POST', 'path': '/hb/bid_won?test=1', 'data': {'ad': [{'dsp': 8, 'id': 800008, 'cost': 1.0e-5, 'nurl': 'https://test.domain/'}], 'unit_id': 1234, 'site_id': 123}}); + }); + }); + + describe('adResponse', function () { + const bid = { + 'unitId': 13144370, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '2bdcb0b203c17d', + 'referer': 'https://test.domain/index.html' + }; + const ad = { + 'ad': '
ad
', + 'width': 300, + 'height': 250, + 'creativeId': '8:123456', + 'syncs': [], + 'winNotification': [], + 'cpm': 0.01, + 'currency': 'USD', + 'netRevenue': true + }; + + it('fill ad for response', function () { + const result = spec.adResponse(bid, ad); + expect(result.requestId).to.equal('2bdcb0b203c17d'); + expect(result.cpm).to.equal(0.01); + expect(result.width).to.equal(300); + expect(result.height).to.equal(250); + expect(result.creativeId).to.equal('8:123456'); + expect(result.currency).to.equal('USD'); + expect(result.ttl).to.equal(60); + }); + }); + + describe('onBidWon', function () { + const bid = { + winNotification: [ + { + 'method': 'POST', + 'path': '/hb/bid_won?test=1', + 'data': { + 'ad': [ + {'dsp': 8, 'id': 800008, 'cost': 0.01, 'nurl': 'http://test.domain/'} + ], + 'unit_id': 1234, + 'site_id': 123 + } + } + ] + }; + + let ajaxStub; + + beforeEach(() => { + ajaxStub = sinon.stub(spec, 'postRequest') + }) + + afterEach(() => { + ajaxStub.restore() + }) + + it('calls adpartner\'s callback endpoint', () => { + const result = spec.onBidWon(bid); + expect(result).to.equal(true); + expect(ajaxStub.calledOnce).to.equal(true); + expect(ajaxStub.firstCall.args[0]).to.equal(ENDPOINT_PROTOCOL + '://' + ENDPOINT_DOMAIN + '/hb/bid_won?test=1'); + expect(ajaxStub.firstCall.args[1]).to.deep.equal(JSON.stringify(bid.winNotification[0].data)); + }); + }); +}); diff --git a/test/spec/modules/adpod_spec.js b/test/spec/modules/adpod_spec.js index ff416e05522..5e4bcce1fe6 100644 --- a/test/spec/modules/adpod_spec.js +++ b/test/spec/modules/adpod_spec.js @@ -981,7 +981,7 @@ describe('adpod.js', function () { durationBucket: 15 }, meta: { - iabSubCatId: 'testCategory_123' + primaryCatId: 'testCategory_123' }, vastXml: 'test XML here' }; @@ -1050,7 +1050,7 @@ describe('adpod.js', function () { }); let goodBid = utils.deepClone(adpodTestBid); - goodBid.meta.iabSubCatId = undefined; + goodBid.meta.primaryCatId = undefined; checkVideoBidSetupHook(callbackFn, goodBid, bidderRequestNoExact, {}, ADPOD); expect(callbackResult).to.be.null; expect(bailResult).to.equal(true); @@ -1074,7 +1074,7 @@ describe('adpod.js', function () { } let noCatBid = utils.deepClone(adpodTestBid); - noCatBid.meta.iabSubCatId = undefined; + noCatBid.meta.primaryCatId = undefined; testInvalidAdpodBid(noCatBid, false); let noContextBid = utils.deepClone(adpodTestBid); @@ -1101,7 +1101,7 @@ describe('adpod.js', function () { durationSeconds: 30 }, meta: { - iabSubCatId: 'testCategory_123' + primaryCatId: 'testCategory_123' }, vastXml: '' }; diff --git a/test/spec/modules/adprimeBidAdapter_spec.js b/test/spec/modules/adprimeBidAdapter_spec.js index 7524665e33f..fe05634baae 100644 --- a/test/spec/modules/adprimeBidAdapter_spec.js +++ b/test/spec/modules/adprimeBidAdapter_spec.js @@ -55,7 +55,7 @@ describe('AdprimebBidAdapter', function () { expect(data.gdpr).to.not.exist; expect(data.ccpa).to.not.exist; let placement = data['placements'][0]; - expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'sizes', 'hPlayer', 'wPlayer', 'schain'); + expect(placement).to.have.keys('placementId', 'bidId', 'identeties', 'traffic', 'sizes', 'hPlayer', 'wPlayer', 'schain', 'keywords'); expect(placement.placementId).to.equal(0); expect(placement.bidId).to.equal('23fhj33i987f'); expect(placement.traffic).to.equal(BANNER); @@ -106,6 +106,23 @@ describe('AdprimebBidAdapter', function () { expect(data.placements).to.be.an('array').that.is.empty; }); }); + describe('buildRequests with user ids', function () { + bid.userId = {} + bid.userId.idl_env = 'idl_env123'; + let serverRequest = spec.buildRequests([bid], bidderRequest); + it('Return bids with user identeties', function () { + let data = serverRequest.data; + let placements = data['placements']; + expect(data).to.be.an('object'); + for (let i = 0; i < placements.length; i++) { + let placement = placements[i]; + expect(placement).to.have.property('identeties') + expect(placement.identeties).to.be.an('object') + expect(placement.identeties).to.have.property('identityLink') + expect(placement.identeties.identityLink).to.be.equal('idl_env123') + } + }); + }); describe('interpretResponse', function () { it('Should interpret banner response', function () { const banner = { diff --git a/test/spec/modules/adrelevantisBidAdapter_spec.js b/test/spec/modules/adrelevantisBidAdapter_spec.js new file mode 100644 index 00000000000..11a6a14a353 --- /dev/null +++ b/test/spec/modules/adrelevantisBidAdapter_spec.js @@ -0,0 +1,769 @@ +import { expect } from 'chai'; +import { spec } from 'modules/adrelevantisBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import * as bidderFactory from 'src/adapters/bidderFactory.js'; +import { deepClone } from 'src/utils.js'; +import { config } from 'src/config.js'; + +const ENDPOINT = 'https://ssp.adrelevantis.com/prebid'; + +describe('AdrelevantisAdapter', function () { + const adapter = newBidder(spec); + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + let bid = { + 'bidder': 'adrelevantis', + 'params': { + 'placementId': '10433394' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', function () { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + 'placementId': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + let bidRequests = [ + { + 'bidder': 'adrelevantis', + 'params': { + 'placementId': '10433394' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + } + ]; + + it('should parse out private sizes', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placementId: '10433394', + privateSizes: [300, 250] + } + } + ); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].private_sizes).to.exist; + expect(payload.tags[0].private_sizes).to.deep.equal([{width: 300, height: 250}]); + }); + + it('should add source and verison to the tag', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.sdk).to.exist; + expect(payload.sdk).to.deep.equal({ + source: 'pbjs', + version: '$prebid.version$' + }); + }); + + it('should populate the ad_types array on all requests', function () { + ['banner', 'video', 'native'].forEach(type => { + const bidRequest = Object.assign({}, bidRequests[0]); + bidRequest.mediaTypes = {}; + bidRequest.mediaTypes[type] = {}; + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].ad_types).to.deep.equal([type]); + }); + }); + + it('should populate the ad_types array on outstream requests', function () { + const bidRequest = Object.assign({}, bidRequests[0]); + bidRequest.mediaTypes = {}; + bidRequest.mediaTypes.video = {context: 'outstream'}; + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].ad_types).to.deep.equal(['video']); + }); + + it('sends bid request to ENDPOINT via POST', function () { + const request = spec.buildRequests(bidRequests); + expect(request.url).to.equal(ENDPOINT); + expect(request.method).to.equal('POST'); + }); + + it('should attach valid video params to the tag', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placementId: '10433394', + video: { + id: 123, + minduration: 100, + foobar: 'invalid' + } + } + } + ); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + expect(payload.tags[0].video).to.deep.equal({ + id: 123, + minduration: 100 + }); + }); + + it('should add video property when adUnit includes a renderer', function () { + const videoData = { + mediaTypes: { + video: { + context: 'outstream', + mimes: ['video/mp4'] + } + }, + params: { + placementId: '10433394', + video: { + skippable: true, + playback_method: ['auto_play_sound_off'] + } + } + }; + + let bidRequest1 = deepClone(bidRequests[0]); + bidRequest1 = Object.assign({}, bidRequest1, videoData, { + renderer: { + url: 'http://test.renderer.url', + render: function () {} + } + }); + + let bidRequest2 = deepClone(bidRequests[0]); + bidRequest2.adUnitCode = 'adUnit_code_2'; + bidRequest2 = Object.assign({}, bidRequest2, videoData); + + const request = spec.buildRequests([bidRequest1, bidRequest2]); + const payload = JSON.parse(request.data); + expect(payload.tags[0].video).to.deep.equal({ + skippable: true, + playback_method: ['auto_play_sound_off'], + custom_renderer_present: true + }); + expect(payload.tags[1].video).to.deep.equal({ + skippable: true, + playback_method: ['auto_play_sound_off'] + }); + }); + + it('should attach valid user params to the tag', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placementId: '10433394', + user: { + externalUid: '123', + foobar: 'invalid' + } + } + } + ); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.user).to.exist; + expect(payload.user).to.deep.equal({ + externalUid: '123', + }); + }); + + it('should contain hb_source value for other media', function() { + let bidRequest = Object.assign({}, + bidRequests[0], + { + mediaType: 'banner', + params: { + sizes: [[300, 250], [300, 600]], + placementId: 10433394 + } + } + ); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + expect(payload.tags[0].hb_source).to.deep.equal(1); + }); + + it('adds context data (category and keywords) to request when set', function() { + let bidRequest = Object.assign({}, bidRequests[0]); + sinon + .stub(config, 'getConfig') + .withArgs('fpd') + .returns({ + context: { + keywords: 'US Open', + data: { + category: 'sports/tennis' + } + } + }); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.fpd.keywords).to.equal('US Open'); + expect(payload.fpd.category).to.equal('sports/tennis'); + + config.getConfig.restore(); + }); + + it('should attach native params to the request', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + mediaType: 'native', + nativeParams: { + title: {required: true}, + body: {required: true}, + body2: {required: true}, + image: {required: true, sizes: [100, 100]}, + icon: {required: true}, + cta: {required: false}, + rating: {required: true}, + sponsoredBy: {required: true}, + privacyLink: {required: true}, + displayUrl: {required: true}, + address: {required: true}, + downloads: {required: true}, + likes: {required: true}, + phone: {required: true}, + price: {required: true}, + salePrice: {required: true} + } + } + ); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].native.layouts[0]).to.deep.equal({ + title: {required: true}, + description: {required: true}, + desc2: {required: true}, + main_image: {required: true, sizes: [{ width: 100, height: 100 }]}, + icon: {required: true}, + ctatext: {required: false}, + rating: {required: true}, + sponsored_by: {required: true}, + privacy_link: {required: true}, + displayurl: {required: true}, + address: {required: true}, + downloads: {required: true}, + likes: {required: true}, + phone: {required: true}, + price: {required: true}, + saleprice: {required: true}, + privacy_supported: true + }); + expect(payload.tags[0].hb_source).to.equal(1); + }); + + it('should always populated tags[].sizes with 1,1 for native if otherwise not defined', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + mediaType: 'native', + nativeParams: { + image: { required: true } + } + } + ); + bidRequest.sizes = [[150, 100], [300, 250]]; + + let request = spec.buildRequests([bidRequest]); + let payload = JSON.parse(request.data); + expect(payload.tags[0].sizes).to.deep.equal([{width: 150, height: 100}, {width: 300, height: 250}]); + + delete bidRequest.sizes; + + request = spec.buildRequests([bidRequest]); + payload = JSON.parse(request.data); + + expect(payload.tags[0].sizes).to.deep.equal([{width: 1, height: 1}]); + }); + + it('should convert keyword params to proper form and attaches to request', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placementId: '10433394', + keywords: { + single: 'val', + singleArr: ['val'], + singleArrNum: [5], + multiValMixed: ['value1', 2, 'value3'], + singleValNum: 123, + emptyStr: '', + emptyArr: [''], + badValue: {'foo': 'bar'} // should be dropped + } + } + } + ); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].keywords).to.deep.equal([{ + 'key': 'single', + 'value': ['val'] + }, { + 'key': 'singleArr', + 'value': ['val'] + }, { + 'key': 'singleArrNum', + 'value': ['5'] + }, { + 'key': 'multiValMixed', + 'value': ['value1', '2', 'value3'] + }, { + 'key': 'singleValNum', + 'value': ['123'] + }, { + 'key': 'emptyStr' + }, { + 'key': 'emptyArr' + }]); + }); + + it('should add payment rules to the request', function () { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placementId: '10433394', + usePaymentRule: true + } + } + ); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].use_pmt_rule).to.equal(true); + }); + + it('should add gdpr consent information to the request', function () { + let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; + let bidderRequest = { + 'bidderCode': 'adrelevantis', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gdprConsent': { + consentString: consentString, + gdprApplies: true + } + }; + bidderRequest.bids = bidRequests; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.gdpr_consent).to.exist; + expect(payload.gdpr_consent.consent_string).to.exist.and.to.equal(consentString); + expect(payload.gdpr_consent.consent_required).to.exist.and.to.be.true; + }); + + it('supports sending hybrid mobile app parameters', function () { + let appRequest = Object.assign({}, + bidRequests[0], + { + params: { + placementId: '10433394', + app: { + id: 'B1O2W3M4AN.com.prebid.webview', + geo: { + lat: 40.0964439, + lng: -75.3009142 + }, + device_id: { + idfa: '4D12078D-3246-4DA4-AD5E-7610481E7AE', // Apple advertising identifier + aaid: '38400000-8cf0-11bd-b23e-10b96e40000d', // Android advertising identifier + md5udid: '5756ae9022b2ea1e47d84fead75220c8', // MD5 hash of the ANDROID_ID + sha1udid: '4DFAA92388699AC6539885AEF1719293879985BF', // SHA1 hash of the ANDROID_ID + windowsadid: '750c6be243f1c4b5c9912b95a5742fc5' // Windows advertising identifier + } + } + } + } + ); + const request = spec.buildRequests([appRequest]); + const payload = JSON.parse(request.data); + expect(payload.app).to.exist; + expect(payload.app).to.deep.equal({ + appid: 'B1O2W3M4AN.com.prebid.webview' + }); + expect(payload.device.device_id).to.exist; + expect(payload.device.device_id).to.deep.equal({ + aaid: '38400000-8cf0-11bd-b23e-10b96e40000d', + idfa: '4D12078D-3246-4DA4-AD5E-7610481E7AE', + md5udid: '5756ae9022b2ea1e47d84fead75220c8', + sha1udid: '4DFAA92388699AC6539885AEF1719293879985BF', + windowsadid: '750c6be243f1c4b5c9912b95a5742fc5' + }); + expect(payload.device.geo).to.exist; + expect(payload.device.geo).to.deep.equal({ + lat: 40.0964439, + lng: -75.3009142 + }); + }); + + it('should add referer info to payload', function () { + const bidRequest = Object.assign({}, bidRequests[0]) + const bidderRequest = { + refererInfo: { + referer: 'http://example.com/page.html', + reachedTop: true, + numIframes: 2, + stack: [ + 'http://example.com/page.html', + 'http://example.com/iframe1.html', + 'http://example.com/iframe2.html' + ] + } + } + const request = spec.buildRequests([bidRequest], bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.referrer_detection).to.exist; + expect(payload.referrer_detection).to.deep.equal({ + rd_ref: 'http%3A%2F%2Fexample.com%2Fpage.html', + rd_top: true, + rd_ifs: 2, + rd_stk: bidderRequest.refererInfo.stack.map((url) => encodeURIComponent(url)).join(',') + }); + }); + + it('should populate coppa if set in config', function () { + let bidRequest = Object.assign({}, bidRequests[0]); + sinon.stub(config, 'getConfig') + .withArgs('coppa') + .returns(true); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.user.coppa).to.equal(true); + + config.getConfig.restore(); + }); + }) + + describe('interpretResponse', function () { + let bfStub; + before(function() { + bfStub = sinon.stub(bidderFactory, 'getIabSubCategory'); + }); + + after(function() { + bfStub.restore(); + }); + + let response = { + 'version': '3.0.0', + 'tags': [ + { + 'uuid': '3db3773286ee59', + 'tag_id': 10433394, + 'auction_id': '4534722592064951574', + 'nobid': false, + 'no_ad_url': 'http://lax1-ib.adnxs.com/no-ad', + 'timeout_ms': 10000, + 'ad_profile_id': 27079, + 'ads': [ + { + 'content_source': 'rtb', + 'ad_type': 'banner', + 'buyer_member_id': 958, + 'creative_id': 29681110, + 'media_type_id': 1, + 'media_subtype_id': 1, + 'cpm': 0.5, + 'cpm_publisher_currency': 0.5, + 'publisher_currency_code': '$', + 'client_initiated_ad_counting': true, + 'viewability': { + 'config': '' + }, + 'rtb': { + 'banner': { + 'content': '', + 'width': 300, + 'height': 250 + }, + 'trackers': [ + { + 'impression_urls': [ + 'http://lax1-ib.adnxs.com/impression' + ], + 'video_events': {} + } + ] + } + } + ] + } + ] + }; + + it('should get correct bid response', function () { + let expectedResponse = [ + { + 'requestId': '3db3773286ee59', + 'cpm': 0.5, + 'creativeId': 29681110, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '', + 'mediaType': 'banner', + 'currency': 'USD', + 'ttl': 300, + 'netRevenue': true, + 'adUnitCode': 'code', + 'adrelevantis': { + 'buyerMemberId': 958 + } + } + ]; + let bidderRequest = { + bids: [{ + bidId: '3db3773286ee59', + adUnitCode: 'code' + }] + } + let result = spec.interpretResponse({ body: response }, {bidderRequest}); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + }); + + it('handles nobid responses', function () { + let response = { + 'version': '0.0.1', + 'tags': [{ + 'uuid': '84ab500420319d', + 'tag_id': 5976557, + 'auction_id': '297492697822162468', + 'nobid': true + }] + }; + let bidderRequest; + + let result = spec.interpretResponse({ body: response }, {bidderRequest}); + expect(result.length).to.equal(0); + }); + + it('handles outstream video responses', function () { + let response = { + 'tags': [{ + 'uuid': '84ab500420319d', + 'ads': [{ + 'ad_type': 'video', + 'cpm': 0.500000, + 'notify_url': 'imptracker.com', + 'rtb': { + 'video': { + 'content': '' + } + }, + 'javascriptTrackers': '' + }] + }] + }; + let bidderRequest = { + bids: [{ + bidId: '84ab500420319d', + adUnitCode: 'code', + mediaTypes: { + video: { + context: 'outstream' + } + } + }] + } + + let result = spec.interpretResponse({ body: response }, {bidderRequest}); + expect(result[0]).to.have.property('vastXml'); + expect(result[0]).to.have.property('vastImpUrl'); + expect(result[0]).to.have.property('mediaType', 'video'); + }); + + it('handles instream video responses', function () { + let response = { + 'tags': [{ + 'uuid': '84ab500420319d', + 'ads': [{ + 'ad_type': 'video', + 'cpm': 0.500000, + 'notify_url': 'imptracker.com', + 'rtb': { + 'video': { + 'asset_url': 'https://sample.vastURL.com/here/vid' + } + }, + 'javascriptTrackers': '' + }] + }] + }; + let bidderRequest = { + bids: [{ + bidId: '84ab500420319d', + adUnitCode: 'code', + mediaTypes: { + video: { + context: 'instream' + } + } + }] + } + + let result = spec.interpretResponse({ body: response }, {bidderRequest}); + expect(result[0]).to.have.property('vastUrl'); + expect(result[0]).to.have.property('vastImpUrl'); + expect(result[0]).to.have.property('mediaType', 'video'); + }); + + it('handles native responses', function () { + let response1 = deepClone(response); + response1.tags[0].ads[0].ad_type = 'native'; + response1.tags[0].ads[0].rtb.native = { + 'title': 'Native Creative', + 'desc': 'Cool description great stuff', + 'desc2': 'Additional body text', + 'ctatext': 'Do it', + 'sponsored': 'AppNexus', + 'icon': { + 'width': 0, + 'height': 0, + 'url': 'https://cdn.adnxs.com/icon.png' + }, + 'main_img': { + 'width': 2352, + 'height': 1516, + 'url': 'https://cdn.adnxs.com/img.png' + }, + 'link': { + 'url': 'https://www.appnexus.com', + 'fallback_url': '', + 'click_trackers': ['https://nym1-ib.adnxs.com/click'] + }, + 'impression_trackers': ['https://example.com'], + 'rating': '5', + 'displayurl': 'https://AppNexus.com/?url=display_url', + 'likes': '38908320', + 'downloads': '874983', + 'price': '9.99', + 'saleprice': 'FREE', + 'phone': '1234567890', + 'address': '28 W 23rd St, New York, NY 10010', + 'privacy_link': 'https://appnexus.com/?url=privacy_url', + 'javascriptTrackers': '' + }; + let bidderRequest = { + bids: [{ + bidId: '3db3773286ee59', + adUnitCode: 'code' + }] + } + + let result = spec.interpretResponse({ body: response1 }, {bidderRequest}); + expect(result[0].native.title).to.equal('Native Creative'); + expect(result[0].native.body).to.equal('Cool description great stuff'); + expect(result[0].native.cta).to.equal('Do it'); + expect(result[0].native.image.url).to.equal('https://cdn.adnxs.com/img.png'); + }); + + it('supports configuring outstream renderers', function () { + const outstreamResponse = deepClone(response); + outstreamResponse.tags[0].ads[0].rtb.video = {}; + outstreamResponse.tags[0].ads[0].renderer_url = 'renderer.js'; + + const bidderRequest = { + bids: [{ + bidId: '3db3773286ee59', + renderer: { + options: { + adText: 'configured' + } + }, + mediaTypes: { + video: { + context: 'outstream' + } + } + }] + }; + + const result = spec.interpretResponse({ body: outstreamResponse }, {bidderRequest}); + expect(result[0].renderer.config).to.deep.equal( + bidderRequest.bids[0].renderer.options + ); + }); + + it('should add deal_priority and deal_code', function() { + let responseWithDeal = deepClone(response); + responseWithDeal.tags[0].ads[0].deal_priority = 'high'; + responseWithDeal.tags[0].ads[0].deal_code = '123'; + + let bidderRequest = { + bids: [{ + bidId: '3db3773286ee59', + adUnitCode: 'code' + }] + } + let result = spec.interpretResponse({ body: responseWithDeal }, {bidderRequest}); + expect(Object.keys(result[0].adrelevantis)).to.include.members(['buyerMemberId', 'dealPriority', 'dealCode']); + }); + + it('should add advertiser id', function() { + let responseAdvertiserId = deepClone(response); + responseAdvertiserId.tags[0].ads[0].advertiser_id = '123'; + + let bidderRequest = { + bids: [{ + bidId: '3db3773286ee59', + adUnitCode: 'code' + }] + } + let result = spec.interpretResponse({ body: responseAdvertiserId }, {bidderRequest}); + expect(Object.keys(result[0].meta)).to.include.members(['advertiserId']); + }) + }); +}); diff --git a/test/spec/modules/adtargetBidAdapter_spec.js b/test/spec/modules/adtargetBidAdapter_spec.js new file mode 100644 index 00000000000..5a867e7dd52 --- /dev/null +++ b/test/spec/modules/adtargetBidAdapter_spec.js @@ -0,0 +1,338 @@ +import { expect } from 'chai'; +import { spec } from 'modules/adtargetBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import { config } from 'src/config.js'; + +const DISPLAY_REQUEST = { + 'bidder': 'adtarget', + 'params': { + 'aid': 12345 + }, + 'schain': { ver: 1 }, + 'userId': { criteo: 2 }, + 'mediaTypes': { 'banner': { 'sizes': [300, 250] } }, + 'bidderRequestId': '7101db09af0db2', + 'auctionId': '2e41f65424c87c', + 'adUnitCode': 'adunit-code', + 'bidId': '84ab500420319d', +}; + +const VIDEO_REQUEST = { + 'bidder': 'adtarget', + 'mediaTypes': { + 'video': { + 'playerSize': [[480, 360], [640, 480]] + } + }, + 'params': { + 'aid': 12345 + }, + 'bidderRequestId': '7101db09af0db2', + 'auctionId': '2e41f65424c87c', + 'adUnitCode': 'adunit-code', + 'bidId': '84ab500420319d' +}; + +const SERVER_VIDEO_RESPONSE = { + 'source': { 'aid': 12345, 'pubId': 54321 }, + 'bids': [{ + 'vastUrl': 'https://rtb.adtarget.com/vast/?adid=44F2AEB9BFC881B3', + 'requestId': '2e41f65424c87c', + 'url': '44F2AEB9BFC881B3', + 'creative_id': 342516, + 'durationSeconds': 30, + 'cmpId': 342516, + 'height': 480, + 'cur': 'USD', + 'width': 640, + 'cpm': 0.9 + }] +}; +const SERVER_DISPLAY_RESPONSE = { + 'source': { 'aid': 12345, 'pubId': 54321 }, + 'bids': [{ + 'ad': '', + 'requestId': '2e41f65424c87c', + 'creative_id': 342516, + 'cmpId': 342516, + 'height': 250, + 'cur': 'USD', + 'width': 300, + 'cpm': 0.9 + }], + 'cookieURLs': ['link1', 'link2'] +}; +const SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS = { + 'source': { 'aid': 12345, 'pubId': 54321 }, + 'bids': [{ + 'ad': '', + 'requestId': '2e41f65424c87c', + 'creative_id': 342516, + 'cmpId': 342516, + 'height': 250, + 'cur': 'USD', + 'width': 300, + 'cpm': 0.9 + }], + 'cookieURLs': ['link3', 'link4'], + 'cookieURLSTypes': ['image', 'iframe'] +}; +const videoBidderRequest = { + bidderCode: 'bidderCode', + bids: [{ mediaTypes: { video: {} }, bidId: '2e41f65424c87c' }] +}; + +const displayBidderRequest = { + bidderCode: 'bidderCode', + bids: [{ bidId: '2e41f65424c87c' }] +}; + +const displayBidderRequestWithConsents = { + bidderCode: 'bidderCode', + bids: [{ bidId: '2e41f65424c87c' }], + gdprConsent: { + gdprApplies: true, + consentString: 'test' + }, + uspConsent: 'iHaveIt' +}; + +const videoEqResponse = [{ + vastUrl: 'https://rtb.adtarget.com/vast/?adid=44F2AEB9BFC881B3', + requestId: '2e41f65424c87c', + creativeId: 342516, + mediaType: 'video', + netRevenue: true, + currency: 'USD', + height: 480, + width: 640, + ttl: 300, + cpm: 0.9 +}]; + +const displayEqResponse = [{ + requestId: '2e41f65424c87c', + creativeId: 342516, + mediaType: 'banner', + netRevenue: true, + currency: 'USD', + ad: '', + height: 250, + width: 300, + ttl: 300, + cpm: 0.9 +}]; + +describe('adtargetBidAdapter', () => { + const adapter = newBidder(spec); + describe('inherited functions', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('user syncs', () => { + describe('as image', () => { + it('should be returned if pixel enabled', () => { + const syncs = spec.getUserSyncs({ pixelEnabled: true }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]); + + expect(syncs.map(s => s.url)).to.deep.equal([SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS.cookieURLs[0]]); + expect(syncs.map(s => s.type)).to.deep.equal(['image']); + }) + }) + + describe('as iframe', () => { + it('should be returned if iframe enabled', () => { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]); + + expect(syncs.map(s => s.url)).to.deep.equal([SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS.cookieURLs[1]]); + expect(syncs.map(s => s.type)).to.deep.equal(['iframe']); + }) + }) + + describe('user sync', () => { + it('should not be returned if passed syncs where already used', () => { + const syncs = spec.getUserSyncs({ + iframeEnabled: true, + pixelEnabled: true + }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]); + + expect(syncs).to.deep.equal([]); + }) + + it('should not be returned if pixel not set', () => { + const syncs = spec.getUserSyncs({}, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]); + + expect(syncs).to.be.empty; + }); + }); + describe('user syncs with both types', () => { + it('should be returned if pixel and iframe enabled', () => { + const mockedServerResponse = Object.assign({}, SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS, { 'cookieURLs': ['link5', 'link6'] }); + const syncs = spec.getUserSyncs({ + iframeEnabled: true, + pixelEnabled: true + }, [{ body: mockedServerResponse }]); + + expect(syncs.map(s => s.url)).to.deep.equal(mockedServerResponse.cookieURLs); + expect(syncs.map(s => s.type)).to.deep.equal(mockedServerResponse.cookieURLSTypes); + }); + }); + }); + + describe('isBidRequestValid', () => { + it('should return true when required params found', () => { + expect(spec.isBidRequestValid(VIDEO_REQUEST)).to.equal(true); + }); + + it('should return false when required params are not passed', () => { + let bid = Object.assign({}, VIDEO_REQUEST); + delete bid.params; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', () => { + let videoBidRequests = [VIDEO_REQUEST]; + let displayBidRequests = [DISPLAY_REQUEST]; + let videoAndDisplayBidRequests = [DISPLAY_REQUEST, VIDEO_REQUEST]; + const displayRequest = spec.buildRequests(displayBidRequests, {}); + const videoRequest = spec.buildRequests(videoBidRequests, {}); + const videoAndDisplayRequests = spec.buildRequests(videoAndDisplayBidRequests, {}); + + it('building requests as arrays', () => { + expect(videoRequest).to.be.a('array'); + expect(displayRequest).to.be.a('array'); + expect(videoAndDisplayRequests).to.be.a('array'); + }) + + it('sending as POST', () => { + const postActionMethod = 'POST' + const comparator = br => br.method === postActionMethod; + expect(videoRequest.every(comparator)).to.be.true; + expect(displayRequest.every(comparator)).to.be.true; + expect(videoAndDisplayRequests.every(comparator)).to.be.true; + }); + + it('sends correct video bid parameters', () => { + const data = videoRequest[0].data; + + const eq = { + CallbackId: '84ab500420319d', + AdType: 'video', + Aid: 12345, + Sizes: '480x360,640x480' + }; + expect(data.BidRequests[0]).to.deep.equal(eq); + }); + + it('sends correct display bid parameters', () => { + const data = displayRequest[0].data; + + const eq = { + CallbackId: '84ab500420319d', + AdType: 'display', + Aid: 12345, + Sizes: '300x250' + }; + + expect(data.BidRequests[0]).to.deep.equal(eq); + }); + + it('sends correct video and display bid parameters', () => { + const bidRequests = videoAndDisplayRequests[0].data; + const expectedBidReqs = [{ + CallbackId: '84ab500420319d', + AdType: 'display', + Aid: 12345, + Sizes: '300x250' + }, { + CallbackId: '84ab500420319d', + AdType: 'video', + Aid: 12345, + Sizes: '480x360,640x480' + }] + + expect(bidRequests.BidRequests).to.deep.equal(expectedBidReqs); + }); + + describe('publisher environment', () => { + const sandbox = sinon.sandbox.create(); + sandbox.stub(config, 'getConfig').callsFake((key) => { + const config = { + 'coppa': true + }; + return config[key]; + }); + const bidRequestWithPubSettingsData = spec.buildRequests([DISPLAY_REQUEST], displayBidderRequestWithConsents)[0].data; + sandbox.restore(); + it('sets GDPR', () => { + expect(bidRequestWithPubSettingsData.GDPR).to.be.equal(1); + expect(bidRequestWithPubSettingsData.GDPRConsent).to.be.equal(displayBidderRequestWithConsents.gdprConsent.consentString); + }); + it('sets USP', () => { + expect(bidRequestWithPubSettingsData.USP).to.be.equal(displayBidderRequestWithConsents.uspConsent); + }) + it('sets Coppa', () => { + expect(bidRequestWithPubSettingsData.Coppa).to.be.equal(1); + }) + it('sets Schain', () => { + expect(bidRequestWithPubSettingsData.Schain).to.be.deep.equal(DISPLAY_REQUEST.schain); + }) + it('sets UserId\'s', () => { + expect(bidRequestWithPubSettingsData.UserIds).to.be.deep.equal(DISPLAY_REQUEST.userId); + }) + }) + }); + + describe('interpretResponse', () => { + let serverResponse; + let adapterRequest; + let eqResponse; + + afterEach(() => { + serverResponse = null; + adapterRequest = null; + eqResponse = null; + }); + + it('should get correct video bid response', () => { + serverResponse = SERVER_VIDEO_RESPONSE; + adapterRequest = videoBidderRequest; + eqResponse = videoEqResponse; + + bidServerResponseCheck(); + }); + + it('should get correct display bid response', () => { + serverResponse = SERVER_DISPLAY_RESPONSE; + adapterRequest = displayBidderRequest; + eqResponse = displayEqResponse; + + bidServerResponseCheck(); + }); + + function bidServerResponseCheck() { + const result = spec.interpretResponse({ body: serverResponse }, { adapterRequest }); + + expect(result).to.deep.equal(eqResponse); + } + + function nobidServerResponseCheck() { + const noBidServerResponse = { bids: [] }; + const noBidResult = spec.interpretResponse({ body: noBidServerResponse }, { adapterRequest }); + + expect(noBidResult.length).to.equal(0); + } + + it('handles video nobid responses', () => { + adapterRequest = videoBidderRequest; + nobidServerResponseCheck(); + }); + + it('handles display nobid responses', () => { + adapterRequest = displayBidderRequest; + nobidServerResponseCheck(); + }); + }); +}); diff --git a/test/spec/modules/adtelligentBidAdapter_spec.js b/test/spec/modules/adtelligentBidAdapter_spec.js index ad81795d0e9..9c694668703 100644 --- a/test/spec/modules/adtelligentBidAdapter_spec.js +++ b/test/spec/modules/adtelligentBidAdapter_spec.js @@ -1,15 +1,23 @@ -import {expect} from 'chai'; -import {spec} from 'modules/adtelligentBidAdapter.js'; -import {newBidder} from 'src/adapters/bidderFactory.js'; - -const ENDPOINT = 'https://ghb.adtelligent.com/auction/'; +import { expect } from 'chai'; +import { spec } from 'modules/adtelligentBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import { config } from 'src/config.js'; + +const EXPECTED_ENDPOINTS = [ + 'https://ghb.adtelligent.com/v2/auction/', + 'https://ghb1.adtelligent.com/v2/auction/', + 'https://ghb2.adtelligent.com/v2/auction/', + 'https://ghb.adtelligent.com/v2/auction/' +]; const DISPLAY_REQUEST = { 'bidder': 'adtelligent', 'params': { 'aid': 12345 }, - 'mediaTypes': {'banner': {'sizes': [300, 250]}}, + 'schain': { ver: 1 }, + 'userId': { criteo: 2 }, + 'mediaTypes': { 'banner': { 'sizes': [300, 250] } }, 'bidderRequestId': '7101db09af0db2', 'auctionId': '2e41f65424c87c', 'adUnitCode': 'adunit-code', @@ -32,13 +40,32 @@ const VIDEO_REQUEST = { 'bidId': '84ab500420319d' }; +const ADPOD_REQUEST = { + 'bidder': 'adtelligent', + 'mediaTypes': { + 'video': { + 'context': 'adpod', + 'playerSize': [[640, 480]], + 'anyField': 10 + } + }, + 'params': { + 'aid': 12345 + }, + 'bidderRequestId': '7101db09af0db2', + 'auctionId': '2e41f65424c87c', + 'adUnitCode': 'adunit-code', + 'bidId': '2e41f65424c87c' +}; + const SERVER_VIDEO_RESPONSE = { - 'source': {'aid': 12345, 'pubId': 54321}, + 'source': { 'aid': 12345, 'pubId': 54321 }, 'bids': [{ 'vastUrl': 'http://rtb.adtelligent.com/vast/?adid=44F2AEB9BFC881B3', 'requestId': '2e41f65424c87c', 'url': '44F2AEB9BFC881B3', 'creative_id': 342516, + 'durationSeconds': 30, 'cmpId': 342516, 'height': 480, 'cur': 'USD', @@ -47,9 +74,9 @@ const SERVER_VIDEO_RESPONSE = { } ] }; - +const SERVER_OUSTREAM_VIDEO_RESPONSE = SERVER_VIDEO_RESPONSE; const SERVER_DISPLAY_RESPONSE = { - 'source': {'aid': 12345, 'pubId': 54321}, + 'source': { 'aid': 12345, 'pubId': 54321 }, 'bids': [{ 'ad': '', 'requestId': '2e41f65424c87c', @@ -63,7 +90,7 @@ const SERVER_DISPLAY_RESPONSE = { 'cookieURLs': ['link1', 'link2'] }; const SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS = { - 'source': {'aid': 12345, 'pubId': 54321}, + 'source': { 'aid': 12345, 'pubId': 54321 }, 'bids': [{ 'ad': '', 'requestId': '2e41f65424c87c', @@ -77,24 +104,42 @@ const SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS = { 'cookieURLs': ['link3', 'link4'], 'cookieURLSTypes': ['image', 'iframe'] }; - +const outstreamVideoBidderRequest = { + bidderCode: 'bidderCode', + bids: [{ + 'params': { + 'aid': 12345, + 'outstream': { + 'video_controls': 'show' + } + }, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480] + } + }, + bidId: '2e41f65424c87c' + }] +}; const videoBidderRequest = { bidderCode: 'bidderCode', - bids: [{mediaTypes: {video: {}}, bidId: '2e41f65424c87c'}] + bids: [{ mediaTypes: { video: {} }, bidId: '2e41f65424c87c' }] }; const displayBidderRequest = { bidderCode: 'bidderCode', - bids: [{bidId: '2e41f65424c87c'}] + bids: [{ bidId: '2e41f65424c87c' }] }; -const displayBidderRequestWithGdpr = { +const displayBidderRequestWithConsents = { bidderCode: 'bidderCode', - bids: [{bidId: '2e41f65424c87c'}], + bids: [{ bidId: '2e41f65424c87c' }], gdprConsent: { gdprApplies: true, consentString: 'test' - } + }, + uspConsent: 'iHaveIt' }; const videoEqResponse = [{ @@ -106,219 +151,259 @@ const videoEqResponse = [{ currency: 'USD', height: 480, width: 640, - ttl: 3600, + ttl: 300, cpm: 0.9 }]; const displayEqResponse = [{ requestId: '2e41f65424c87c', creativeId: 342516, - mediaType: 'display', + mediaType: 'banner', netRevenue: true, currency: 'USD', ad: '', height: 250, width: 300, - ttl: 3600, + ttl: 300, cpm: 0.9 }]; -describe('adtelligentBidAdapter', function () { +describe('adtelligentBidAdapter', () => { const adapter = newBidder(spec); + describe('inherited functions', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); - describe('user syncs as image', function () { - it('should be returned if pixel enabled', function () { - const syncs = spec.getUserSyncs({pixelEnabled: true}, [{body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS}]); + describe('user syncs', () => { + describe('as image', () => { + it('should be returned if pixel enabled', () => { + const syncs = spec.getUserSyncs({ pixelEnabled: true }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]); - expect(syncs.map(s => s.url)).to.deep.equal([SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS.cookieURLs[0]]); - expect(syncs.map(s => s.type)).to.deep.equal(['image']); + expect(syncs.map(s => s.url)).to.deep.equal([SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS.cookieURLs[0]]); + expect(syncs.map(s => s.type)).to.deep.equal(['image']); + }) }) - }) - describe('user syncs as iframe', function () { - it('should be returned if iframe enabled', function () { - const syncs = spec.getUserSyncs({iframeEnabled: true}, [{body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS}]); + describe('as iframe', () => { + it('should be returned if iframe enabled', () => { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]); - expect(syncs.map(s => s.url)).to.deep.equal([SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS.cookieURLs[1]]); - expect(syncs.map(s => s.type)).to.deep.equal(['iframe']); + expect(syncs.map(s => s.url)).to.deep.equal([SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS.cookieURLs[1]]); + expect(syncs.map(s => s.type)).to.deep.equal(['iframe']); + }) }) - }) - describe('user sync', function () { - it('should not be returned if passed syncs where already used', function () { - const syncs = spec.getUserSyncs({ - iframeEnabled: true, - pixelEnabled: true - }, [{body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS}]); + describe('user sync', () => { + it('should not be returned if passed syncs where already used', () => { + const syncs = spec.getUserSyncs({ + iframeEnabled: true, + pixelEnabled: true + }, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]); - expect(syncs).to.deep.equal([]); - }) - }); + expect(syncs).to.deep.equal([]); + }) - describe('user syncs with both types', function () { - it('should be returned if pixel and iframe enabled', function () { - const mockedServerResponse = Object.assign({}, SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS, {'cookieURLs': ['link5', 'link6']}); - const syncs = spec.getUserSyncs({ - iframeEnabled: true, - pixelEnabled: true - }, [{body: mockedServerResponse}]); + it('should not be returned if pixel not set', () => { + const syncs = spec.getUserSyncs({}, [{ body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS }]); - expect(syncs.map(s => s.url)).to.deep.equal(mockedServerResponse.cookieURLs); - expect(syncs.map(s => s.type)).to.deep.equal(mockedServerResponse.cookieURLSTypes); + expect(syncs).to.be.empty; + }); }); - }); - - describe('user syncs', function () { - it('should not be returned if pixel not set', function () { - const syncs = spec.getUserSyncs({}, [{body: SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS}]); - - expect(syncs).to.be.empty; + describe('user syncs with both types', () => { + it('should be returned if pixel and iframe enabled', () => { + const mockedServerResponse = Object.assign({}, SERVER_DISPLAY_RESPONSE_WITH_MIXED_SYNCS, { 'cookieURLs': ['link5', 'link6'] }); + const syncs = spec.getUserSyncs({ + iframeEnabled: true, + pixelEnabled: true + }, [{ body: mockedServerResponse }]); + + expect(syncs.map(s => s.url)).to.deep.equal(mockedServerResponse.cookieURLs); + expect(syncs.map(s => s.type)).to.deep.equal(mockedServerResponse.cookieURLSTypes); + }); }); }); - describe('inherited functions', function () { - it('exists and is a function', function () { - expect(adapter.callBids).to.exist.and.to.be.a('function'); - }); - }); - - describe('isBidRequestValid', function () { - it('should return true when required params found', function () { + describe('isBidRequestValid', () => { + it('should return true when required params found', () => { expect(spec.isBidRequestValid(VIDEO_REQUEST)).to.equal(true); }); - it('should return false when required params are not passed', function () { + it('should return false when required params are not passed', () => { let bid = Object.assign({}, VIDEO_REQUEST); delete bid.params; expect(spec.isBidRequestValid(bid)).to.equal(false); }); }); - describe('buildRequests', function () { + describe('buildRequests', () => { let videoBidRequests = [VIDEO_REQUEST]; let displayBidRequests = [DISPLAY_REQUEST]; let videoAndDisplayBidRequests = [DISPLAY_REQUEST, VIDEO_REQUEST]; - const displayRequest = spec.buildRequests(displayBidRequests, {}); const videoRequest = spec.buildRequests(videoBidRequests, {}); const videoAndDisplayRequests = spec.buildRequests(videoAndDisplayBidRequests, {}); + const rotatingRequest = spec.buildRequests(displayBidRequests, {}); + it('rotates endpoints', () => { + const bidReqUrls = [displayRequest[0], videoRequest[0], videoAndDisplayRequests[0], rotatingRequest[0]].map(br => br.url); + expect(bidReqUrls).to.deep.equal(EXPECTED_ENDPOINTS); + }) - it('sends bid request to ENDPOINT via GET', function () { - expect(videoRequest.method).to.equal('GET'); - expect(displayRequest.method).to.equal('GET'); - expect(videoAndDisplayRequests.method).to.equal('GET'); - }); + it('building requests as arrays', () => { + expect(videoRequest).to.be.a('array'); + expect(displayRequest).to.be.a('array'); + expect(videoAndDisplayRequests).to.be.a('array'); + }) - it('sends bid request to correct ENDPOINT', function () { - expect(videoRequest.url).to.equal(ENDPOINT); - expect(displayRequest.url).to.equal(ENDPOINT); - expect(videoAndDisplayRequests.url).to.equal(ENDPOINT); + it('sending as POST', () => { + const postActionMethod = 'POST' + const comparator = br => br.method === postActionMethod; + expect(videoRequest.every(comparator)).to.be.true; + expect(displayRequest.every(comparator)).to.be.true; + expect(videoAndDisplayRequests.every(comparator)).to.be.true; }); - - it('sends correct video bid parameters', function () { - const bid = Object.assign({}, videoRequest.data); - delete bid.domain; + it('forms correct ADPOD request', () => { + const pbBidReqData = spec.buildRequests([ADPOD_REQUEST], {})[0].data; + const impRequest = pbBidReqData.BidRequests[0] + expect(impRequest.AdType).to.be.equal('video'); + expect(impRequest.Adpod).to.be.a('object'); + expect(impRequest.Adpod.anyField).to.be.equal(10); + }) + it('sends correct video bid parameters', () => { + const data = videoRequest[0].data; const eq = { - callbackId: '84ab500420319d', - ad_type: 'video', - aid: 12345, - sizes: '480x360,640x480' + CallbackId: '84ab500420319d', + AdType: 'video', + Aid: 12345, + Sizes: '480x360,640x480' }; - - expect(bid).to.deep.equal(eq); + expect(data.BidRequests[0]).to.deep.equal(eq); }); - it('sends correct display bid parameters', function () { - const bid = Object.assign({}, displayRequest.data); - delete bid.domain; + it('sends correct display bid parameters', () => { + const data = displayRequest[0].data; const eq = { - callbackId: '84ab500420319d', - ad_type: 'display', - aid: 12345, - sizes: '300x250' + CallbackId: '84ab500420319d', + AdType: 'display', + Aid: 12345, + Sizes: '300x250' }; - expect(bid).to.deep.equal(eq); + expect(data.BidRequests[0]).to.deep.equal(eq); }); - it('sends correct video and display bid parameters', function () { - const bid = Object.assign({}, videoAndDisplayRequests.data); - delete bid.domain; - - const eq = { - callbackId: '84ab500420319d', - ad_type: 'display', - aid: 12345, - sizes: '300x250', - callbackId2: '84ab500420319d', - ad_type2: 'video', - aid2: 12345, - sizes2: '480x360,640x480' - }; - - expect(bid).to.deep.equal(eq); + it('sends correct video and display bid parameters', () => { + const bidRequests = videoAndDisplayRequests[0].data; + const expectedBidReqs = [{ + CallbackId: '84ab500420319d', + AdType: 'display', + Aid: 12345, + Sizes: '300x250' + }, { + CallbackId: '84ab500420319d', + AdType: 'video', + Aid: 12345, + Sizes: '480x360,640x480' + }] + + expect(bidRequests.BidRequests).to.deep.equal(expectedBidReqs); }); + + describe('publisher environment', () => { + const sandbox = sinon.sandbox.create(); + sandbox.stub(config, 'getConfig').callsFake((key) => { + const config = { + 'coppa': true + }; + return config[key]; + }); + const bidRequestWithPubSettingsData = spec.buildRequests([DISPLAY_REQUEST], displayBidderRequestWithConsents)[0].data; + sandbox.restore(); + it('sets GDPR', () => { + expect(bidRequestWithPubSettingsData.GDPR).to.be.equal(1); + expect(bidRequestWithPubSettingsData.GDPRConsent).to.be.equal(displayBidderRequestWithConsents.gdprConsent.consentString); + }); + it('sets USP', () => { + expect(bidRequestWithPubSettingsData.USP).to.be.equal(displayBidderRequestWithConsents.uspConsent); + }) + it('sets Coppa', () => { + expect(bidRequestWithPubSettingsData.Coppa).to.be.equal(1); + }) + it('sets Schain', () => { + expect(bidRequestWithPubSettingsData.Schain).to.be.deep.equal(DISPLAY_REQUEST.schain); + }) + it('sets UserId\'s', () => { + expect(bidRequestWithPubSettingsData.UserIds).to.be.deep.equal(DISPLAY_REQUEST.userId); + }) + }) }); - describe('interpretResponse', function () { + describe('interpretResponse', () => { let serverResponse; - let bidderRequest; + let adapterRequest; let eqResponse; - afterEach(function () { + afterEach(() => { serverResponse = null; - bidderRequest = null; + adapterRequest = null; eqResponse = null; }); - it('should get correct video bid response', function () { + it('should get correct video bid response', () => { serverResponse = SERVER_VIDEO_RESPONSE; - bidderRequest = videoBidderRequest; + adapterRequest = videoBidderRequest; eqResponse = videoEqResponse; bidServerResponseCheck(); }); - it('should get correct display bid response', function () { + it('should get correct display bid response', () => { serverResponse = SERVER_DISPLAY_RESPONSE; - bidderRequest = displayBidderRequest; + adapterRequest = displayBidderRequest; eqResponse = displayEqResponse; bidServerResponseCheck(); }); - it('should set gdpr data correctly', function () { - const builtRequestData = spec.buildRequests([DISPLAY_REQUEST], displayBidderRequestWithGdpr); - - expect(builtRequestData.data.gdpr).to.be.equal(1); - expect(builtRequestData.data.gdpr_consent).to.be.equal(displayBidderRequestWithGdpr.gdprConsent.consentString); - }); - function bidServerResponseCheck() { - const result = spec.interpretResponse({body: serverResponse}, {bidderRequest}); + const result = spec.interpretResponse({ body: serverResponse }, { adapterRequest }); expect(result).to.deep.equal(eqResponse); } function nobidServerResponseCheck() { - const noBidServerResponse = {bids: []}; - const noBidResult = spec.interpretResponse({body: noBidServerResponse}, {bidderRequest}); + const noBidServerResponse = { bids: [] }; + const noBidResult = spec.interpretResponse({ body: noBidServerResponse }, { adapterRequest }); expect(noBidResult.length).to.equal(0); } - it('handles video nobid responses', function () { - bidderRequest = videoBidderRequest; + it('handles video nobid responses', () => { + adapterRequest = videoBidderRequest; nobidServerResponseCheck(); }); - it('handles display nobid responses', function () { - bidderRequest = displayBidderRequest; + it('handles display nobid responses', () => { + adapterRequest = displayBidderRequest; nobidServerResponseCheck(); }); + + it('forms correct ADPOD response', () => { + const videoBids = spec.interpretResponse({ body: SERVER_VIDEO_RESPONSE }, { adapterRequest: { bids: [ADPOD_REQUEST] } }); + expect(videoBids[0].video.durationSeconds).to.be.equal(30); + expect(videoBids[0].video.context).to.be.equal('adpod'); + }) + describe('outstream setup', () => { + const videoBids = spec.interpretResponse({ body: SERVER_OUSTREAM_VIDEO_RESPONSE }, { adapterRequest: outstreamVideoBidderRequest }); + it('should return renderer with expected outstream params config', () => { + expect(!!videoBids[0].renderer).to.be.true; + expect(videoBids[0].renderer.getConfig().video_controls).to.equal('show'); + }) + }) }); }); diff --git a/test/spec/modules/adxcgBidAdapter_spec.js b/test/spec/modules/adxcgBidAdapter_spec.js index 306914960c3..f9aaea308a7 100644 --- a/test/spec/modules/adxcgBidAdapter_spec.js +++ b/test/spec/modules/adxcgBidAdapter_spec.js @@ -281,7 +281,7 @@ describe('AdxcgAdapter', function () { let bid = deepClone([bidBanner]); let bidderRequests = {}; - bid[0].userId = {id5id: 'id5idsample'}; + bid[0].userId = {id5id: {uid: 'id5idsample'}}; it('should send pubcid if available', function () { let request = spec.buildRequests(bid, bidderRequests); diff --git a/test/spec/modules/adxpremiumAnalyticsAdapter_spec.js b/test/spec/modules/adxpremiumAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..e4a8fa9dccd --- /dev/null +++ b/test/spec/modules/adxpremiumAnalyticsAdapter_spec.js @@ -0,0 +1,415 @@ +import adxpremiumAnalyticsAdapter from 'modules/adxpremiumAnalyticsAdapter.js'; +import { testSend } from 'modules/adxpremiumAnalyticsAdapter.js'; +import { expect } from 'chai'; +import adapterManager from 'src/adapterManager.js'; +import { server } from 'test/mocks/xhr.js'; + +let events = require('src/events'); +let constants = require('src/constants.json'); + +describe('AdxPremium analytics adapter', function () { + beforeEach(function () { + sinon.stub(events, 'getEvents').returns([]); + }); + + afterEach(function () { + events.getEvents.restore(); + }); + + describe('track', function () { + let initOptions = { + pubId: 123, + sid: 's2' + }; + + let auctionInit = { + 'auctionId': 'c4f0cce0-264c-483a-b2f4-8ac2248a896b', + 'timestamp': 1589707613899, + 'auctionStatus': 'inProgress', + 'adUnits': [ + { + 'code': 'div-gpt-ad-1533155193780-2', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ] + ] + } + }, + 'bids': [ + { + 'bidder': 'luponmedia', + 'params': { + 'siteId': 303522, + 'keyId': '4o2c4' + }, + 'crumbs': { + 'pubcid': 'aebbdfa9-3e0f-49b6-ad87-437aaa88db2d' + } + } + ], + 'sizes': [ + [ + 300, + 250 + ] + ], + 'transactionId': 'f68c54c2-0814-4ae5-95f5-09f6dd9dc1ef' + } + ], + 'adUnitCodes': [ + 'div-gpt-ad-1533155193780-2' + ], + 'labels': [ + 'BA' + ], + 'bidderRequests': [ + { + 'bidderCode': 'luponmedia', + 'auctionId': 'c4f0cce0-264c-483a-b2f4-8ac2248a896b', + 'bidderRequestId': '18c49b05a23645', + 'bids': [ + { + 'bidder': 'luponmedia', + 'params': { + 'siteId': 303522, + 'keyId': '4o2c4' + }, + 'crumbs': { + 'pubcid': 'aebbdfa9-3e0f-49b6-ad87-437aaa88db2d' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ] + ] + } + }, + 'adUnitCode': 'div-gpt-ad-1533155193780-2', + 'transactionId': 'f68c54c2-0814-4ae5-95f5-09f6dd9dc1ef', + 'sizes': [ + [ + 300, + 250 + ] + ], + 'bidId': '284f8e1469246a', + 'bidderRequestId': '18c49b05a23645', + 'auctionId': 'c4f0cce0-264c-483a-b2f4-8ac2248a896b', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0, + 'schain': { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'novi.ba', + 'sid': '199424', + 'hp': 1 + } + ] + } + } + ], + 'auctionStart': 1589707613899, + 'timeout': 2000, + 'refererInfo': { + 'referer': 'https://test.com/article/176067', + 'reachedTop': true, + 'numIframes': 0, + 'stack': [ + 'https://test.com/article/176067' + ] + }, + 'gdprConsent': {} + } + ], + 'noBids': [], + 'bidsReceived': [], + 'winningBids': [], + 'timeout': 2000, + 'config': { + 'pubId': 4444, + 'sid': 's2' + } + }; + + // requests & responses + let bidRequest = { + 'bidderCode': 'luponmedia', + 'auctionId': 'c4f0cce0-264c-483a-b2f4-8ac2248a896b', + 'bidderRequestId': '18c49b05a23645', + 'bids': [ + { + 'bidder': 'luponmedia', + 'params': { + 'siteId': 303522, + 'keyId': '4o2c4' + }, + 'crumbs': { + 'pubcid': 'aebbdfa9-3e0f-49b6-ad87-437aaa88db2d' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ] + ] + } + }, + 'adUnitCode': 'div-gpt-ad-1533155193780-2', + 'transactionId': 'f68c54c2-0814-4ae5-95f5-09f6dd9dc1ef', + 'sizes': [ + [ + 300, + 250 + ] + ], + 'bidId': '284f8e1469246a', + 'bidderRequestId': '18c49b05a23645', + 'auctionId': 'c4f0cce0-264c-483a-b2f4-8ac2248a896b', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0, + }, + { + 'bidder': 'luponmedia', + 'params': { + 'siteId': 303522, + 'keyId': '4o2c5' + }, + 'crumbs': { + 'pubcid': 'aebbdfa9-3e0f-49b6-ad87-437aaa88db2d' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ] + ] + } + }, + 'adUnitCode': 'div-gpt-ad-1533155193780-3', + 'transactionId': 'f68c54c2-0814-4ae5-95f5-09f6dd9dc1ef', + 'sizes': [ + [ + 300, + 250 + ] + ], + 'bidId': '284f8e1469246b', + 'bidderRequestId': '18c49b05a23645', + 'auctionId': 'c4f0cce0-264c-483a-b2f4-8ac2248a896b', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0, + } + ], + 'auctionStart': 1589707613899, + 'timeout': 2000, + 'refererInfo': { + 'referer': 'https://test.com/article/176067', + 'reachedTop': true, + 'numIframes': 0, + 'stack': [ + 'https://test.com/article/176067' + ] + }, + 'start': 1589707613908 + }; + + let bidResponse = { + 'bidderCode': 'luponmedia', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '3b40e0da8968f5', + 'requestId': '284f8e1469246a', + 'mediaType': 'banner', + 'source': 'client', + 'cpm': 0.43, + 'creativeId': '443801010', + 'currency': 'USD', + 'netRevenue': false, + 'ttl': 300, + 'referrer': '', + 'ad': " ", + 'originalCpm': '0.43', + 'originalCurrency': 'USD', + 'auctionId': 'c4f0cce0-264c-483a-b2f4-8ac2248a896b', + 'responseTimestamp': 1589707615188, + 'requestTimestamp': 1589707613908, + 'bidder': 'luponmedia', + 'adUnitCode': 'div-gpt-ad-1533155193780-2', + 'timeToRespond': 1280, + 'pbLg': '0.00', + 'pbMg': '0.40', + 'pbHg': '0.43', + 'pbAg': '0.40', + 'pbDg': '0.43', + 'pbCg': '0.43', + 'size': '300x250', + 'adserverTargeting': { + 'hb_bidder': 'luponmedia', + 'hb_adid': '3b40e0da8968f5', + 'hb_pb': '0.43', + 'hb_size': '300x250', + 'hb_source': 'client', + 'hb_format': 'banner' + } + }; + + // what we expect after general auction + + let expectedAfterBidData = JSON.parse(atob('eyJwdWJsaXNoZXJfaWQiOjEyMywiYXVjdGlvbl9pZCI6ImM0ZjBjY2UwLTI2NGMtNDgzYS1iMmY0LThhYzIyNDhhODk2YiIsInJlZmVyZXIiOiJodHRwczovL3Rlc3QuY29tL2FydGljbGUvMTc2MDY3Iiwic2NyZWVuX3Jlc29sdXRpb24iOiIxNDQweDkwMCIsImRldmljZV90eXBlIjoiZGVza3RvcCIsImdlbyI6bnVsbCwiZXZlbnRzIjpbeyJ0eXBlIjoiVElNRU9VVCIsImJpZGRlcl9jb2RlIjoibHVwb25tZWRpYSIsImV2ZW50X3RpbWVzdGFtcCI6MTU4OTcwNzYxMzkwOCwiYmlkX2dwdF9jb2RlcyI6eyJkaXYtZ3B0LWFkLTE1MzMxNTUxOTM3ODAtMiI6W1szMDAsMjUwXV0sImRpdi1ncHQtYWQtMTUzMzE1NTE5Mzc4MC0zIjpbWzMwMCwyNTBdXX19XX0=')); + expectedAfterBidData['screen_resolution'] = window.screen.width + 'x' + window.screen.height; + expectedAfterBidData = btoa(JSON.stringify(expectedAfterBidData)); + + let expectedAfterBid = { + 'query': 'mutation {createEvent(input: {event: {eventData: "' + expectedAfterBidData + '"}}) {event {createTime } } }' + }; + + // what we expect after timeout + + let expectedAfterTimeoutData = JSON.parse(atob('eyJwdWJsaXNoZXJfaWQiOjEyMywiYXVjdGlvbl9pZCI6ImM0ZjBjY2UwLTI2NGMtNDgzYS1iMmY0LThhYzIyNDhhODk2YiIsInJlZmVyZXIiOiJodHRwczovL3Rlc3QuY29tL2FydGljbGUvMTc2MDY3Iiwic2NyZWVuX3Jlc29sdXRpb24iOiIxNDQweDkwMCIsImRldmljZV90eXBlIjoiZGVza3RvcCIsImdlbyI6bnVsbCwiZXZlbnRzIjpbeyJ0eXBlIjoiVElNRU9VVCIsImJpZGRlcl9jb2RlIjoibHVwb25tZWRpYSIsImV2ZW50X3RpbWVzdGFtcCI6MTU4OTcwNzYxMzkwOCwiYmlkX2dwdF9jb2RlcyI6eyJkaXYtZ3B0LWFkLTE1MzMxNTUxOTM3ODAtMiI6W1szMDAsMjUwXV0sImRpdi1ncHQtYWQtMTUzMzE1NTE5Mzc4MC0zIjpbWzMwMCwyNTBdXX19XX0=')); + expectedAfterTimeoutData['screen_resolution'] = window.screen.width + 'x' + window.screen.height; + expectedAfterTimeoutData = btoa(JSON.stringify(expectedAfterTimeoutData)); + + let expectedAfterTimeout = { + 'query': 'mutation {createEvent(input: {event: {eventData: "' + expectedAfterTimeoutData + '"}}) {event {createTime } } }' + }; + + // lets simulate that some bidders timeout + let bidTimeoutArgsV1 = [ + { + 'bidId': '284f8e1469246b', + 'bidder': 'luponmedia', + 'adUnitCode': 'div-gpt-ad-1533155193780-3', + 'auctionId': 'c4f0cce0-264c-483a-b2f4-8ac2248a896b' + } + ]; + + // now simulate some WIN and RENDERING + let wonRequest = { + 'bidderCode': 'luponmedia', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '3b40e0da8968f5', + 'requestId': '284f8e1469246a', + 'mediaType': 'banner', + 'source': 'client', + 'cpm': 0.43, + 'creativeId': '443801010', + 'currency': 'USD', + 'netRevenue': false, + 'ttl': 300, + 'referrer': '', + 'ad': " ", + 'originalCpm': '0.43', + 'originalCurrency': 'USD', + 'auctionId': 'c4f0cce0-264c-483a-b2f4-8ac2248a896b', + 'responseTimestamp': 1589707615188, + 'requestTimestamp': 1589707613908, + 'bidder': 'luponmedia', + 'adUnitCode': 'div-gpt-ad-1533155193780-2', + 'timeToRespond': 1280, + 'pbLg': '0.00', + 'pbMg': '0.40', + 'pbHg': '0.43', + 'pbAg': '0.40', + 'pbDg': '0.43', + 'pbCg': '0.43', + 'size': '300x250', + 'adserverTargeting': { + 'hb_bidder': 'luponmedia', + 'hb_adid': '3b40e0da8968f5', + 'hb_pb': '0.43', + 'hb_size': '300x250', + 'hb_source': 'client', + 'hb_format': 'banner' + }, + 'status': 'rendered', + 'params': [ + { + 'siteId': 303522, + 'keyId': '4o2c4' + } + ] + }; + + let wonExpectData = JSON.parse(atob('eyJwdWJsaXNoZXJfaWQiOjEyMywiYXVjdGlvbl9pZCI6ImM0ZjBjY2UwLTI2NGMtNDgzYS1iMmY0LThhYzIyNDhhODk2YiIsInJlZmVyZXIiOiJodHRwczovL3Rlc3QuY29tL2FydGljbGUvMTc2MDY3Iiwic2NyZWVuX3Jlc29sdXRpb24iOiIxNDQweDkwMCIsImRldmljZV90eXBlIjoiZGVza3RvcCIsImdlbyI6bnVsbCwiZXZlbnRzIjpbeyJ0eXBlIjoiVElNRU9VVCIsImJpZGRlcl9jb2RlIjoibHVwb25tZWRpYSIsImV2ZW50X3RpbWVzdGFtcCI6MTU4OTcwNzYxMzkwOCwiYmlkX2dwdF9jb2RlcyI6eyJkaXYtZ3B0LWFkLTE1MzMxNTUxOTM3ODAtMiI6W1szMDAsMjUwXV0sImRpdi1ncHQtYWQtMTUzMzE1NTE5Mzc4MC0zIjpbWzMwMCwyNTBdXX19LHsidHlwZSI6IlJFU1BPTlNFIiwiYmlkZGVyX2NvZGUiOiJsdXBvbm1lZGlhIiwiZXZlbnRfdGltZXN0YW1wIjoxNTg5NzA3NjE1MTg4LCJzaXplIjoiMzAweDI1MCIsImdwdF9jb2RlIjoiZGl2LWdwdC1hZC0xNTMzMTU1MTkzNzgwLTIiLCJjdXJyZW5jeSI6IlVTRCIsImNyZWF0aXZlX2lkIjoiNDQzODAxMDEwIiwidGltZV90b19yZXNwb25kIjoxMjgwLCJjcG0iOjAuNDMsImlzX3dpbm5pbmciOmZhbHNlfV19')); + wonExpectData['screen_resolution'] = window.screen.width + 'x' + window.screen.height; + wonExpectData = btoa(JSON.stringify(wonExpectData)); + + let wonExpect = { + 'query': 'mutation {createEvent(input: {event: {eventData: "' + wonExpectData + '"}}) {event {createTime } } }' + }; + + adapterManager.registerAnalyticsAdapter({ + code: 'adxpremium', + adapter: adxpremiumAnalyticsAdapter + }); + + beforeEach(function () { + adapterManager.enableAnalytics({ + provider: 'adxpremium', + options: initOptions + }); + }); + + afterEach(function () { + adxpremiumAnalyticsAdapter.disableAnalytics(); + }); + + it('builds and sends auction data', function () { + // Step 1: Send auction init event + events.emit(constants.EVENTS.AUCTION_INIT, auctionInit); + + // Step 2: Send bid requested event + events.emit(constants.EVENTS.BID_REQUESTED, bidRequest); + + // Step 3: Send bid response event + events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + + // Step 4: Send bid time out event + events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeoutArgsV1); + + // Step 5: Send auction end event + events.emit(constants.EVENTS.AUCTION_END, {}); + + testSend(); + + expect(server.requests.length).to.equal(2); + + let realAfterBid = JSON.parse(server.requests[0].requestBody); + + expect(realAfterBid).to.deep.equal(expectedAfterBid); + + // expect after timeout + expect(realAfterBid).to.deep.equal(expectedAfterTimeout); + + // Step 6: Send auction bid won event + events.emit(constants.EVENTS.BID_WON, wonRequest); + + expect(server.requests.length).to.equal(3); + let winEventData = JSON.parse(server.requests[1].requestBody); + + expect(winEventData).to.deep.equal(wonExpect); + }); + }); +}); diff --git a/test/spec/modules/adyoulikeBidAdapter_spec.js b/test/spec/modules/adyoulikeBidAdapter_spec.js index 3573681dd17..d2d4e10c17f 100644 --- a/test/spec/modules/adyoulikeBidAdapter_spec.js +++ b/test/spec/modules/adyoulikeBidAdapter_spec.js @@ -275,6 +275,29 @@ describe('Adyoulike Adapter', function () { expect(payload.uspConsent).to.exist.and.to.equal(uspConsentData); }); + it('should not set a default value for gdpr consentRequired', function () { + let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; + let uspConsentData = '1YCC'; + let bidderRequest = { + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gdprConsent': { + consentString: consentString + }, + 'uspConsent': uspConsentData + }; + + bidderRequest.bids = bidRequestWithSinglePlacement; + + const request = spec.buildRequests(bidRequestWithSinglePlacement, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.gdprConsent).to.exist; + expect(payload.gdprConsent.consentString).to.exist.and.to.equal(consentString); + expect(payload.gdprConsent.consentRequired).to.be.null; + }); + it('sends bid request to endpoint with single placement', function () { const request = spec.buildRequests(bidRequestWithSinglePlacement, bidderRequest); const payload = JSON.parse(request.data); diff --git a/test/spec/modules/amxBidAdapter_spec.js b/test/spec/modules/amxBidAdapter_spec.js new file mode 100644 index 00000000000..91315da8801 --- /dev/null +++ b/test/spec/modules/amxBidAdapter_spec.js @@ -0,0 +1,473 @@ +import * as utils from 'src/utils.js'; +import { createEidsArray } from 'modules/userId/eids.js'; +import { expect } from 'chai'; +import { spec } from 'modules/amxBidAdapter.js'; +import { BANNER, VIDEO } from 'src/mediaTypes.js'; +import { config } from 'src/config.js'; + +const sampleRequestId = '82c91e127a9b93e'; +const sampleDisplayAd = (additionalImpressions) => `${additionalImpressions}`; +const sampleDisplayCRID = '78827819'; +// minimal example vast +const sampleVideoAd = (addlImpression) => ` +00:00:15${addlImpression} +`.replace(/\n+/g, '') + +const embeddedTrackingPixel = `https://1x1.a-mo.net/hbx/g_impression?A=sample&B=20903`; +const sampleNurl = 'https://example.exchange/nurl'; + +const sampleFPD = { + context: { + keywords: 'sample keywords', + data: { + pageType: 'article' + } + }, + user: { + gender: 'O', + yob: 1982, + } +}; + +const stubConfig = (withStub) => { + const stub = sinon.stub(config, 'getConfig').callsFake( + (arg) => arg === 'fpd' ? sampleFPD : null + ) + + withStub(); + stub.restore(); +}; + +const sampleBidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: utils.getUniqueIdentifierStr(), + vendorData: {} + }, + auctionId: utils.getUniqueIdentifierStr(), + uspConsent: '1YYY', + refererInfo: { + referer: 'https://www.prebid.org', + canonicalUrl: 'https://www.prebid.org/the/link/to/the/page' + } +}; + +const sampleBidRequestBase = { + bidder: spec.code, + params: { + endpoint: 'https://httpbin.org/post', + }, + sizes: [[320, 50]], + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]] + } + }, + adUnitCode: 'div-gpt-ad-example', + transactionId: utils.getUniqueIdentifierStr(), + bidId: sampleRequestId, + auctionId: utils.getUniqueIdentifierStr(), +}; + +const sampleBidRequestVideo = { + ...sampleBidRequestBase, + bidId: sampleRequestId + '_video', + sizes: [[300, 150]], + mediaTypes: { + [VIDEO]: { + sizes: [[360, 250]] + } + } +}; + +const sampleServerResponse = { + 'p': { + 'hreq': ['https://1x1.a-mo.net/hbx/g_sync?partner=test', 'https://1x1.a-mo.net/hbx/g_syncf?__st=iframe'] + }, + 'r': { + [sampleRequestId]: [ + { + 'b': [ + { + 'adid': '78827819', + 'adm': sampleDisplayAd(''), + 'adomain': [ + 'example.com' + ], + 'crid': sampleDisplayCRID, + 'ext': { + 'himp': [ + embeddedTrackingPixel + ], + }, + 'nurl': sampleNurl, + 'h': 600, + 'id': '2014691335735134254', + 'impid': '1', + 'price': 0.25, + 'w': 300 + }, + { + 'adid': '222976952', + 'adm': sampleVideoAd(''), + 'adomain': [ + 'example.com' + ], + 'crid': sampleDisplayCRID, + 'ext': { + 'himp': [ + embeddedTrackingPixel + ], + }, + 'nurl': sampleNurl, + 'h': 1, + 'id': '7735706981389902829', + 'impid': '1', + 'price': 0.25, + 'w': 1 + }, + ], + } + ] + }, +} + +describe('AmxBidAdapter', () => { + describe('isBidRequestValid', () => { + it('endpoint must be an optional string', () => { + expect(spec.isBidRequestValid({params: { endpoint: 1 }})).to.equal(false) + expect(spec.isBidRequestValid({params: { endpoint: 'test' }})).to.equal(true) + }); + + it('tagId is an optional string', () => { + expect(spec.isBidRequestValid({params: { tagId: 1 }})).to.equal(false) + expect(spec.isBidRequestValid({params: { tagId: 'test' }})).to.equal(true) + }); + + it('testMode is an optional boolean', () => { + expect(spec.isBidRequestValid({params: { testMode: 1 }})).to.equal(false) + expect(spec.isBidRequestValid({params: { testMode: false }})).to.equal(true) + }); + + it('none of the params are required', () => { + expect(spec.isBidRequestValid({})).to.equal(true) + }); + }) + describe('getUserSync', () => { + it('will only sync from valid server responses', () => { + const syncs = spec.getUserSyncs({ iframeEnabled: true }); + expect(syncs).to.eql([]); + }); + + it('will return valid syncs from a server response', () => { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, [{body: sampleServerResponse}]); + expect(syncs.length).to.equal(2); + expect(syncs[0].type).to.equal('image'); + expect(syncs[1].type).to.equal('iframe'); + }); + + it('will filter out iframe syncs based on options', () => { + const syncs = spec.getUserSyncs({ iframeEnabled: false }, [{body: sampleServerResponse}, {body: sampleServerResponse}]); + expect(syncs.length).to.equal(2); + expect(syncs).to.satisfy((allSyncs) => allSyncs.every((sync) => sync.type === 'image')) + }); + }); + + describe('buildRequests', () => { + it('will default to prebid.a-mo.net endpoint', () => { + const { url } = spec.buildRequests([], sampleBidderRequest); + expect(url).to.equal('https://prebid.a-mo.net/a/c') + }); + + it('reads test mode from the first bid request', () => { + const { data } = spec.buildRequests([{ + ...sampleBidRequestBase, + params: { + testMode: true + } + }], sampleBidderRequest); + expect(data.tm).to.equal(true); + }); + + it('handles referer data and GDPR, USP Consent, COPPA', () => { + const { data } = spec.buildRequests([sampleBidRequestBase], sampleBidderRequest); + delete data.m; // don't deal with "m" in this test + expect(data.gs).to.equal(sampleBidderRequest.gdprConsent.gdprApplies) + expect(data.gc).to.equal(sampleBidderRequest.gdprConsent.consentString) + expect(data.usp).to.equal(sampleBidderRequest.uspConsent) + expect(data.cpp).to.equal(0) + }); + + it('will forward bid request count & wins count data', () => { + const bidderRequestsCount = Math.floor(Math.random() * 100) + const bidderWinsCount = Math.floor(Math.random() * 100) + const { data } = spec.buildRequests([{ + ...sampleBidRequestBase, + bidderRequestsCount, + bidderWinsCount + }], sampleBidderRequest); + + expect(data.brc).to.equal(bidderRequestsCount) + expect(data.bwc).to.equal(bidderWinsCount) + expect(data.trc).to.equal(0) + }); + it('will forward first-party data', () => { + stubConfig(() => { + const { data } = spec.buildRequests([sampleBidRequestBase], sampleBidderRequest); + expect(data.fpd).to.deep.equal(sampleFPD) + }); + }); + + it('will collect & forward RTI user IDs', () => { + const randomRTI = `greatRTI${Math.floor(Math.random() * 100)}` + const userId = { + britepoolid: 'sample-britepool', + criteoId: 'sample-criteo', + digitrustid: {data: {id: 'sample-digitrust'}}, + id5id: {uid: 'sample-id5'}, + idl_env: 'sample-liveramp', + lipb: {lipbid: 'sample-liveintent'}, + netId: 'sample-netid', + parrableId: { eid: 'sample-parrable' }, + pubcid: 'sample-pubcid', + [randomRTI]: 'sample-unknown', + tdid: 'sample-ttd', + }; + + const eids = createEidsArray(userId); + const bid = { + ...sampleBidRequestBase, + userIdAsEids: eids + }; + + const { data } = spec.buildRequests([bid, bid], sampleBidderRequest); + expect(data.eids).to.deep.equal(eids) + }); + + it('can build a banner request', () => { + const { method, url, data } = spec.buildRequests([sampleBidRequestBase, { + ...sampleBidRequestBase, + bidId: sampleRequestId + '_2', + params: { + ...sampleBidRequestBase.params, + tagId: 'example' + } + }], sampleBidderRequest) + + expect(url).to.equal(sampleBidRequestBase.params.endpoint) + expect(method).to.equal('POST'); + expect(Object.keys(data.m).length).to.equal(2); + expect(data.m[sampleRequestId]).to.deep.equal({ + av: true, + au: 'div-gpt-ad-example', + ms: [ + [[320, 50]], + [[300, 250]], + [] + ], + aw: 300, + ah: 250, + tf: 0, + vr: false + }); + expect(data.m[sampleRequestId + '_2']).to.deep.equal({ + av: true, + aw: 300, + au: 'div-gpt-ad-example', + ms: [ + [[320, 50]], + [[300, 250]], + [] + ], + i: 'example', + ah: 250, + tf: 0, + vr: false, + }); + }); + + it('can build a video request', () => { + const { data } = spec.buildRequests([sampleBidRequestVideo], sampleBidderRequest); + expect(Object.keys(data.m).length).to.equal(1); + expect(data.m[sampleRequestId + '_video']).to.deep.equal({ + au: 'div-gpt-ad-example', + ms: [ + [[300, 150]], + [], + [[360, 250]] + ], + av: true, + aw: 360, + ah: 250, + tf: 0, + vr: true + }); + }); + }); + + describe('interpretResponse', () => { + const baseBidResponse = { + requestId: sampleRequestId, + cpm: 0.25, + creativeId: sampleDisplayCRID, + currency: 'USD', + netRevenue: true, + meta: { + advertiserDomains: ['example.com'], + }, + }; + + const baseRequest = { + data: { + m: { + [sampleRequestId]: { + aw: 300, + ah: 250, + }, + } + } + }; + + it('will handle a nobid response', () => { + const parsed = spec.interpretResponse({ body: '' }, baseRequest) + expect(parsed).to.eql([]) + }); + + it('can parse a display ad', () => { + const parsed = spec.interpretResponse({ body: sampleServerResponse }, baseRequest) + expect(parsed.length).to.equal(2) + + // we should have display, video, display + expect(parsed[0]).to.deep.equal({ + ...baseBidResponse, + meta: { + ...baseBidResponse.meta, + mediaType: BANNER, + }, + width: 300, + height: 600, // from the bid itself + ttl: 70, + ad: sampleDisplayAd( + `` + + `` + ), + }); + }); + + it('can parse a video ad', () => { + const parsed = spec.interpretResponse({ body: sampleServerResponse }, baseRequest) + expect(parsed.length).to.equal(2) + + // we should have display, video, display + const xml = parsed[1].vastXml + delete parsed[1].vastXml + + expect(xml).to.have.string(``) + expect(xml).to.have.string(``) + + expect(parsed[1]).to.deep.equal({ + ...baseBidResponse, + meta: { + ...baseBidResponse.meta, + mediaType: VIDEO, + }, + width: 300, + height: 250, + ttl: 90, + }); + }); + }); + + describe('analytics methods', () => { + let firedPixels = []; + let _Image = window.Image; + before(() => { + _Image = window.Image; + window.Image = class FakeImage { + set src(value) { + firedPixels.push(value) + } + } + }); + + beforeEach(() => { + firedPixels = []; + }); + + after(() => { + window.Image = _Image; + }); + + it('will fire an event for onSetTargeting', () => { + spec.onSetTargeting({ + bidder: 'example', + width: 300, + height: 250, + adId: 'ad-id', + mediaType: BANNER, + cpm: 1.23, + requestId: utils.getUniqueIdentifierStr(), + adUnitCode: 'div-gpt-ad', + adserverTargeting: { + hb_pb: '1.23', + hb_adid: 'ad-id', + hb_bidder: 'example' + } + }); + expect(firedPixels.length).to.equal(1) + expect(firedPixels[0]).to.match(/\/hbx\/g_pbst/) + try { + const parsed = new URL(firedPixels[0]); + const nestedData = parsed.searchParams.get('c2'); + expect(nestedData).to.equal(utils.formatQS({ + hb_pb: '1.23', + hb_adid: 'ad-id', + hb_bidder: 'example' + })); + } catch (e) { + // unsupported browser; try testing for string + const pixel = firedPixels[0]; + expect(pixel).to.have.string(encodeURIComponent('hb_pb=1.23')) + expect(pixel).to.have.string(encodeURIComponent('hb_adid=ad-id')) + } + }); + + it('will log an event for timeout', () => { + spec.onTimeout({ + bidder: 'example', + bidId: 'test-bid-id', + adUnitCode: 'div-gpt-ad', + timeout: 300, + auctionId: utils.getUniqueIdentifierStr() + }); + expect(firedPixels.length).to.equal(1) + expect(firedPixels[0]).to.match(/\/hbx\/g_pbto/) + }); + + it('will log an event for prebid win', () => { + spec.onBidWon({ + bidder: 'example', + adId: 'test-ad-id', + width: 300, + height: 250, + mediaType: VIDEO, + cpm: 1.34, + adUnitCode: 'div-gpt-ad', + timeout: 300, + auctionId: utils.getUniqueIdentifierStr() + }); + expect(firedPixels.length).to.equal(1) + expect(firedPixels[0]).to.match(/\/hbx\/g_pbwin/) + + const pixel = firedPixels[0]; + try { + const url = new URL(pixel); + expect(url.searchParams.get('C')).to.equal('1') + expect(url.searchParams.get('np')).to.equal('1.34') + } catch (e) { + expect(pixel).to.have.string('C=1') + expect(pixel).to.have.string('np=1.34') + } + }); + }); +}); diff --git a/test/spec/modules/aniviewBidAdapter_spec.js b/test/spec/modules/aniviewBidAdapter_spec.js index 0161652505c..2e1fdb56201 100644 --- a/test/spec/modules/aniviewBidAdapter_spec.js +++ b/test/spec/modules/aniviewBidAdapter_spec.js @@ -41,7 +41,6 @@ describe('ANIVIEW Bid Adapter Test', function () { }); describe('buildRequests', function () { - const ENDPOINT = 'https://v.lkqd.net/ad'; let bid2Requests = [ { 'bidder': 'aniview', @@ -156,7 +155,6 @@ describe('ANIVIEW Bid Adapter Test', function () { expect(bidResponses.length).to.equal(1); let bidResponse = bidResponses[0]; expect(bidResponse.requestId).to.equal(bidRequest.data.bidId); - expect(bidResponse.bidderCode).to.equal(BIDDER_CODE); expect(bidResponse.cpm).to.equal('2'); expect(bidResponse.ttl).to.equal(600); expect(bidResponse.currency).to.equal('USD'); @@ -179,6 +177,33 @@ describe('ANIVIEW Bid Adapter Test', function () { let result = spec.interpretResponse(nobidResponse, bidRequest); expect(result.length).to.equal(0); }); + + it('should add renderer if outstream context', function () { + const bidRequest = spec.buildRequests([ + { + bidId: '253dcb69fb2577', + params: { + playerDomain: 'example.com', + AV_PUBLISHERID: '55b78633181f4603178b4568', + AV_CHANNELID: '55b7904d181f46410f8b4568' + }, + mediaTypes: { + video: { + playerSize: [[640, 480]], + context: 'outstream' + } + } + } + ])[0] + const bidResponse = spec.interpretResponse(serverResponse, bidRequest)[0] + + expect(bidResponse.renderer.url).to.equal('https://example.com/script/6.1/prebidRenderer.js') + expect(bidResponse.renderer.config.AV_PUBLISHERID).to.equal('55b78633181f4603178b4568') + expect(bidResponse.renderer.config.AV_CHANNELID).to.equal('55b7904d181f46410f8b4568') + expect(bidResponse.renderer.loaded).to.equal(false) + expect(bidResponse.width).to.equal(640) + expect(bidResponse.height).to.equal(480) + }) }); describe('getUserSyncs', function () { diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index 8934d1cdaef..7e985045c45 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -100,6 +100,24 @@ describe('AppNexusAdapter', function () { expect(payload.tags[0].private_sizes).to.deep.equal([{width: 300, height: 250}]); }); + it('should add publisher_id in request', function() { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { + placementId: '10433394', + publisherId: '1231234' + } + }); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + + expect(payload.tags[0].publisher_id).to.exist; + expect(payload.tags[0].publisher_id).to.deep.equal(1231234); + expect(payload.publisher_id).to.exist; + expect(payload.publisher_id).to.deep.equal(1231234); + }) + it('should add source and verison to the tag', function () { const request = spec.buildRequests(bidRequests); const payload = JSON.parse(request.data); @@ -230,12 +248,12 @@ describe('AppNexusAdapter', function () { const payload = JSON.parse(request.data); expect(payload.tags[0].video).to.deep.equal({ skippable: true, - playback_method: ['auto_play_sound_off'], + playback_method: 2, custom_renderer_present: true }); expect(payload.tags[1].video).to.deep.equal({ skippable: true, - playback_method: ['auto_play_sound_off'] + playback_method: 2 }); }); @@ -720,18 +738,6 @@ describe('AppNexusAdapter', function () { }); }); - it('should populate tpids array when userId is available', function () { - const bidRequest = Object.assign({}, bidRequests[0], { - userId: { - criteoId: 'sample-userid' - } - }); - - const request = spec.buildRequests([bidRequest]); - const payload = JSON.parse(request.data); - expect(payload.tpuids).to.deep.equal([{provider: 'criteo', user_id: 'sample-userid'}]); - }); - it('should populate schain if available', function () { const bidRequest = Object.assign({}, bidRequests[0], { schain: { @@ -801,6 +807,28 @@ describe('AppNexusAdapter', function () { const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.options).to.deep.equal({withCredentials: false}); }); + + it('should populate eids array when ttd id and criteo is available', function () { + const bidRequest = Object.assign({}, bidRequests[0], { + userId: { + tdid: 'sample-userid', + criteoId: 'sample-criteo-userid' + } + }); + + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + expect(payload.eids).to.deep.include({ + source: 'adserver.org', + id: 'sample-userid', + rti_partner: 'TDID' + }); + + expect(payload.eids).to.deep.include({ + source: 'criteo.com', + id: 'sample-criteo-userid', + }); + }); }) describe('interpretResponse', function () { diff --git a/test/spec/modules/apstreamBidAdapter_spec.js b/test/spec/modules/apstreamBidAdapter_spec.js new file mode 100644 index 00000000000..e640c009989 --- /dev/null +++ b/test/spec/modules/apstreamBidAdapter_spec.js @@ -0,0 +1,346 @@ +// jshint esversion: 6, es3: false, node: true +import {assert, expect} from 'chai'; +import {config} from 'src/config.js'; +import {spec} from 'modules/apstreamBidAdapter.js'; +import * as utils from 'src/utils.js'; + +const validBidRequests = [{ + bidId: 'bidId', + adUnitCode: '/id/site1/header-ad', + sizes: [[980, 120], [980, 180]], + mediaTypes: { + banner: { + sizes: [[980, 120], [980, 180]] + } + }, + params: { + publisherId: '1234' + } +}]; + +describe('AP Stream adapter', function() { + describe('isBidRequestValid', function() { + const bid = { + bidder: 'apstream', + mediaTypes: { + banner: { + sizes: [300, 250] + } + }, + params: { + } + }; + + let mockConfig; + beforeEach(function () { + mockConfig = { + apstream: { + publisherId: '4321' + } + }; + sinon.stub(config, 'getConfig').callsFake((key) => { + return utils.deepAccess(mockConfig, key); + }); + }); + + afterEach(function () { + config.getConfig.restore(); + }); + + it('should return true when publisherId is configured and one media type', function() { + bid.params.publisherId = '1234'; + assert(spec.isBidRequestValid(bid)) + }); + + it('should return false when publisherId is configured and two media types', function() { + bid.mediaTypes.video = {sizes: [300, 250]}; + assert.isFalse(spec.isBidRequestValid(bid)) + }); + + it('should return true when publisherId is configured via config', function() { + delete bid.mediaTypes.video; + delete bid.params.publisherId; + assert.isTrue(spec.isBidRequestValid(bid)) + }); + }); + + describe('buildRequests', function() { + it('should send request with correct structure', function() { + const request = spec.buildRequests(validBidRequests, { })[0]; + + assert.equal(request.method, 'GET'); + assert.deepEqual(request.options, {withCredentials: false}); + assert.ok(request.data); + }); + + it('should send request with different endpoints', function() { + const validTwoBidRequests = [ + ...validBidRequests, + ...[{ + bidId: 'bidId2', + adUnitCode: '/id/site1/header-ad', + sizes: [[980, 980], [980, 900]], + mediaTypes: { + banner: { + sizes: [[980, 980], [980, 900]] + } + }, + params: { + publisherId: '1234', + endpoint: 'site2.com' + } + }] + ]; + + const request = spec.buildRequests(validTwoBidRequests, {}); + assert.isArray(request); + assert.lengthOf(request, 2); + assert.equal(request[1].data.bids, 'bidId2:t=b,s=980x980_980x900,c=/id/site1/header-ad'); + }); + + it('should send request with adUnit code', function() { + const adunitCodeValidBidRequests = [ + { + ...validBidRequests[0], + ...{ + params: { + code: 'Site1_Leaderboard' + } + } + } + ]; + + const request = spec.buildRequests(adunitCodeValidBidRequests, { })[0]; + assert.equal(request.data.bids, 'bidId:t=b,s=980x120_980x180,c=Site1_Leaderboard'); + }); + + it('should send request with adUnit id', function() { + const adunitIdValidBidRequests = [ + { + ...validBidRequests[0], + ...{ + params: { + adunitId: '12345' + } + } + } + ]; + + const request = spec.buildRequests(adunitIdValidBidRequests, { })[0]; + assert.equal(request.data.bids, 'bidId:t=b,s=980x120_980x180,u=12345'); + }); + + it('should send request with different media type', function() { + const types = { + 'audio': 'a', + 'banner': 'b', + 'native': 'n', + 'video': 'v' + } + Object.keys(types).forEach(key => { + const adunitIdValidBidRequests = [ + { + ...validBidRequests[0], + ...{ + mediaTypes: { + [key]: { + sizes: [300, 250] + } + } + } + } + ]; + + const request = spec.buildRequests(adunitIdValidBidRequests, { })[0]; + assert.equal(request.data.bids, `bidId:t=${types[key]},s=980x120_980x180,c=/id/site1/header-ad`); + }) + }); + + describe('gdpr', function() { + let mockConfig; + + beforeEach(function () { + mockConfig = { + consentManagement: { + cmpApi: 'iab' + } + }; + sinon.stub(config, 'getConfig').callsFake((key) => { + return utils.deepAccess(mockConfig, key); + }); + }); + + afterEach(function () { + config.getConfig.restore(); + }); + + it('should send GDPR Consent data', function() { + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentDataString', + vendorData: { + vendorConsents: { + '394': true + } + } + } + }; + + const request = spec.buildRequests(validBidRequests, bidderRequest)[0].data; + assert.equal(request.iab_consent, bidderRequest.gdprConsent.consentString); + }); + }); + + describe('dsu', function() { + it('should pass DSU from local storage if set', function() { + let dsu = 'some_dsu'; + localStorage.setItem('apr_dsu', dsu); + + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentDataString', + vendorData: { + vendorConsents: { + '394': true + } + } + } + }; + + const request = spec.buildRequests(validBidRequests, bidderRequest)[0].data; + + assert.equal(request.dsu, dsu); + }); + + it('should generate new DSU if nothing in local storage', function() { + localStorage.removeItem('apr_dsu'); + + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentDataString', + vendorData: { + vendorConsents: { + '394': true + } + } + } + }; + + const request = spec.buildRequests(validBidRequests, bidderRequest)[0].data; + let dsu = localStorage.getItem('apr_dsu'); + + assert.isNotEmpty(dsu); + assert.equal(request.dsu, dsu); + }); + }); + }); + + describe('dsu config', function() { + let mockConfig; + beforeEach(function () { + mockConfig = { + apstream: { + noDsu: true + } + }; + sinon.stub(config, 'getConfig').callsFake((key) => { + return utils.deepAccess(mockConfig, key); + }); + }); + + afterEach(function () { + config.getConfig.restore(); + }); + + it('should not send DSU if it is disabled in config', function() { + const request = spec.buildRequests(validBidRequests, { })[0]; + + assert.equal(request.data.dsu, ''); + }); + }); + + describe('interpretResponse', function () { + it('should return empty array if no body in response', function () { + const serverResponse = {}; + const bidRequest = {}; + + assert.isEmpty(spec.interpretResponse(serverResponse, bidRequest)); + }); + + it('should map server response', function () { + const serverResponse = { + body: [ + { + bidId: 123, + bidDetails: { + cpm: 1.23, + width: 980, + height: 300, + currency: 'DKK', + netRevenue: 'true', + creativeId: '1234', + dealId: '99008', + ad: '

Buy our something!

', + ttl: 360 + } + } + ] + }; + const bidRequest = {}; + + const response = spec.interpretResponse(serverResponse, bidRequest); + + const expected = { + requestId: 123, + cpm: 1.23, + width: 980, + height: 300, + currency: 'DKK', + creativeId: '1234', + netRevenue: 'true', + dealId: '99008', + ad: '

Buy our something!

', + ttl: 360 + }; + + assert.deepEqual(response[0], expected); + }); + + it('should add pixels to ad', function () { + const serverResponse = { + body: [ + { + bidId: 123, + bidDetails: { + cpm: 1.23, + width: 980, + height: 300, + currency: 'DKK', + creativeId: '1234', + netRevenue: 'true', + dealId: '99008', + ad: '

Buy our something!

', + ttl: 360, + noticeUrls: [ + 'site1', + 'site2' + ], + impressionScripts: [ + 'url_to_script' + ] + } + } + ] + }; + const bidRequest = {}; + + const response = spec.interpretResponse(serverResponse, bidRequest); + + assert.match(response[0].ad, /site1/); + assert.match(response[0].ad, /site2/); + }); + }); +}); diff --git a/test/spec/modules/atsAnalyticsAdapter_spec.js b/test/spec/modules/atsAnalyticsAdapter_spec.js index 3dd6f261c11..849ccf88c51 100644 --- a/test/spec/modules/atsAnalyticsAdapter_spec.js +++ b/test/spec/modules/atsAnalyticsAdapter_spec.js @@ -2,7 +2,7 @@ import atsAnalyticsAdapter from '../../../modules/atsAnalyticsAdapter.js'; import { expect } from 'chai'; import adapterManager from 'src/adapterManager.js'; import {server} from '../../mocks/xhr.js'; -import {browserIsChrome, browserIsEdge, browserIsFirefox, browserIsSafari} from '../../../modules/atsAnalyticsAdapter.js'; +import {checkUserBrowser, browserIsChrome, browserIsEdge, browserIsSafari, browserIsFirefox} from '../../../modules/atsAnalyticsAdapter.js'; let events = require('src/events'); let constants = require('src/constants.json'); @@ -77,7 +77,7 @@ describe('ats analytics adapter', function () { 'bidder': 'appnexus', 'bid_id': '30c77d079cdf17', 'auction_id': 'a5b849e5-87d7-4205-8300-d063084fcfb7', - 'user_browser': (browserIsFirefox() || browserIsEdge() || browserIsChrome() || browserIsSafari()), + 'user_browser': checkUserBrowser(), 'user_platform': navigator.platform, 'auction_start': '2020-02-03T14:14:25.161Z', 'domain': window.location.hostname, @@ -146,5 +146,63 @@ describe('ats analytics adapter', function () { expect(atsAnalyticsAdapter.context.host).to.equal(initOptions.host); expect(atsAnalyticsAdapter.context.pid).to.equal(initOptions.pid); }) + it('check browser is not safari', function () { + window.safari = undefined; + let browser = browserIsSafari(); + expect(browser).to.equal(false); + }) + it('check browser is safari', function () { + window.safari = {}; + let browser = browserIsSafari(); + expect(browser).to.equal('Safari'); + }) + it('check browser is not chrome', function () { + window.chrome = { + app: undefined, + webstore: undefined, + runtime: undefined + }; + let browser = browserIsChrome(); + expect(browser).to.equal(false); + }) + it('check browser is chrome', function () { + window.chrome = { + app: {}, + webstore: {}, + runtime: {} + }; + let browser = browserIsChrome(); + expect(browser).to.equal('Chrome'); + }) + it('check browser is edge', function () { + Object.defineProperty(window, 'StyleMedia', { + value: {}, + writable: true + }); + Object.defineProperty(document, 'documentMode', { + value: undefined, + writable: true + }); + let browser = browserIsEdge(); + expect(browser).to.equal('Edge'); + }) + it('check browser is not edge', function () { + Object.defineProperty(document, 'documentMode', { + value: {}, + writable: true + }); + let browser = browserIsEdge(); + expect(browser).to.equal(false); + }) + it('check browser is firefox', function () { + global.InstallTrigger = {}; + let browser = browserIsFirefox(); + expect(browser).to.equal('Firefox'); + }) + it('check browser is not firefox', function () { + global.InstallTrigger = undefined; + let browser = browserIsFirefox(); + expect(browser).to.equal(false); + }) }) }) diff --git a/test/spec/modules/audienceNetworkBidAdapter_spec.js b/test/spec/modules/audienceNetworkBidAdapter_spec.js deleted file mode 100644 index 04694731981..00000000000 --- a/test/spec/modules/audienceNetworkBidAdapter_spec.js +++ /dev/null @@ -1,568 +0,0 @@ -/** - * @file Tests for AudienceNetwork adapter. - */ -import { expect } from 'chai'; - -import { spec } from 'modules/audienceNetworkBidAdapter.js'; -import * as utils from 'src/utils.js'; - -const { - code, - supportedMediaTypes, - isBidRequestValid, - buildRequests, - interpretResponse -} = spec; - -const bidder = 'audienceNetwork'; -const placementId = 'test-placement-id'; -const playerwidth = 320; -const playerheight = 180; -const requestId = 'test-request-id'; -const debug = 'adapterver=1.3.0&platform=241394079772386&platver=$prebid.version$&cb=test-uuid'; -const expectedPageUrl = encodeURIComponent('http://www.prebid-test.com/audienceNetworkTest.html?pbjs_debug=true'); -const mockBidderRequest = { - bidderCode: 'audienceNetwork', - auctionId: '720146a0-8f32-4db0-bb30-21f1d057efb4', - bidderRequestId: '1312d48561657e', - auctionStart: 1579711852920, - timeout: 3000, - refererInfo: { - referer: 'http://www.prebid-test.com/audienceNetworkTest.html?pbjs_debug=true', - reachedTop: true, - numIframes: 0, - stack: ['http://www.prebid-test.com/audienceNetworkTest.html?pbjs_debug=true'], - canonicalUrl: undefined - }, - start: 1579711852925 -}; - -describe('AudienceNetwork adapter', function () { - describe('Public API', function () { - it('code', function () { - expect(code).to.equal(bidder); - }); - it('supportedMediaTypes', function () { - expect(supportedMediaTypes).to.deep.equal(['banner', 'video']); - }); - it('isBidRequestValid', function () { - expect(isBidRequestValid).to.be.a('function'); - }); - it('buildRequests', function () { - expect(buildRequests).to.be.a('function'); - }); - it('interpretResponse', function () { - expect(interpretResponse).to.be.a('function'); - }); - }); - - describe('isBidRequestValid', function () { - it('missing placementId parameter', function () { - expect(isBidRequestValid({ - bidder, - sizes: [[300, 250]] - })).to.equal(false); - }); - - it('invalid sizes parameter', function () { - expect(isBidRequestValid({ - bidder, - sizes: ['', undefined, null, '300x100', [300, 100], [300], {}], - params: { placementId } - })).to.equal(false); - }); - - it('valid when at least one valid size', function () { - expect(isBidRequestValid({ - bidder, - sizes: [[1, 1], [300, 250]], - params: { placementId } - })).to.equal(true); - }); - - it('valid parameters', function () { - expect(isBidRequestValid({ - bidder, - sizes: [[300, 250], [320, 50]], - params: { placementId } - })).to.equal(true); - }); - - it('fullwidth', function () { - expect(isBidRequestValid({ - bidder, - sizes: [[300, 250], [336, 280]], - params: { - placementId, - format: 'fullwidth' - } - })).to.equal(true); - }); - - it('native', function () { - expect(isBidRequestValid({ - bidder, - sizes: [[300, 250]], - params: { - placementId, - format: 'native' - } - })).to.equal(true); - }); - - it('native with non-IAB size', function () { - expect(isBidRequestValid({ - bidder, - sizes: [[728, 90]], - params: { - placementId, - format: 'native' - } - })).to.equal(true); - }); - - it('video', function () { - expect(isBidRequestValid({ - bidder, - sizes: [[playerwidth, playerheight]], - params: { - placementId, - format: 'video' - } - })).to.equal(true); - }); - }); - - describe('buildRequests', function () { - before(function () { - sinon - .stub(utils, 'generateUUID') - .returns('test-uuid'); - }); - - after(function () { - utils.generateUUID.restore(); - }); - - it('takes the canonicalUrl as priority over referer for pageurl', function () { - let expectedCanonicalUrl = encodeURIComponent('http://www.this-is-canonical-url.com/hello-world.html?pbjs_debug=true'); - mockBidderRequest.refererInfo.canonicalUrl = 'http://www.this-is-canonical-url.com/hello-world.html?pbjs_debug=true'; - expect(buildRequests([{ - bidder, - bidId: requestId, - sizes: [[300, 50], [300, 250], [320, 50]], - params: { placementId } - }], mockBidderRequest)).to.deep.equal([{ - adformats: ['300x250'], - method: 'GET', - pageurl: expectedCanonicalUrl, - requestIds: [requestId], - sizes: ['300x250'], - url: 'https://an.facebook.com/v2/placementbid.json', - data: `placementids[]=test-placement-id&adformats[]=300x250&testmode=false&pageurl=${expectedCanonicalUrl}&sdk[]=6.0.web&${debug}` - }]); - mockBidderRequest.refererInfo.canonicalUrl = undefined; - }); - - it('can build URL for IAB unit', function () { - expect(buildRequests([{ - bidder, - bidId: requestId, - sizes: [[300, 50], [300, 250], [320, 50]], - params: { placementId } - }], mockBidderRequest)).to.deep.equal([{ - adformats: ['300x250'], - method: 'GET', - pageurl: expectedPageUrl, - requestIds: [requestId], - sizes: ['300x250'], - url: 'https://an.facebook.com/v2/placementbid.json', - data: `placementids[]=test-placement-id&adformats[]=300x250&testmode=false&pageurl=${expectedPageUrl}&sdk[]=6.0.web&${debug}` - }]); - }); - - it('can build URL for video unit', function () { - expect(buildRequests([{ - bidder, - bidId: requestId, - sizes: [[640, 480]], - params: { - placementId, - format: 'video' - } - }], mockBidderRequest)).to.deep.equal([{ - adformats: ['video'], - method: 'GET', - pageurl: expectedPageUrl, - requestIds: [requestId], - sizes: ['640x480'], - url: 'https://an.facebook.com/v2/placementbid.json', - data: `placementids[]=test-placement-id&adformats[]=video&testmode=false&pageurl=${expectedPageUrl}&sdk[]=&${debug}&playerwidth=640&playerheight=480` - }]); - }); - - it('can build URL for native unit in non-IAB size', function () { - expect(buildRequests([{ - bidder, - bidId: requestId, - sizes: [[728, 90]], - params: { - placementId, - format: 'native' - } - }], mockBidderRequest)).to.deep.equal([{ - adformats: ['native'], - method: 'GET', - pageurl: expectedPageUrl, - requestIds: [requestId], - sizes: ['728x90'], - url: 'https://an.facebook.com/v2/placementbid.json', - data: `placementids[]=test-placement-id&adformats[]=native&testmode=false&pageurl=${expectedPageUrl}&sdk[]=6.0.web&${debug}` - }]); - }); - - it('can build URL for deprecated fullwidth unit, overriding platform', function () { - const platform = 'test-platform'; - const debugPlatform = debug.replace('241394079772386', platform); - - expect(buildRequests([{ - bidder, - bidId: requestId, - sizes: [[300, 250]], - params: { - placementId, - platform, - format: 'fullwidth' - } - }], mockBidderRequest)).to.deep.equal([{ - adformats: ['300x250'], - method: 'GET', - pageurl: expectedPageUrl, - requestIds: [requestId], - sizes: ['300x250'], - url: 'https://an.facebook.com/v2/placementbid.json', - data: `placementids[]=test-placement-id&adformats[]=300x250&testmode=false&pageurl=${expectedPageUrl}&sdk[]=6.0.web&${debugPlatform}` - }]); - }); - }); - - describe('interpretResponse', function () { - it('error in response', function () { - expect(interpretResponse({ - body: { - errors: ['test-error-message'] - } - }, {})).to.deep.equal([]); - }); - - it('valid native bid in response', function () { - const [bidResponse] = interpretResponse({ - body: { - errors: [], - bids: { - [placementId]: [{ - placement_id: placementId, - bid_id: 'test-bid-id', - bid_price_cents: 123, - bid_price_currency: 'usd', - bid_price_model: 'cpm' - }] - } - } - }, { - adformats: ['native'], - requestIds: [requestId], - sizes: [[300, 250]], - pageurl: expectedPageUrl - }); - - expect(bidResponse.cpm).to.equal(1.23); - expect(bidResponse.requestId).to.equal(requestId); - expect(bidResponse.width).to.equal(300); - expect(bidResponse.height).to.equal(250); - expect(bidResponse.ad) - .to.contain(`placementid: '${placementId}',`) - .and.to.contain(`format: 'native',`) - .and.to.contain(`bidid: 'test-bid-id',`) - .and.to.contain('getElementsByTagName("style")', 'ad missing native styles') - .and.to.contain('
', 'ad missing native container'); - expect(bidResponse.ttl).to.equal(600); - expect(bidResponse.creativeId).to.equal(placementId); - expect(bidResponse.netRevenue).to.equal(true); - expect(bidResponse.currency).to.equal('USD'); - - expect(bidResponse.hb_bidder).to.equal('fan'); - expect(bidResponse.fb_bidid).to.equal('test-bid-id'); - expect(bidResponse.fb_format).to.equal('native'); - expect(bidResponse.fb_placementid).to.equal(placementId); - }); - - it('valid IAB bid in response', function () { - const [bidResponse] = interpretResponse({ - body: { - errors: [], - bids: { - [placementId]: [{ - placement_id: placementId, - bid_id: 'test-bid-id', - bid_price_cents: 123, - bid_price_currency: 'usd', - bid_price_model: 'cpm' - }] - } - } - }, { - adformats: ['300x250'], - requestIds: [requestId], - sizes: [[300, 250]], - pageurl: expectedPageUrl - }); - - expect(bidResponse.cpm).to.equal(1.23); - expect(bidResponse.requestId).to.equal(requestId); - expect(bidResponse.width).to.equal(300); - expect(bidResponse.height).to.equal(250); - expect(bidResponse.ad) - .to.contain(`placementid: '${placementId}',`) - .and.to.contain(`format: '300x250',`) - .and.to.contain(`bidid: 'test-bid-id',`) - .and.not.to.contain('getElementsByTagName("style")', 'ad should not contain native styles') - .and.not.to.contain('
', 'ad should not contain native container'); - expect(bidResponse.ttl).to.equal(600); - expect(bidResponse.creativeId).to.equal(placementId); - expect(bidResponse.netRevenue).to.equal(true); - expect(bidResponse.currency).to.equal('USD'); - expect(bidResponse.hb_bidder).to.equal('fan'); - expect(bidResponse.fb_bidid).to.equal('test-bid-id'); - expect(bidResponse.fb_format).to.equal('300x250'); - expect(bidResponse.fb_placementid).to.equal(placementId); - }); - - it('filters invalid slot sizes', function () { - const [bidResponse] = interpretResponse({ - body: { - errors: [], - bids: { - [placementId]: [{ - placement_id: placementId, - bid_id: 'test-bid-id', - bid_price_cents: 123, - bid_price_currency: 'usd', - bid_price_model: 'cpm' - }] - } - } - }, { - adformats: ['300x250'], - requestIds: [requestId], - sizes: [[300, 250]], - pageurl: expectedPageUrl - }); - - expect(bidResponse.cpm).to.equal(1.23); - expect(bidResponse.requestId).to.equal(requestId); - expect(bidResponse.width).to.equal(300); - expect(bidResponse.height).to.equal(250); - expect(bidResponse.ttl).to.equal(600); - expect(bidResponse.creativeId).to.equal(placementId); - expect(bidResponse.netRevenue).to.equal(true); - expect(bidResponse.currency).to.equal('USD'); - expect(bidResponse.hb_bidder).to.equal('fan'); - expect(bidResponse.fb_bidid).to.equal('test-bid-id'); - expect(bidResponse.fb_format).to.equal('300x250'); - expect(bidResponse.fb_placementid).to.equal(placementId); - }); - - it('valid multiple bids in response', function () { - const placementIdNative = 'test-placement-id-native'; - const placementIdIab = 'test-placement-id-iab'; - - const [bidResponseNative, bidResponseIab] = interpretResponse({ - body: { - errors: [], - bids: { - [placementIdNative]: [{ - placement_id: placementIdNative, - bid_id: 'test-bid-id-native', - bid_price_cents: 123, - bid_price_currency: 'usd', - bid_price_model: 'cpm' - }], - [placementIdIab]: [{ - placement_id: placementIdIab, - bid_id: 'test-bid-id-iab', - bid_price_cents: 456, - bid_price_currency: 'usd', - bid_price_model: 'cpm' - }] - } - } - }, { - adformats: ['native', '300x250'], - requestIds: [requestId, requestId], - sizes: ['300x250', [300, 250]], - pageurl: expectedPageUrl - }); - - expect(bidResponseNative.cpm).to.equal(1.23); - expect(bidResponseNative.requestId).to.equal(requestId); - expect(bidResponseNative.width).to.equal(300); - expect(bidResponseNative.height).to.equal(250); - expect(bidResponseNative.ad) - .to.contain(`placementid: '${placementIdNative}',`) - .and.to.contain(`format: 'native',`) - .and.to.contain(`bidid: 'test-bid-id-native',`); - expect(bidResponseNative.ttl).to.equal(600); - expect(bidResponseNative.creativeId).to.equal(placementIdNative); - expect(bidResponseNative.netRevenue).to.equal(true); - expect(bidResponseNative.currency).to.equal('USD'); - expect(bidResponseNative.hb_bidder).to.equal('fan'); - expect(bidResponseNative.fb_bidid).to.equal('test-bid-id-native'); - expect(bidResponseNative.fb_format).to.equal('native'); - expect(bidResponseNative.fb_placementid).to.equal(placementIdNative); - - expect(bidResponseIab.cpm).to.equal(4.56); - expect(bidResponseIab.requestId).to.equal(requestId); - expect(bidResponseIab.width).to.equal(300); - expect(bidResponseIab.height).to.equal(250); - expect(bidResponseIab.ad) - .to.contain(`placementid: '${placementIdIab}',`) - .and.to.contain(`format: '300x250',`) - .and.to.contain(`bidid: 'test-bid-id-iab',`); - expect(bidResponseIab.ttl).to.equal(600); - expect(bidResponseIab.creativeId).to.equal(placementIdIab); - expect(bidResponseIab.netRevenue).to.equal(true); - expect(bidResponseIab.currency).to.equal('USD'); - expect(bidResponseIab.hb_bidder).to.equal('fan'); - expect(bidResponseIab.fb_bidid).to.equal('test-bid-id-iab'); - expect(bidResponseIab.fb_format).to.equal('300x250'); - expect(bidResponseIab.fb_placementid).to.equal(placementIdIab); - }); - - it('valid video bid in response', function () { - const bidId = 'test-bid-id-video'; - - const [bidResponse] = interpretResponse({ - body: { - errors: [], - bids: { - [placementId]: [{ - placement_id: placementId, - bid_id: bidId, - bid_price_cents: 123, - bid_price_currency: 'usd', - bid_price_model: 'cpm' - }] - } - } - }, { - adformats: ['video'], - requestIds: [requestId], - sizes: [[playerwidth, playerheight]], - pageurl: expectedPageUrl - }); - - expect(bidResponse.cpm).to.equal(1.23); - expect(bidResponse.requestId).to.equal(requestId); - expect(bidResponse.ttl).to.equal(3600); - expect(bidResponse.mediaType).to.equal('video'); - expect(bidResponse.vastUrl).to.equal(`https://an.facebook.com/v1/instream/vast.xml?placementid=${placementId}&pageurl=${expectedPageUrl}&playerwidth=${playerwidth}&playerheight=${playerheight}&bidid=${bidId}`); - expect(bidResponse.width).to.equal(playerwidth); - expect(bidResponse.height).to.equal(playerheight); - }); - - it('mixed video and native bids', function () { - const videoPlacementId = 'test-video-placement-id'; - const videoBidId = 'test-video-bid-id'; - const nativePlacementId = 'test-native-placement-id'; - const nativeBidId = 'test-native-bid-id'; - - const [bidResponseVideo, bidResponseNative] = interpretResponse({ - body: { - errors: [], - bids: { - [videoPlacementId]: [{ - placement_id: videoPlacementId, - bid_id: videoBidId, - bid_price_cents: 123, - bid_price_currency: 'usd', - bid_price_model: 'cpm' - }], - [nativePlacementId]: [{ - placement_id: nativePlacementId, - bid_id: nativeBidId, - bid_price_cents: 456, - bid_price_currency: 'usd', - bid_price_model: 'cpm' - }] - } - } - }, { - adformats: ['video', 'native'], - requestIds: [requestId, requestId], - sizes: [[playerwidth, playerheight], [300, 250]], - pageurl: expectedPageUrl - }); - - expect(bidResponseVideo.cpm).to.equal(1.23); - expect(bidResponseVideo.requestId).to.equal(requestId); - expect(bidResponseVideo.ttl).to.equal(3600); - expect(bidResponseVideo.mediaType).to.equal('video'); - expect(bidResponseVideo.vastUrl).to.equal(`https://an.facebook.com/v1/instream/vast.xml?placementid=${videoPlacementId}&pageurl=${expectedPageUrl}&playerwidth=${playerwidth}&playerheight=${playerheight}&bidid=${videoBidId}`); - expect(bidResponseVideo.width).to.equal(playerwidth); - expect(bidResponseVideo.height).to.equal(playerheight); - - expect(bidResponseNative.cpm).to.equal(4.56); - expect(bidResponseNative.requestId).to.equal(requestId); - expect(bidResponseNative.ttl).to.equal(600); - expect(bidResponseNative.width).to.equal(300); - expect(bidResponseNative.height).to.equal(250); - expect(bidResponseNative.ad) - .to.contain(`placementid: '${nativePlacementId}',`) - .and.to.contain(`format: 'native',`) - .and.to.contain(`bidid: '${nativeBidId}',`); - }); - - it('mixture of valid native bid and error in response', function () { - const [bidResponse] = interpretResponse({ - body: { - errors: ['test-error-message'], - bids: { - [placementId]: [{ - placement_id: placementId, - bid_id: 'test-bid-id', - bid_price_cents: 123, - bid_price_currency: 'usd', - bid_price_model: 'cpm' - }] - } - } - }, { - adformats: ['native'], - requestIds: [requestId], - sizes: [[300, 250]], - pageurl: expectedPageUrl - }); - - expect(bidResponse.cpm).to.equal(1.23); - expect(bidResponse.requestId).to.equal(requestId); - expect(bidResponse.width).to.equal(300); - expect(bidResponse.height).to.equal(250); - expect(bidResponse.ad) - .to.contain(`placementid: '${placementId}',`) - .and.to.contain(`format: 'native',`) - .and.to.contain(`bidid: 'test-bid-id',`) - .and.to.contain('getElementsByTagName("style")', 'ad missing native styles') - .and.to.contain('
', 'ad missing native container'); - expect(bidResponse.ttl).to.equal(600); - expect(bidResponse.creativeId).to.equal(placementId); - expect(bidResponse.netRevenue).to.equal(true); - expect(bidResponse.currency).to.equal('USD'); - - expect(bidResponse.hb_bidder).to.equal('fan'); - expect(bidResponse.fb_bidid).to.equal('test-bid-id'); - expect(bidResponse.fb_format).to.equal('native'); - expect(bidResponse.fb_placementid).to.equal(placementId); - }); - }); -}); diff --git a/test/spec/modules/automatadBidAdapter_spec.js b/test/spec/modules/automatadBidAdapter_spec.js index 788fd3aefc4..fca1a464ff2 100644 --- a/test/spec/modules/automatadBidAdapter_spec.js +++ b/test/spec/modules/automatadBidAdapter_spec.js @@ -86,6 +86,11 @@ describe('automatadBidAdapter', function () { expect(rdata.imp.length).to.equal(1) }) + it('should include placement', function () { + let r = rdata.imp[0] + expect(r.placement !== null).to.be.true + }) + it('should include media types', function () { let r = rdata.imp[0] expect(r.media_types !== null).to.be.true @@ -95,6 +100,11 @@ describe('automatadBidAdapter', function () { let r = rdata.imp[0] expect(r.siteID !== null && r.placementID !== null).to.be.true }) + + it('should include adunit code', function () { + let r = rdata.imp[0] + expect(r.adUnitCode !== null).to.be.true + }) }) describe('interpretResponse', function () { @@ -103,6 +113,56 @@ describe('automatadBidAdapter', function () { expect(result).to.be.an('array').that.is.not.empty }) + it('should interpret multiple bids in seatbid', function () { + let multipleBidResponse = [{ + 'body': { + 'id': 'abc-321', + 'seatbid': [ + { + 'bid': [ + { + 'adm': '', + 'adomain': [ + 'someAdDomain' + ], + 'crid': 123, + 'h': 600, + 'id': 'bid1', + 'impid': 'imp1', + 'nurl': 'https://example/win', + 'price': 0.5, + 'w': 300 + } + ] + }, { + 'bid': [ + { + 'adm': '', + 'adomain': [ + 'someAdDomain' + ], + 'crid': 321, + 'h': 600, + 'id': 'bid1', + 'impid': 'imp2', + 'nurl': 'https://example/win', + 'price': 0.5, + 'w': 300 + } + ] + } + ] + } + }] + let result = spec.interpretResponse(multipleBidResponse[0]).map(bid => { + const {requestId} = bid; + return [ requestId ]; + }); + + assert.equal(result.length, 2); + assert.deepEqual(result, [[ 'imp1' ], [ 'imp2' ]]); + }) + it('handles empty bid response', function () { let response = { body: '' diff --git a/test/spec/modules/avocetBidAdapter_spec.js b/test/spec/modules/avocetBidAdapter_spec.js new file mode 100644 index 00000000000..2a2f29e48d2 --- /dev/null +++ b/test/spec/modules/avocetBidAdapter_spec.js @@ -0,0 +1,167 @@ +import { expect } from 'chai'; +import { spec } from 'modules/avocetBidAdapter'; +import { newBidder } from 'src/adapters/bidderFactory'; +import { config } from 'src/config'; + +describe('Avocet adapter', function () { + beforeEach(function () { + config.setConfig({ + currency: { + adServerCurrency: 'USD', + }, + publisherDomain: 'test.com', + fpd: { + some: 'data', + }, + }); + }); + + afterEach(function () { + config.resetConfig(); + }); + + describe('inherited functions', function () { + it('exists and is a function', function () { + const adapter = newBidder(spec); + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + it('should return false for bid request missing params', () => { + const invalidBidRequest = { + bid: {}, + }; + expect(spec.isBidRequestValid(invalidBidRequest)).to.equal(false); + }); + it('should return false for an invalid type placement param', () => { + const invalidBidRequest = { + params: { + placement: 123, + }, + }; + expect(spec.isBidRequestValid(invalidBidRequest)).to.equal(false); + }); + it('should return false for an invalid length placement param', () => { + const invalidBidRequest = { + params: { + placement: '123', + }, + }; + expect(spec.isBidRequestValid(invalidBidRequest)).to.equal(false); + }); + it('should return true for a valid length placement param', () => { + const validBidRequest = { + params: { + placement: '012345678901234567890123', + }, + }; + expect(spec.isBidRequestValid(validBidRequest)).to.equal(true); + }); + }); + describe('buildRequests', function () { + it('constructs a valid POST request', function () { + const request = spec.buildRequests( + [ + { + bidder: 'avct', + params: { + placement: '012345678901234567890123', + }, + userId: { + id5id: { + uid: 'test' + } + } + }, + { + bidder: 'avct', + params: { + placement: '012345678901234567890123', + }, + }, + ], + exampleBidderRequest + ); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal('https://ads.avct.cloud/prebid'); + + const requestData = JSON.parse(request.data); + expect(requestData.ext).to.be.an('object'); + expect(requestData.ext.currency).to.equal('USD'); + expect(requestData.ext.publisherDomain).to.equal('test.com'); + expect(requestData.ext.fpd).to.deep.equal({ some: 'data' }); + expect(requestData.ext.schain).to.deep.equal({ + validation: 'strict', + config: { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + hp: 1, + }, + ], + }, + }); + expect(requestData.ext.id5id).to.equal('test'); + expect(requestData.bids).to.be.an('array'); + expect(requestData.bids.length).to.equal(2); + }); + }); + describe('interpretResponse', function () { + it('no response', function () { + const response = spec.interpretResponse(); + expect(response).to.be.an('array'); + expect(response.length).to.equal(0); + }); + it('no body', function () { + const response = spec.interpretResponse({}); + expect(response).to.be.an('array'); + expect(response.length).to.equal(0); + }); + it('null body', function () { + const response = spec.interpretResponse({ body: null }); + expect(response).to.be.an('array'); + expect(response.length).to.equal(0); + }); + it('empty body', function () { + const response = spec.interpretResponse({ body: {} }); + expect(response).to.be.an('array'); + expect(response.length).to.equal(0); + }); + it('null body.responses', function () { + const response = spec.interpretResponse({ body: { responses: null } }); + expect(response).to.be.an('array'); + expect(response.length).to.equal(0); + }); + it('array body', function () { + const response = spec.interpretResponse({ body: [{}] }); + expect(response).to.be.an('array'); + expect(response.length).to.equal(1); + }); + it('array body.responses', function () { + const response = spec.interpretResponse({ body: { responses: [{}] } }); + expect(response).to.be.an('array'); + expect(response.length).to.equal(1); + }); + }); +}); + +const exampleBidderRequest = { + schain: { + validation: 'strict', + config: { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + hp: 1, + }, + ], + }, + }, +}; diff --git a/test/spec/modules/beachfrontBidAdapter_spec.js b/test/spec/modules/beachfrontBidAdapter_spec.js index f7dcc1305e5..5711e111e30 100644 --- a/test/spec/modules/beachfrontBidAdapter_spec.js +++ b/test/spec/modules/beachfrontBidAdapter_spec.js @@ -146,6 +146,7 @@ describe('BeachfrontAdapter', function () { const width = 640; const height = 480; const bidRequest = bidRequests[0]; + bidRequest.params.tagid = '7cd7a7b4-ef3f-4aeb-9565-3627f255fa10'; bidRequest.mediaTypes = { video: { playerSize: [ width, height ] @@ -165,6 +166,7 @@ describe('BeachfrontAdapter', function () { expect(data.id).to.be.a('string'); expect(data.imp[0].video).to.deep.contain({ w: width, h: height, mimes: DEFAULT_MIMES }); expect(data.imp[0].bidfloor).to.equal(bidRequest.params.bidfloor); + expect(data.imp[0].tagid).to.equal(bidRequest.params.tagid); expect(data.site).to.deep.equal({ page: topLocation.href, domain: topLocation.hostname }); expect(data.device).to.deep.contain({ ua: navigator.userAgent, language: navigator.language, js: 1 }); expect(data.cur).to.deep.equal(['USD']); diff --git a/test/spec/modules/bluebillywigBidAdapter_spec.js b/test/spec/modules/bluebillywigBidAdapter_spec.js index fcf3e16ad8b..56ea29d6d73 100644 --- a/test/spec/modules/bluebillywigBidAdapter_spec.js +++ b/test/spec/modules/bluebillywigBidAdapter_spec.js @@ -40,6 +40,13 @@ describe('BlueBillywigAdapter', () => { expect(spec.isBidRequestValid(baseValidBid)).to.equal(true); }); + it('should return false when params missing', () => { + const bid = deepClone(baseValidBid); + delete bid.params; + + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + it('should return false when publicationName is missing', () => { const bid = deepClone(baseValidBid); delete bid.params.publicationName; @@ -184,6 +191,25 @@ describe('BlueBillywigAdapter', () => { bid.mediaTypes[VIDEO].context = 'instream'; expect(spec.isBidRequestValid(bid)).to.equal(false); }); + + it('should fail if video is specified but is not an object', () => { + const bid = deepClone(baseValidBid); + + bid.params.video = null; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.video = 'string'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.video = 123; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.video = false; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.video = void (0); + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); }); describe('buildRequests', () => { @@ -358,6 +384,24 @@ describe('BlueBillywigAdapter', () => { expect(payload.device.h).to.be.a('number'); }); + it('should add site when specified in config', () => { + config.setConfig({ site: { name: 'Blue Billywig', domain: 'bluebillywig.com', page: 'https://bluebillywig.com/', publisher: { id: 'abc', name: 'Blue Billywig', domain: 'bluebillywig.com' } } }); + + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.property('site'); + expect(payload).to.have.nested.property('site.name'); + expect(payload).to.have.nested.property('site.domain'); + expect(payload).to.have.nested.property('site.page'); + expect(payload).to.have.nested.property('site.publisher'); + expect(payload).to.have.nested.property('site.publisher.id'); + expect(payload).to.have.nested.property('site.publisher.name'); + expect(payload).to.have.nested.property('site.publisher.domain'); + + config.resetConfig(); + }); + it('should add app when specified in config', () => { config.setConfig({ app: { bundle: 'org.prebid.mobile.demoapp', domain: 'prebid.org' } }); @@ -492,30 +536,64 @@ describe('BlueBillywigAdapter', () => { expect(deepAccess(payload, 'user.ext.eids')).to.be.undefined; }); - it('should set digitrust when present on bid', () => { - const digiTrust = {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}; + it('should set imp.0.video.[w|h|placement] by default', () => { + const newBaseValidBidRequests = deepClone(baseValidBidRequests); + const request = spec.buildRequests(newBaseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(deepAccess(payload, 'imp.0.video.w')).to.equal(768); + expect(deepAccess(payload, 'imp.0.video.h')).to.equal(432); + expect(deepAccess(payload, 'imp.0.video.placement')).to.equal(3); + }); + + it('should update imp0.video.[w|h] when present in config', () => { const newBaseValidBidRequests = deepClone(baseValidBidRequests); - newBaseValidBidRequests[0].userId = { digitrustid: digiTrust }; + newBaseValidBidRequests[0].mediaTypes.video.playerSize = [1, 1]; const request = spec.buildRequests(newBaseValidBidRequests, validBidderRequest); const payload = JSON.parse(request.data); - expect(payload).to.have.nested.property('user.ext.digitrust'); - expect(payload.user.ext.digitrust.id).to.equal(digiTrust.data.id); - expect(payload.user.ext.digitrust.keyv).to.equal(digiTrust.data.keyv); + expect(deepAccess(payload, 'imp.0.video.w')).to.equal(1); + expect(deepAccess(payload, 'imp.0.video.h')).to.equal(1); }); - it('should not set digitrust when opted out', () => { - const digiTrust = {data: {id: 'DTID', keyv: 4, privacy: {optout: true}, producer: 'ABC', version: 2}}; + it('should allow overriding any imp0.video key through params.video', () => { + const newBaseValidBidRequests = deepClone(baseValidBidRequests); + newBaseValidBidRequests[0].params.video = { + w: 2, + h: 2, + placement: 1, + minduration: 15, + maxduration: 30 + }; + + const request = spec.buildRequests(newBaseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(deepAccess(payload, 'imp.0.video.w')).to.equal(2); + expect(deepAccess(payload, 'imp.0.video.h')).to.equal(2); + expect(deepAccess(payload, 'imp.0.video.placement')).to.equal(1); + expect(deepAccess(payload, 'imp.0.video.minduration')).to.equal(15); + expect(deepAccess(payload, 'imp.0.video.maxduration')).to.equal(30); + }); + it('should not allow placing any non-OpenRTB 2.5 keys on imp.0.video through params.video', () => { const newBaseValidBidRequests = deepClone(baseValidBidRequests); - newBaseValidBidRequests[0].userId = { digitrustid: digiTrust }; + newBaseValidBidRequests[0].params.video = { + 'true': true, + 'testing': 'some', + 123: {}, + '': 'values' + }; const request = spec.buildRequests(newBaseValidBidRequests, validBidderRequest); const payload = JSON.parse(request.data); - expect(deepAccess(payload, 'user.ext.digitrust')).to.be.undefined; + expect(deepAccess(request, 'imp.0.video.true')).to.be.undefined; + expect(deepAccess(payload, 'imp.0.video.testing')).to.be.undefined; + expect(deepAccess(payload, 'imp.0.video.123')).to.be.undefined; + expect(deepAccess(payload, 'imp.0.video.')).to.be.undefined; }); }); describe('interpretResponse', () => { @@ -553,7 +631,7 @@ describe('BlueBillywigAdapter', () => { bidder: BB_CONSTANTS.BIDDER_CODE, bidderRequestId: '1a2345b67c8d9e0', params: baseValidBid.params, - sizes: [[768, 432], [640, 480], [630, 360]], + sizes: [[640, 480], [630, 360]], transactionId: '2b34c5de-f67a-8901-bcd2-34567efabc89' }], start: 11585918458869, @@ -741,6 +819,101 @@ describe('BlueBillywigAdapter', () => { expect(result.length).to.equal(0); } }); + + it('should take default width and height when w/h not present', () => { + const bidSizesMissing = deepClone(serverResponse); + + delete bidSizesMissing.body.seatbid[0].bid[0].w; + delete bidSizesMissing.body.seatbid[0].bid[0].h; + + const response = bidSizesMissing; + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(deepAccess(result, '0.width')).to.equal(768); + expect(deepAccess(result, '0.height')).to.equal(432); + }); + + it('should take nurl value when adm not present', () => { + const bidAdmMissing = deepClone(serverResponse); + + delete bidAdmMissing.body.seatbid[0].bid[0].adm; + bidAdmMissing.body.seatbid[0].bid[0].nurl = 'https://bluebillywig.com'; + + const response = bidAdmMissing; + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(deepAccess(result, '0.vastXml')).to.be.undefined; + expect(deepAccess(result, '0.vastUrl')).to.equal('https://bluebillywig.com'); + }); + + it('should not take nurl value when adm present', () => { + const bidAdmNurlPresent = deepClone(serverResponse); + + bidAdmNurlPresent.body.seatbid[0].bid[0].nurl = 'https://bluebillywig.com'; + + const response = bidAdmNurlPresent; + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(deepAccess(result, '0.vastXml')).to.equal(bidAdmNurlPresent.body.seatbid[0].bid[0].adm); + expect(deepAccess(result, '0.vastUrl')).to.be.undefined; + }); + + it('should take ext.prebid.cache data when present, ignore ext.prebid.targeting and nurl', () => { + const bidExtPrebidCache = deepClone(serverResponse); + + delete bidExtPrebidCache.body.seatbid[0].bid[0].adm; + bidExtPrebidCache.body.seatbid[0].bid[0].nurl = 'https://notnurl.com'; + + bidExtPrebidCache.body.seatbid[0].bid[0].ext = { + prebid: { + cache: { + vastXml: { + url: 'https://bluebillywig.com', + cacheId: '12345' + } + }, + targeting: { + hb_uuid: '23456', + hb_cache_host: 'bluebillywig.com', + hb_cache_path: '/cache' + } + } + }; + + const response = bidExtPrebidCache; + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(deepAccess(result, '0.vastUrl')).to.equal('https://bluebillywig.com'); + expect(deepAccess(result, '0.videoCacheKey')).to.equal('12345'); + }); + + it('should take ext.prebid.targeting data when ext.prebid.cache not present, and ignore nurl', () => { + const bidExtPrebidTargeting = deepClone(serverResponse); + + delete bidExtPrebidTargeting.body.seatbid[0].bid[0].adm; + bidExtPrebidTargeting.body.seatbid[0].bid[0].nurl = 'https://notnurl.com'; + + bidExtPrebidTargeting.body.seatbid[0].bid[0].ext = { + prebid: { + targeting: { + hb_uuid: '34567', + hb_cache_host: 'bluebillywig.com', + hb_cache_path: '/cache' + } + } + }; + + const response = bidExtPrebidTargeting; + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(deepAccess(result, '0.vastUrl')).to.equal('https://bluebillywig.com/cache?uuid=34567'); + expect(deepAccess(result, '0.videoCacheKey')).to.equal('34567'); + }); }); describe('getUserSyncs', () => { const publicationName = 'bbprebid.dev'; diff --git a/test/spec/modules/boldwinBidAdapter_spec.js b/test/spec/modules/boldwinBidAdapter_spec.js new file mode 100644 index 00000000000..a353665ec33 --- /dev/null +++ b/test/spec/modules/boldwinBidAdapter_spec.js @@ -0,0 +1,281 @@ +import {expect} from 'chai'; +import {spec} from '../../../modules/boldwinBidAdapter.js'; +import { BANNER, VIDEO } from '../../../src/mediaTypes.js'; + +describe('BoldwinBidAdapter', function () { + const bid = { + bidId: '23fhj33i987f', + bidder: 'boldwin', + params: { + placementId: 0, + traffic: BANNER + } + }; + + const bidderRequest = { + refererInfo: { + referer: 'test.com' + } + }; + + describe('isBidRequestValid', function () { + it('Should return true if there are bidId, params and placementId parameters present', function () { + expect(spec.isBidRequestValid(bid)).to.be.true; + }); + it('Should return false if at least one of parameters is not present', function () { + delete bid.params.placementId; + expect(spec.isBidRequestValid(bid)).to.be.false; + }); + }); + + describe('buildRequests', function () { + let serverRequest = spec.buildRequests([bid], bidderRequest); + it('Creates a ServerRequest object with method, URL and data', function () { + expect(serverRequest).to.exist; + expect(serverRequest.method).to.exist; + expect(serverRequest.url).to.exist; + expect(serverRequest.data).to.exist; + }); + it('Returns POST method', function () { + expect(serverRequest.method).to.equal('POST'); + }); + it('Returns valid URL', function () { + expect(serverRequest.url).to.equal('https://ssp.videowalldirect.com/?c=o&m=multi'); + }); + it('Returns valid data if array of bids is valid', function () { + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements'); + expect(data.deviceWidth).to.be.a('number'); + expect(data.deviceHeight).to.be.a('number'); + expect(data.language).to.be.a('string'); + expect(data.secure).to.be.within(0, 1); + expect(data.host).to.be.a('string'); + expect(data.page).to.be.a('string'); + expect(data.gdpr).to.not.exist; + expect(data.ccpa).to.not.exist; + let placement = data['placements'][0]; + expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'sizes', 'hPlayer', 'wPlayer', 'schain'); + expect(placement.placementId).to.equal(0); + expect(placement.bidId).to.equal('23fhj33i987f'); + expect(placement.traffic).to.equal(BANNER); + expect(placement.schain).to.be.an('object'); + }); + + it('Returns valid data for mediatype video', function () { + const playerSize = [300, 300]; + bid.mediaTypes = {}; + bid.params.traffic = VIDEO; + bid.mediaTypes[VIDEO] = { + playerSize + }; + serverRequest = spec.buildRequests([bid], bidderRequest); + let data = serverRequest.data; + expect(data).to.be.an('object'); + let placement = data['placements'][0]; + expect(placement).to.be.an('object'); + expect(placement.traffic).to.equal(VIDEO); + expect(placement.wPlayer).to.equal(playerSize[0]); + expect(placement.hPlayer).to.equal(playerSize[1]); + }); + + it('Returns data with gdprConsent and without uspConsent', function () { + bidderRequest.gdprConsent = 'test'; + serverRequest = spec.buildRequests([bid], bidderRequest); + let data = serverRequest.data; + expect(data.gdpr).to.exist; + expect(data.gdpr).to.be.a('string'); + expect(data.gdpr).to.equal(bidderRequest.gdprConsent); + expect(data.ccpa).to.not.exist; + delete bidderRequest.gdprConsent; + }); + + it('Returns data with uspConsent and without gdprConsent', function () { + bidderRequest.uspConsent = 'test'; + serverRequest = spec.buildRequests([bid], bidderRequest); + let data = serverRequest.data; + expect(data.ccpa).to.exist; + expect(data.ccpa).to.be.a('string'); + expect(data.ccpa).to.equal(bidderRequest.uspConsent); + expect(data.gdpr).to.not.exist; + }); + + it('Returns empty data if no valid requests are passed', function () { + serverRequest = spec.buildRequests([]); + let data = serverRequest.data; + expect(data.placements).to.be.an('array').that.is.empty; + }); + }); + describe('interpretResponse', function () { + it('Should interpret banner response', function () { + const banner = { + body: [{ + mediaType: 'banner', + width: 300, + height: 250, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let bannerResponses = spec.interpretResponse(banner); + expect(bannerResponses).to.be.an('array').that.is.not.empty; + let dataItem = bannerResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType'); + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.4); + expect(dataItem.width).to.equal(300); + expect(dataItem.height).to.equal(250); + expect(dataItem.ad).to.equal('Test'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + }); + it('Should interpret video response', function () { + const video = { + body: [{ + vastUrl: 'test.com', + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let videoResponses = spec.interpretResponse(video); + expect(videoResponses).to.be.an('array').that.is.not.empty; + + let dataItem = videoResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'vastUrl', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType'); + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.5); + expect(dataItem.vastUrl).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + }); + it('Should interpret native response', function () { + const native = { + body: [{ + mediaType: 'native', + native: { + clickUrl: 'test.com', + title: 'Test', + image: 'test.com', + impressionTrackers: ['test.com'], + }, + ttl: 120, + cpm: 0.4, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + }] + }; + let nativeResponses = spec.interpretResponse(native); + expect(nativeResponses).to.be.an('array').that.is.not.empty; + + let dataItem = nativeResponses[0]; + expect(dataItem).to.have.keys('requestId', 'cpm', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'native'); + expect(dataItem.native).to.have.keys('clickUrl', 'impressionTrackers', 'title', 'image') + expect(dataItem.requestId).to.equal('23fhj33i987f'); + expect(dataItem.cpm).to.equal(0.4); + expect(dataItem.native.clickUrl).to.equal('test.com'); + expect(dataItem.native.title).to.equal('Test'); + expect(dataItem.native.image).to.equal('test.com'); + expect(dataItem.native.impressionTrackers).to.be.an('array').that.is.not.empty; + expect(dataItem.native.impressionTrackers[0]).to.equal('test.com'); + expect(dataItem.ttl).to.equal(120); + expect(dataItem.creativeId).to.equal('2'); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal('USD'); + }); + it('Should return an empty array if invalid banner response is passed', function () { + const invBanner = { + body: [{ + width: 300, + cpm: 0.4, + ad: 'Test', + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + + let serverResponses = spec.interpretResponse(invBanner); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid video response is passed', function () { + const invVideo = { + body: [{ + mediaType: 'video', + cpm: 0.5, + requestId: '23fhj33i987f', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invVideo); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid native response is passed', function () { + const invNative = { + body: [{ + mediaType: 'native', + clickUrl: 'test.com', + title: 'Test', + impressionTrackers: ['test.com'], + ttl: 120, + requestId: '23fhj33i987f', + creativeId: '2', + netRevenue: true, + currency: 'USD', + }] + }; + let serverResponses = spec.interpretResponse(invNative); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + it('Should return an empty array if invalid response is passed', function () { + const invalid = { + body: [{ + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }; + let serverResponses = spec.interpretResponse(invalid); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + }); + + describe('getUserSyncs', function () { + let userSync = spec.getUserSyncs(); + it('Returns valid URL and type', function () { + expect(userSync).to.be.an('array').with.lengthOf(1); + expect(userSync[0].type).to.exist; + expect(userSync[0].url).to.exist; + expect(userSync[0].type).to.be.equal('image'); + expect(userSync[0].url).to.be.equal('https://cs.videowalldirect.com/?c=o&m=cookie'); + }); + }); +}); diff --git a/test/spec/modules/bridgewellBidAdapter_spec.js b/test/spec/modules/bridgewellBidAdapter_spec.js index 644f468abe8..24ec523ac67 100644 --- a/test/spec/modules/bridgewellBidAdapter_spec.js +++ b/test/spec/modules/bridgewellBidAdapter_spec.js @@ -22,6 +22,16 @@ describe('bridgewellBidAdapter', function () { expect(spec.isBidRequestValid(validTag)).to.equal(true); }); + it('should return true when required params found', function () { + const validTag = { + 'bidder': 'bridgewell', + 'params': { + 'cid': 1234 + }, + }; + expect(spec.isBidRequestValid(validTag)).to.equal(true); + }); + it('should return false when required params not found', function () { const invalidTag = { 'bidder': 'bridgewell', @@ -39,6 +49,26 @@ describe('bridgewellBidAdapter', function () { }; expect(spec.isBidRequestValid(invalidTag)).to.equal(false); }); + + it('should return false when required params are empty', function () { + const invalidTag = { + 'bidder': 'bridgewell', + 'params': { + 'cid': '', + }, + }; + expect(spec.isBidRequestValid(invalidTag)).to.equal(false); + }); + + it('should return false when required param cid is not a number', function () { + const invalidTag = { + 'bidder': 'bridgewell', + 'params': { + 'cid': 'bad_cid', + }, + }; + expect(spec.isBidRequestValid(invalidTag)).to.equal(false); + }); }); describe('buildRequests', function () { @@ -113,12 +143,58 @@ describe('bridgewellBidAdapter', function () { expect(payload.url).to.exist.and.to.equal('https://www.bridgewell.com/'); for (let i = 0, max_i = payload.adUnits.length; i < max_i; i++) { expect(payload.adUnits[i]).to.have.property('ChannelID').that.is.a('string'); + expect(payload.adUnits[i]).to.not.have.property('cid'); expect(payload.adUnits[i]).to.have.property('adUnitCode').and.to.equal('adunit-code-2'); + expect(payload.adUnits[i]).to.have.property('requestId').and.to.equal('3150ccb55da321'); + } + }); + + it('should attach valid params to the tag, part2', function() { + const bidderRequest = { + refererInfo: { + referer: 'https://www.bridgewell.com/' + } + } + const bidRequests2 = [ + { + 'bidder': 'bridgewell', + 'params': { + 'cid': 1234, + }, + 'adUnitCode': 'adunit-code-2', + 'mediaTypes': { + 'banner': { + 'sizes': [728, 90] + } + }, + 'bidId': '3150ccb55da321', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }, + ]; + + const request = spec.buildRequests(bidRequests2, bidderRequest); + const payload = request.data; + + expect(payload).to.be.an('object'); + expect(payload.adUnits).to.be.an('array'); + expect(payload.url).to.exist.and.to.equal('https://www.bridgewell.com/'); + for (let i = 0, max_i = payload.adUnits.length; i < max_i; i++) { + expect(payload.adUnits[i]).to.have.property('cid').that.is.a('number'); + expect(payload.adUnits[i]).to.not.have.property('ChannelID'); + expect(payload.adUnits[i]).to.have.property('adUnitCode').and.to.equal('adunit-code-2'); + expect(payload.adUnits[i]).to.have.property('requestId').and.to.equal('3150ccb55da321'); } }); it('should attach validBidRequests to the tag', function () { - const request = spec.buildRequests(bidRequests); + const bidderRequest = { + refererInfo: { + referer: 'https://www.bridgewell.com/' + } + } + + const request = spec.buildRequests(bidRequests, bidderRequest); const validBidRequests = request.validBidRequests; expect(validBidRequests).to.deep.equal(bidRequests); }); diff --git a/test/spec/modules/brightMountainMediaBidAdapter_spec.js b/test/spec/modules/brightMountainMediaBidAdapter_spec.js new file mode 100644 index 00000000000..f6312253722 --- /dev/null +++ b/test/spec/modules/brightMountainMediaBidAdapter_spec.js @@ -0,0 +1,139 @@ +import { expect } from 'chai'; +import { spec } from '../../../modules/brightMountainMediaBidAdapter.js'; + +describe('brightMountainMediaBidAdapter_spec', function () { + let bid = { + bidId: '2dd581a2b6281d', + bidder: 'brightmountainmedia', + bidderRequestId: '145e1d6a7837c9', + params: { + placement_id: '123qwerty' + }, + placementCode: 'placementid_0', + auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + transactionId: '3bb2f6da-87a6-4029-aeb0-bfe951372e62', + }; + let bidderRequest = { + bidderCode: 'brightmountainmedia', + auctionId: 'fffffff-ffff-ffff-ffff-ffffffffffff', + bidderRequestId: 'ffffffffffffff', + start: 1472239426002, + auctionStart: 1472239426000, + timeout: 5000, + uspConsent: '1YN-', + refererInfo: { + referer: 'http://www.example.com', + reachedTop: true, + }, + bids: [bid] + } + + describe('isBidRequestValid', function () { + it('Should return true when when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.be.true; + }); + it('Should return false when required params are not passed', function () { + bid.params = {} + expect(spec.isBidRequestValid(bid)).to.be.false; + }); + }); + + describe('buildRequests', function () { + let serverRequest = spec.buildRequests([bid], bidderRequest); + it('Creates a ServerRequest object with method, URL and data', function () { + expect(serverRequest).to.exist; + expect(serverRequest.method).to.exist; + expect(serverRequest.url).to.exist; + expect(serverRequest.data).to.exist; + }); + it('Returns POST method', function () { + expect(serverRequest.method).to.equal('POST'); + }); + it('Returns valid URL', function () { + expect(serverRequest.url).to.equal('https://console.brightmountainmedia.com/hb/bid'); + }); + + it('Returns valid data if array of bids is valid', function () { + let data = serverRequest.data; + expect(data).to.be.an('object'); + expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements'); + expect(data.deviceWidth).to.be.a('number'); + expect(data.deviceHeight).to.be.a('number'); + expect(data.language).to.be.a('string'); + expect(data.secure).to.be.within(0, 1); + expect(data.host).to.be.a('string'); + expect(data.page).to.be.a('string'); + let placements = data['placements']; + for (let i = 0; i < placements.length; i++) { + let placement = placements[i]; + expect(placement).to.have.all.keys('placementId', 'bidId', 'traffic', 'sizes'); + expect(placement.placementId).to.be.a('string'); + expect(placement.bidId).to.be.a('string'); + expect(placement.traffic).to.be.a('string'); + expect(placement.sizes).to.be.an('array'); + } + }); + it('Returns empty data if no valid requests are passed', function () { + serverRequest = spec.buildRequests([]); + let data = serverRequest.data; + expect(data.placements).to.be.an('array').that.is.empty; + }); + }); + describe('interpretResponse', function () { + let resObject = { + body: [{ + requestId: '123', + mediaType: 'banner', + cpm: 0.3, + width: 320, + height: 50, + ad: '

Hello ad

', + ttl: 1000, + creativeId: '123asd', + netRevenue: true, + currency: 'USD' + }] + }; + let serverResponses = spec.interpretResponse(resObject); + it('Returns an array of valid server responses if response object is valid', function () { + expect(serverResponses).to.be.an('array').that.is.not.empty; + for (let i = 0; i < serverResponses.length; i++) { + let dataItem = serverResponses[i]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'mediaType'); + expect(dataItem.requestId).to.be.a('string'); + expect(dataItem.cpm).to.be.a('number'); + expect(dataItem.width).to.be.a('number'); + expect(dataItem.height).to.be.a('number'); + expect(dataItem.ad).to.be.a('string'); + expect(dataItem.ttl).to.be.a('number'); + expect(dataItem.creativeId).to.be.a('string'); + expect(dataItem.netRevenue).to.be.a('boolean'); + expect(dataItem.currency).to.be.a('string'); + expect(dataItem.mediaType).to.be.a('string'); + } + it('Returns an empty array if invalid response is passed', function () { + serverResponses = spec.interpretResponse('invalid_response'); + expect(serverResponses).to.be.an('array').that.is.empty; + }); + }); + }); + + describe('getUserSyncs', function () { + let syncoptionsIframe = { + 'iframeEnabled': 'true' + } + it('should return iframe sync option', function () { + expect(spec.getUserSyncs(syncoptionsIframe)).to.be.an('array').with.lengthOf(1); + expect(spec.getUserSyncs(syncoptionsIframe)[0].type).to.exist; + expect(spec.getUserSyncs(syncoptionsIframe)[0].url).to.exist; + expect(spec.getUserSyncs(syncoptionsIframe)[0].type).to.equal('iframe') + expect(spec.getUserSyncs(syncoptionsIframe)[0].url).to.equal('https://console.brightmountainmedia.com:8443/cookieSync') + }); + }); +}); diff --git a/test/spec/modules/brightcomBidAdapter_spec.js b/test/spec/modules/brightcomBidAdapter_spec.js index 6477e94d9d6..a89391d681e 100644 --- a/test/spec/modules/brightcomBidAdapter_spec.js +++ b/test/spec/modules/brightcomBidAdapter_spec.js @@ -141,6 +141,31 @@ describe('brightcomBidAdapter', function() { expect(payload.site.publisher.id).to.equal(1234567); }); + it('sends gdpr info if exists', function () { + const consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; + const bidderRequest = { + 'bidderCode': 'brightcom', + 'auctionId': '1d1a030790a437', + 'bidderRequestId': '22edbae2744bf5', + 'timeout': 3000, + gdprConsent: { + consentString: consentString, + gdprApplies: true + }, + refererInfo: { + referer: 'http://example.com/page.html', + } + }; + bidderRequest.bids = bidRequests; + + const data = JSON.parse(spec.buildRequests(bidRequests, bidderRequest).data); + + expect(data.regs.ext.gdpr).to.exist.and.to.be.a('number'); + expect(data.regs.ext.gdpr).to.equal(1); + expect(data.user.ext.consent).to.exist.and.to.be.a('string'); + expect(data.user.ext.consent).to.equal(consentString); + }); + context('when element is fully in view', function() { it('returns 100', function() { Object.assign(element, { width: 600, height: 400 }); diff --git a/test/spec/modules/britepoolIdSystem_spec.js b/test/spec/modules/britepoolIdSystem_spec.js index 2c6dd234a90..f2dd2ef533f 100644 --- a/test/spec/modules/britepoolIdSystem_spec.js +++ b/test/spec/modules/britepoolIdSystem_spec.js @@ -1,5 +1,5 @@ -import { expect } from 'chai'; import {britepoolIdSubmodule} from 'modules/britepoolIdSystem.js'; +import * as utils from '../../../src/utils.js'; describe('BritePool Submodule', () => { const api_key = '1111'; @@ -16,6 +16,32 @@ describe('BritePool Submodule', () => { }; }; + let triggerPixelStub; + + beforeEach(function (done) { + triggerPixelStub = sinon.stub(utils, 'triggerPixel'); + done(); + }); + + afterEach(function () { + triggerPixelStub.restore(); + }); + + it('trigger id resolution pixel when no identifiers set', () => { + britepoolIdSubmodule.getId({}); + expect(triggerPixelStub.called).to.be.true; + }); + + it('trigger id resolution pixel when no identifiers set with api_key param', () => { + britepoolIdSubmodule.getId({ api_key }); + expect(triggerPixelStub.called).to.be.true; + }); + + it('does not trigger id resolution pixel when identifiers set', () => { + britepoolIdSubmodule.getId({ api_key, aaid }); + expect(triggerPixelStub.called).to.be.false; + }); + it('sends x-api-key in header and one identifier', () => { const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid }); assert(errors.length === 0, errors); @@ -43,6 +69,42 @@ describe('BritePool Submodule', () => { expect(params.url).to.be.undefined; }); + it('test gdpr consent string in url', () => { + const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid }, { gdprApplies: true, consentString: 'expectedConsentString' }); + expect(url).to.equal('https://api.britepool.com/v1/britepool/id?gdprString=expectedConsentString'); + }); + + it('test gdpr consent string not in url if gdprApplies false', () => { + const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid }, { gdprApplies: false, consentString: 'expectedConsentString' }); + expect(url).to.equal('https://api.britepool.com/v1/britepool/id'); + }); + + it('test gdpr consent string not in url if consent string undefined', () => { + const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid }, { gdprApplies: true, consentString: undefined }); + expect(url).to.equal('https://api.britepool.com/v1/britepool/id'); + }); + + it('dynamic pub params should be added to params', () => { + window.britepool_pubparams = { ppid: '12345' }; + const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid }); + expect(params).to.eql({ aaid, ppid: '12345' }); + window.britepool_pubparams = undefined; + }); + + it('dynamic pub params should override submodule params', () => { + window.britepool_pubparams = { ppid: '67890' }; + const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, ppid: '12345' }); + expect(params).to.eql({ ppid: '67890' }); + window.britepool_pubparams = undefined; + }); + + it('if dynamic pub params undefined do nothing', () => { + window.britepool_pubparams = undefined; + const { params, headers, url, errors } = britepoolIdSubmodule.createParams({ api_key, aaid }); + expect(params).to.eql({ aaid }); + window.britepool_pubparams = undefined; + }); + it('test getter override with value', () => { const { params, headers, url, getter, errors } = britepoolIdSubmodule.createParams({ api_key, aaid, url: url_override, getter: getter_override }); expect(getter).to.equal(getter_override); diff --git a/test/spec/modules/categoryTranslation_spec.js b/test/spec/modules/categoryTranslation_spec.js index 555fe3d6357..2301d6aab1b 100644 --- a/test/spec/modules/categoryTranslation_spec.js +++ b/test/spec/modules/categoryTranslation_spec.js @@ -34,7 +34,7 @@ describe('category translation', function () { })); let bid = { meta: { - iabSubCatId: 'iab-1' + primaryCatId: 'iab-1' } } getAdserverCategoryHook(sinon.spy(), 'code', bid); @@ -57,7 +57,7 @@ describe('category translation', function () { })); let bid = { meta: { - iabSubCatId: 'iab-2' + primaryCatId: 'iab-2' } } getAdserverCategoryHook(sinon.spy(), 'code', bid); @@ -77,6 +77,19 @@ describe('category translation', function () { clock.restore(); }); + it('should make ajax call to update mapping file if data found in localstorage is expired', function () { + let clock = sinon.useFakeTimers(utils.timestamp()); + getLocalStorageStub.returns(JSON.stringify({ + lastUpdated: utils.timestamp() - 2 * 24 * 60 * 60 * 1000, + mapping: { + 'iab-1': '1' + } + })); + initTranslation(); + expect(fakeTranslationServer.requests.length).to.equal(1); + clock.restore(); + }); + it('should use default mapping file if publisher has not defined in config', function () { getLocalStorageStub.returns(null); initTranslation('http://sample.com', 'somekey'); @@ -84,7 +97,7 @@ describe('category translation', function () { expect(fakeTranslationServer.requests[0].url).to.equal('http://sample.com'); }); - it('should use publisher defined defined mapping file', function () { + it('should use publisher defined mapping file', function () { config.setConfig({ 'brandCategoryTranslation': { 'translationFile': 'http://sample.com' diff --git a/test/spec/modules/cointrafficBidAdapter_spec.js b/test/spec/modules/cointrafficBidAdapter_spec.js new file mode 100644 index 00000000000..6d948e36cb9 --- /dev/null +++ b/test/spec/modules/cointrafficBidAdapter_spec.js @@ -0,0 +1,145 @@ +import { expect } from 'chai'; +import { spec } from 'modules/cointrafficBidAdapter.js'; + +const ENDPOINT_URL = 'https://appspb.cointraffic.io/pb/tmp'; + +describe('cointrafficBidAdapter', function () { + describe('isBidRequestValid', function () { + let bid = { + bidder: 'cointraffic', + params: { + placementId: 'testPlacementId' + }, + adUnitCode: 'adunit-code', + sizes: [ + [300, 250] + ], + bidId: 'bidId12345', + bidderRequestId: 'bidderRequestId12345', + auctionId: 'auctionId12345' + }; + + it('should return true where required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + }); + + describe('buildRequests', function () { + let bidRequests = [ + { + bidder: 'cointraffic', + params: { + placementId: 'testPlacementId' + }, + adUnitCode: 'adunit-code', + sizes: [ + [300, 250] + ], + bidId: 'bidId12345', + bidderRequestId: 'bidderRequestId12345', + auctionId: 'auctionId12345', + }, + { + bidder: 'cointraffic', + params: { + placementId: 'testPlacementId' + }, + adUnitCode: 'adunit-code2', + sizes: [ + [300, 250] + ], + bidId: 'bidId67890"', + bidderRequestId: 'bidderRequestId67890', + auctionId: 'auctionId12345', + } + ]; + + let bidderRequests = { + refererInfo: { + numIframes: 0, + reachedTop: true, + referer: 'https://example.com', + stack: [ + 'https://example.com' + ] + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequests); + + it('sends bid request to our endpoint via POST', function () { + expect(request[0].method).to.equal('POST'); + expect(request[1].method).to.equal('POST'); + }); + it('attaches source and version to endpoint URL as query params', function () { + expect(request[0].url).to.equal(ENDPOINT_URL); + expect(request[1].url).to.equal(ENDPOINT_URL); + }); + }); + + describe('interpretResponse', function () { + let bidRequest = [ + { + method: 'POST', + url: ENDPOINT_URL, + data: { + placementId: 'testPlacementId', + device: 'desktop', + sizes: ['300x250'], + bidId: 'bidId12345', + referer: 'www.example.com' + } + } + ]; + + it('should get the correct bid response', function () { + let serverResponse = { + body: { + requestId: 'bidId12345', + cpm: 3.9, + currency: 'EUR', + netRevenue: true, + width: 300, + height: 250, + creativeId: 'creativeId12345', + ttl: 90, + ad: '

I am an ad

', + } + }; + + let expectedResponse = [{ + requestId: 'bidId12345', + cpm: 3.9, + currency: 'EUR', + netRevenue: true, + width: 300, + height: 250, + creativeId: 'creativeId12345', + ttl: 90, + ad: '

I am an ad

' + }]; + let result = spec.interpretResponse(serverResponse, bidRequest[0]); + expect(Object.keys(result)).to.deep.equal(Object.keys(expectedResponse)); + }); + + it('should get empty bid response if server response body is empty', function () { + let serverResponse = { + body: {} + }; + + let expectedResponse = []; + + let result = spec.interpretResponse(serverResponse, bidRequest[0]); + expect(Object.keys(result)).to.deep.equal(Object.keys(expectedResponse)); + }); + + it('should get empty bid response if no server response', function () { + let serverResponse = {}; + + let expectedResponse = []; + + let result = spec.interpretResponse(serverResponse, bidRequest[0]); + expect(Object.keys(result)).to.deep.equal(Object.keys(expectedResponse)); + }); + }); +}); diff --git a/test/spec/modules/colossussspBidAdapter_spec.js b/test/spec/modules/colossussspBidAdapter_spec.js index df9bdcbd47b..a10a7590677 100644 --- a/test/spec/modules/colossussspBidAdapter_spec.js +++ b/test/spec/modules/colossussspBidAdapter_spec.js @@ -108,7 +108,7 @@ describe('ColossussspAdapter', function () { bid.userId.britepoolid = 'britepoolid123'; bid.userId.idl_env = 'idl_env123'; bid.userId.tdid = 'tdid123'; - bid.userId.id5id = 'id5id123' + bid.userId.id5id = { uid: 'id5id123' }; let serverRequest = spec.buildRequests([bid], bidderRequest); it('Returns valid data if array of bids is valid', function () { let data = serverRequest.data; diff --git a/test/spec/modules/concertAnalyticsAdapter_spec.js b/test/spec/modules/concertAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..b0aad2f3156 --- /dev/null +++ b/test/spec/modules/concertAnalyticsAdapter_spec.js @@ -0,0 +1,157 @@ +import concertAnalytics from 'modules/concertAnalyticsAdapter.js'; +import { expect } from 'chai'; +const sinon = require('sinon'); +let adapterManager = require('src/adapterManager').default; +let events = require('src/events'); +let constants = require('src/constants.json'); + +describe('ConcertAnalyticsAdapter', function() { + let sandbox; + let xhr; + let requests; + let clock; + let timestamp = 1896134400; + let auctionId = '9f894496-10fe-4652-863d-623462bf82b8'; + let timeout = 1000; + + before(function () { + sandbox = sinon.createSandbox(); + xhr = sandbox.useFakeXMLHttpRequest(); + requests = []; + + xhr.onCreate = function (request) { + requests.push(request); + }; + clock = sandbox.useFakeTimers(1896134400); + }); + + after(function () { + sandbox.restore(); + }); + + describe('track', function() { + beforeEach(function () { + sandbox.stub(events, 'getEvents').returns([]); + + adapterManager.enableAnalytics({ + provider: 'concert' + }); + }); + + afterEach(function () { + events.getEvents.restore(); + concertAnalytics.eventsStorage = []; + concertAnalytics.disableAnalytics(); + }); + + it('should catch all events', function() { + sandbox.spy(concertAnalytics, 'track'); + + fireBidEvents(events); + sandbox.assert.callCount(concertAnalytics.track, 5); + }); + + it('should report data for BID_RESPONSE, BID_WON events', function() { + fireBidEvents(events); + clock.tick(3000 + 1000); + + const eventsToReport = ['bidResponse', 'bidWon']; + for (var i = 0; i < concertAnalytics.eventsStorage.length; i++) { + expect(eventsToReport.indexOf(concertAnalytics.eventsStorage[i].event)).to.be.above(-1); + } + + for (var i = 0; i < eventsToReport.length; i++) { + expect(concertAnalytics.eventsStorage.some(function(event) { + return event.event === eventsToReport[i] + })).to.equal(true); + } + }); + + it('should report data in the shape expected by analytics endpoint', function() { + fireBidEvents(events); + clock.tick(3000 + 1000); + + const requiredFields = ['event', 'concert_rid', 'adId', 'auctionId', 'creativeId', 'position', 'url', 'cpm', 'width', 'height', 'timeToRespond']; + + for (var i = 0; i < requiredFields.length; i++) { + expect(concertAnalytics.eventsStorage[0]).to.have.property(requiredFields[i]); + } + }); + }); + + const adUnits = [{ + code: 'desktop_leaderboard_variable', + sizes: [[1030, 590]], + mediaTypes: { + banner: { + sizes: [[1030, 590]] + } + }, + bids: [ + { + bidder: 'concert', + params: { + partnerId: 'test_partner' + } + } + ] + }]; + + const bidResponse = { + 'bidderCode': 'concert', + 'width': 1030, + 'height': 590, + 'statusMessage': 'Bid available', + 'adId': '642f13fe18ab7dc', + 'requestId': '4062fba2e039919', + 'mediaType': 'banner', + 'source': 'client', + 'cpm': 6, + 'ad': '', + 'ttl': 360, + 'creativeId': '138308483085|62bac030-a5d3-11ea-b3be-55590c8153a5', + 'netRevenue': false, + 'currency': 'USD', + 'originalCpm': 6, + 'originalCurrency': 'USD', + 'auctionId': '9f894496-10fe-4652-863d-623462bf82b8', + 'responseTimestamp': 1591213790366, + 'requestTimestamp': 1591213790017, + 'bidder': 'concert', + 'adUnitCode': 'desktop_leaderboard_variable', + 'timeToRespond': 349, + 'status': 'rendered', + 'params': [ + { + 'partnerId': 'cst' + } + ] + } + + const bidWon = { + 'adId': '642f13fe18ab7dc', + 'mediaType': 'banner', + 'requestId': '4062fba2e039919', + 'cpm': 6, + 'creativeId': '138308483085|62bac030-a5d3-11ea-b3be-55590c8153a5', + 'currency': 'USD', + 'netRevenue': false, + 'ttl': 360, + 'auctionId': '9f894496-10fe-4652-863d-623462bf82b8', + 'statusMessage': 'Bid available', + 'responseTimestamp': 1591213790366, + 'requestTimestamp': 1591213790017, + 'bidder': 'concert', + 'adUnitCode': 'desktop_leaderboard_variable', + 'sizes': [[1030, 590]], + 'size': [1030, 590] + } + + function fireBidEvents(events) { + events.emit(constants.EVENTS.AUCTION_INIT, {timestamp, auctionId, timeout, adUnits}); + events.emit(constants.EVENTS.BID_REQUESTED, {bidder: 'concert'}); + events.emit(constants.EVENTS.BID_RESPONSE, bidResponse); + events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(constants.EVENTS.BID_WON, bidWon); + } +}); diff --git a/test/spec/modules/concertBidAdapter_spec.js b/test/spec/modules/concertBidAdapter_spec.js new file mode 100644 index 00000000000..df999f45df9 --- /dev/null +++ b/test/spec/modules/concertBidAdapter_spec.js @@ -0,0 +1,219 @@ +import { expect } from 'chai'; +import sinon from 'sinon'; +import { spec } from 'modules/concertBidAdapter.js'; +import { getStorageManager } from '../../../src/storageManager.js' + +describe('ConcertAdapter', function () { + let bidRequests; + let bidRequest; + let bidResponse; + + beforeEach(function () { + bidRequests = [ + { + bidder: 'concert', + params: { + partnerId: 'foo', + slotType: 'fizz' + }, + adUnitCode: 'desktop_leaderboard_variable', + bidId: 'foo', + transactionId: '', + sizes: [[1030, 590]] + } + ]; + + bidRequest = { + refererInfo: { + referer: 'https://www.google.com' + }, + uspConsent: '1YYY', + gdprConsent: {} + }; + + bidResponse = { + body: { + bids: [ + { + bidId: '16d2e73faea32d9', + cpm: '6', + width: '1030', + height: '590', + ad: '', + ttl: '360', + creativeId: '123349|a7d62700-a4bf-11ea-829f-ad3b0b7a9383', + netRevenue: false, + currency: 'USD' + } + ] + } + } + }); + + describe('spec.isBidRequestValid', function() { + it('should return when it recieved all the required params', function() { + const bid = bidRequests[0]; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when partner id is missing', function() { + const bid = { + bidder: 'concert', + params: {} + } + + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('spec.buildRequests', function() { + it('should build a payload object with the shape expected by server', function() { + const request = spec.buildRequests(bidRequests, bidRequest); + const payload = JSON.parse(request.data); + expect(payload).to.have.property('meta'); + expect(payload).to.have.property('slots'); + + const metaRequiredFields = ['prebidVersion', 'pageUrl', 'screen', 'debug', 'uid', 'optedOut', 'adapterVersion', 'uspConsent', 'gdprConsent']; + const slotsRequiredFields = ['name', 'bidId', 'transactionId', 'sizes', 'partnerId', 'slotType']; + + metaRequiredFields.forEach(function(field) { + expect(payload.meta).to.have.property(field); + }); + slotsRequiredFields.forEach(function(field) { + expect(payload.slots[0]).to.have.property(field); + }); + }); + + it('should not generate uid if the user has opted out', function() { + const storage = getStorageManager(); + storage.setDataInLocalStorage('c_nap', 'true'); + const request = spec.buildRequests(bidRequests, bidRequest); + const payload = JSON.parse(request.data); + + expect(payload.meta.uid).to.equal(false); + }); + + it('should generate uid if the user has not opted out', function() { + const storage = getStorageManager(); + storage.removeDataFromLocalStorage('c_nap'); + const request = spec.buildRequests(bidRequests, bidRequest); + const payload = JSON.parse(request.data); + + expect(payload.meta.uid).to.not.equal(false); + }); + + it('should grab uid from local storage if it exists', function() { + const storage = getStorageManager(); + storage.setDataInLocalStorage('c_uid', 'foo'); + storage.removeDataFromLocalStorage('c_nap'); + const request = spec.buildRequests(bidRequests, bidRequest); + const payload = JSON.parse(request.data); + + expect(payload.meta.uid).to.equal('foo'); + }); + }); + + describe('spec.interpretResponse', function() { + it('should return bids in the shape expected by prebid', function() { + const bids = spec.interpretResponse(bidResponse, bidRequest); + const requiredFields = ['requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', 'netRevenue', 'currency']; + + requiredFields.forEach(function(field) { + expect(bids[0]).to.have.property(field); + }); + }); + + it('should return empty bids if there is no response from server', function() { + const bids = spec.interpretResponse({ body: null }, bidRequest); + expect(bids).to.have.lengthOf(0); + }); + + it('should return empty bids if there are no bids from the server', function() { + const bids = spec.interpretResponse({ body: {bids: []} }, bidRequest); + expect(bids).to.have.lengthOf(0); + }); + }); + + describe('spec.getUserSyncs', function() { + it('should not register syncs when iframe is not enabled', function() { + const opts = { + iframeEnabled: false + } + const sync = spec.getUserSyncs(opts, [], bidRequest.gdprConsent, bidRequest.uspConsent); + expect(sync).to.have.lengthOf(0); + }); + + it('should not register syncs when the user has opted out', function() { + const opts = { + iframeEnabled: true + }; + const storage = getStorageManager(); + storage.setDataInLocalStorage('c_nap', 'true'); + + const sync = spec.getUserSyncs(opts, [], bidRequest.gdprConsent, bidRequest.uspConsent); + expect(sync).to.have.lengthOf(0); + }); + + it('should set gdprApplies flag to 1 if the user is in area where GDPR applies', function() { + const opts = { + iframeEnabled: true + }; + const storage = getStorageManager(); + storage.removeDataFromLocalStorage('c_nap'); + + bidRequest.gdprConsent = { + gdprApplies: true + }; + + const sync = spec.getUserSyncs(opts, [], bidRequest.gdprConsent, bidRequest.uspConsent); + expect(sync[0].url).to.have.string('gdpr_applies=1'); + }); + + it('should set gdprApplies flag to 1 if the user is in area where GDPR applies', function() { + const opts = { + iframeEnabled: true + }; + const storage = getStorageManager(); + storage.removeDataFromLocalStorage('c_nap'); + + bidRequest.gdprConsent = { + gdprApplies: false + }; + + const sync = spec.getUserSyncs(opts, [], bidRequest.gdprConsent, bidRequest.uspConsent); + expect(sync[0].url).to.have.string('gdpr_applies=0'); + }); + + it('should set gdpr consent param with the user\'s choices on consent', function() { + const opts = { + iframeEnabled: true + }; + const storage = getStorageManager(); + storage.removeDataFromLocalStorage('c_nap'); + + bidRequest.gdprConsent = { + gdprApplies: false, + consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==' + }; + + const sync = spec.getUserSyncs(opts, [], bidRequest.gdprConsent, bidRequest.uspConsent); + expect(sync[0].url).to.have.string('gdpr_consent=BOJ/P2HOJ/P2HABABMAAAAAZ+A=='); + }); + + it('should set ccpa consent param with the user\'s choices on consent', function() { + const opts = { + iframeEnabled: true + }; + const storage = getStorageManager(); + storage.removeDataFromLocalStorage('c_nap'); + + bidRequest.gdprConsent = { + gdprApplies: false, + uspConsent: '1YYY' + }; + + const sync = spec.getUserSyncs(opts, [], bidRequest.gdprConsent, bidRequest.uspConsent); + expect(sync[0].url).to.have.string('usp_consent=1YY'); + }); + }); +}); diff --git a/test/spec/modules/connectadBidAdapter_spec.js b/test/spec/modules/connectadBidAdapter_spec.js index 626018241c4..dbac3c0dc7c 100644 --- a/test/spec/modules/connectadBidAdapter_spec.js +++ b/test/spec/modules/connectadBidAdapter_spec.js @@ -14,7 +14,8 @@ describe('ConnectAd Adapter', function () { bidder: 'conntectad', params: { siteId: 123456, - networkId: 123456 + networkId: 123456, + bidfloor: 0.50 }, adUnitCode: '/19968336/header-bid-tag-1', mediaTypes: { @@ -46,8 +47,7 @@ describe('ConnectAd Adapter', function () { bidderRequestId: '1c56ad30b9b8ca8', transactionId: 'e76cbb58-f3e1-4ad9-9f4c-718c1919d0df', userId: { - tdid: '123456', - digitrustid: {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}} + tdid: '123456' } }]; @@ -84,7 +84,6 @@ describe('ConnectAd Adapter', function () { } }; const isValid = spec.isBidRequestValid(validBid); - expect(isValid).to.equal(true); }); @@ -154,6 +153,29 @@ describe('ConnectAd Adapter', function () { expect(requestparse.placements[0].networkId).to.equal(123456); }); + it('should process floors module if available', function() { + const floorInfo = { + currency: 'USD', + floor: 5.20 + }; + bidRequests[0].getFloor = () => floorInfo; + const request = spec.buildRequests(bidRequests, bidderRequest); + const requestparse = JSON.parse(request.data); + expect(requestparse.placements[0].bidfloor).to.equal(5.20); + }); + + it('should be bidfloor if no floormodule is available', function() { + const request = spec.buildRequests(bidRequests, bidderRequest); + const requestparse = JSON.parse(request.data); + expect(requestparse.placements[0].bidfloor).to.equal(0.50); + }); + + it('should have 0 bidfloor value', function() { + const request = spec.buildRequests(bidRequestsUserIds, bidderRequest); + const requestparse = JSON.parse(request.data); + expect(requestparse.placements[0].bidfloor).to.equal(0); + }); + it('should contain gdpr info', function () { const request = spec.buildRequests(bidRequests, bidderRequest); const requestparse = JSON.parse(request.data); @@ -227,7 +249,6 @@ describe('ConnectAd Adapter', function () { const requestparse = JSON.parse(request.data); expect(requestparse.user.ext.eids).to.be.an('array'); expect(requestparse.user.ext.eids[0].uids[0].id).to.equal('123456'); - expect(requestparse.user.ext.digitrust.id).to.equal('DTID'); }); it('should add referer info', function () { diff --git a/test/spec/modules/consentManagementUsp_spec.js b/test/spec/modules/consentManagementUsp_spec.js index 2e8d7db92b5..ee4140afa10 100644 --- a/test/spec/modules/consentManagementUsp_spec.js +++ b/test/spec/modules/consentManagementUsp_spec.js @@ -185,7 +185,10 @@ describe('consentManagement', function () { resetConsentData(); }); - it('should bypass CMP and simply use previously stored consentData', function () { + // from prebid 4425 - "the USP (CCPA) api function __uspapi() always responds synchronously, whether or not privacy data is available, while the GDPR CMP may respond asynchronously + // Because the USP API does not wait for a user response, if it was not successfully obtained before the first auction, we should try again to retrieve privacy data before each subsequent auction. + + it('should not bypass CMP and simply use previously stored consentData', function () { let testConsentData = { uspString: '1YY' }; @@ -208,7 +211,7 @@ describe('consentManagement', function () { let consent = uspDataHandler.getConsentData(); expect(didHookReturn).to.be.true; expect(consent).to.equal(testConsentData.uspString); - sinon.assert.notCalled(uspStub); + sinon.assert.called(uspStub); }); }); diff --git a/test/spec/modules/consentManagement_spec.js b/test/spec/modules/consentManagement_spec.js index fb33094e151..deaacbc5a28 100644 --- a/test/spec/modules/consentManagement_spec.js +++ b/test/spec/modules/consentManagement_spec.js @@ -24,9 +24,8 @@ describe('consentManagement', function () { setConsentConfig({}); expect(userCMP).to.be.equal('iab'); expect(consentTimeout).to.be.equal(10000); - expect(allowAuction).to.be.true; expect(gdprScope).to.be.equal(false); - sinon.assert.callCount(utils.logInfo, 4); + sinon.assert.callCount(utils.logInfo, 3); }); it('should exit consent manager if config is not an object', function () { @@ -58,7 +57,10 @@ describe('consentManagement', function () { setConsentConfig(allConfig); expect(userCMP).to.be.equal('iab'); expect(consentTimeout).to.be.equal(7500); - expect(allowAuction).to.be.false; + expect(allowAuction).to.deep.equal({ + value: false, + definedInConfig: true + }); expect(gdprScope).to.be.true; }); @@ -110,7 +112,10 @@ describe('consentManagement', function () { expect(userCMP).to.be.equal('iab'); expect(consentTimeout).to.be.equal(3333); - expect(allowAuction).to.be.equal(false); + expect(allowAuction).to.deep.equal({ + value: false, + definedInConfig: true + }); expect(gdprScope).to.be.equal(false); }); }); @@ -164,7 +169,10 @@ describe('consentManagement', function () { setConsentConfig(staticConfig); expect(userCMP).to.be.equal('static'); expect(consentTimeout).to.be.equal(0); // should always return without a timeout when config is used - expect(allowAuction).to.be.false; + expect(allowAuction).to.deep.equal({ + value: false, + definedInConfig: true + }); expect(staticConsentData).to.be.equal(staticConfig.consentData); }); @@ -244,7 +252,10 @@ describe('consentManagement', function () { setConsentConfig(staticConfig); expect(userCMP).to.be.equal('static'); expect(consentTimeout).to.be.equal(0); // should always return without a timeout when config is used - expect(allowAuction).to.be.false; + expect(allowAuction).to.deep.equal({ + value: false, + definedInConfig: true + }); expect(gdprScope).to.be.equal(false); expect(staticConsentData).to.be.equal(staticConfig.consentData); }); @@ -423,7 +434,6 @@ describe('consentManagement', function () { setConsentConfig(goodConfigWithAllowAuction); requestBidsHook(() => { let consent = gdprDataHandler.getConsentData(); - sinon.assert.notCalled(utils.logWarn); sinon.assert.notCalled(utils.logError); expect(consent.consentString).to.equal(tarConsentString); expect(consent.gdprApplies).to.be.true; @@ -626,7 +636,6 @@ describe('consentManagement', function () { didHookReturn = true; }, {}); let consent = gdprDataHandler.getConsentData(); - sinon.assert.notCalled(utils.logWarn); sinon.assert.notCalled(utils.logError); expect(didHookReturn).to.be.true; expect(consent.consentString).to.equal(testConsentData.tcString); @@ -634,7 +643,33 @@ describe('consentManagement', function () { expect(consent.apiVersion).to.equal(2); }); - it('throws an error when processCmpData check failed while config had allowAuction set to false', function () { + it('performs lookup check and stores consentData for a valid existing user with additional consent', function () { + let testConsentData = { + tcString: 'abc12345234', + addtlConsent: 'superduperstring', + gdprApplies: true, + purposeOneTreatment: false, + eventStatus: 'tcloaded' + }; + cmpStub = sinon.stub(window, '__tcfapi').callsFake((...args) => { + args[2](testConsentData, true); + }); + + setConsentConfig(goodConfigWithAllowAuction); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consent = gdprDataHandler.getConsentData(); + sinon.assert.notCalled(utils.logError); + expect(didHookReturn).to.be.true; + expect(consent.consentString).to.equal(testConsentData.tcString); + expect(consent.addtlConsent).to.equal(testConsentData.addtlConsent); + expect(consent.gdprApplies).to.be.true; + expect(consent.apiVersion).to.equal(2); + }); + + it('throws an error when processCmpData check fails + does not call requestBids callbcack even when allowAuction is true', function () { let testConsentData = {}; let bidsBackHandlerReturn = false; @@ -642,7 +677,7 @@ describe('consentManagement', function () { args[2](testConsentData); }); - setConsentConfig(goodConfigWithCancelAuction); + setConsentConfig(goodConfigWithAllowAuction); requestBidsHook(() => { didHookReturn = true; @@ -650,29 +685,37 @@ describe('consentManagement', function () { let consent = gdprDataHandler.getConsentData(); sinon.assert.calledOnce(utils.logError); + sinon.assert.notCalled(utils.logWarn); expect(didHookReturn).to.be.false; expect(bidsBackHandlerReturn).to.be.true; expect(consent).to.be.null; }); - it('throws a warning + stores consentData + calls callback when processCmpData check failed while config had allowAuction set to true', function () { - let testConsentData = {}; - + it('It still considers it a valid cmp response if gdprApplies is not a boolean', function () { + // gdprApplies is undefined, should just still store consent response but use whatever defaultGdprScope was + let testConsentData = { + tcString: 'abc12345234', + purposeOneTreatment: false, + eventStatus: 'tcloaded' + }; cmpStub = sinon.stub(window, '__tcfapi').callsFake((...args) => { - args[2](testConsentData); + args[2](testConsentData, true); }); - setConsentConfig(goodConfigWithAllowAuction); + setConsentConfig({ + cmpApi: 'iab', + timeout: 7500, + defaultGdprScope: true + }); requestBidsHook(() => { didHookReturn = true; }, {}); let consent = gdprDataHandler.getConsentData(); - - sinon.assert.calledOnce(utils.logWarn); + sinon.assert.notCalled(utils.logError); expect(didHookReturn).to.be.true; - expect(consent.consentString).to.be.undefined; - expect(consent.gdprApplies).to.be.false; + expect(consent.consentString).to.equal(testConsentData.tcString); + expect(consent.gdprApplies).to.be.true; expect(consent.apiVersion).to.equal(2); }); }); diff --git a/test/spec/modules/conversantBidAdapter_spec.js b/test/spec/modules/conversantBidAdapter_spec.js index 7c6d6e5dd6c..d802cd288ef 100644 --- a/test/spec/modules/conversantBidAdapter_spec.js +++ b/test/spec/modules/conversantBidAdapter_spec.js @@ -210,7 +210,7 @@ describe('Conversant adapter tests', function() { }; const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.method).to.equal('POST'); - expect(request.url).to.equal('https://web.hb.ad.cpe.dotomi.com/s2s/header/24'); + expect(request.url).to.equal('https://web.hb.ad.cpe.dotomi.com/cvx/client/hb/ortb/25'); const payload = request.data; expect(payload).to.have.property('id', 'req000'); diff --git a/test/spec/modules/cpmstarBidAdapter_spec.js b/test/spec/modules/cpmstarBidAdapter_spec.js old mode 100755 new mode 100644 index 9e794d3e098..285fca9690a --- a/test/spec/modules/cpmstarBidAdapter_spec.js +++ b/test/spec/modules/cpmstarBidAdapter_spec.js @@ -1,6 +1,42 @@ import { expect } from 'chai'; import { spec } from 'modules/cpmstarBidAdapter.js'; import { deepClone } from 'src/utils.js'; +import { config } from 'src/config.js'; + +const valid_bid_requests = [{ + 'bidder': 'cpmstar', + 'params': { + 'placementId': '57' + }, + 'sizes': [[300, 250]], + 'bidId': 'bidId' +}]; + +const bidderRequest = { + refererInfo: { + referer: 'referer', + reachedTop: false, + } +}; + +const serverResponse = { + body: [{ + creatives: [{ + cpm: 1, + width: 0, + height: 0, + currency: 'USD', + netRevenue: true, + ttl: 1, + creativeid: '1234', + requestid: '11123', + code: 'no idea', + media: 'banner', + } + ], + syncs: [{ type: 'image', url: 'https://server.cpmstar.com/pixel.aspx' }] + }] +}; describe('Cpmstar Bid Adapter', function () { describe('isBidRequestValid', function () { @@ -15,45 +51,32 @@ describe('Cpmstar Bid Adapter', function () { expect(spec.isBidRequestValid(bid)).to.equal(false); }) - it('should return a valid player size', function() { - var bid = { mediaTypes: { - video: { - playerSize: [[960, 540]] + it('should return a valid player size', function () { + var bid = { + mediaTypes: { + video: { + playerSize: [[960, 540]] + } } - }} + } expect(spec.getPlayerSize(bid)[0]).to.equal(960); expect(spec.getPlayerSize(bid)[1]).to.equal(540); }) - it('should return a default player size', function() { - var bid = { mediaTypes: { - video: { - playerSize: null + it('should return a default player size', function () { + var bid = { + mediaTypes: { + video: { + playerSize: null + } } - }} + } expect(spec.getPlayerSize(bid)[0]).to.equal(640); expect(spec.getPlayerSize(bid)[1]).to.equal(440); }) }); describe('buildRequests', function () { - const valid_bid_requests = [{ - 'bidder': 'cpmstar', - 'params': { - 'placementId': '57' - }, - 'sizes': [[300, 250]], - 'bidId': 'bidId' - }]; - - const bidderRequest = { - refererInfo: { - referer: 'referer', - reachedTop: false, - } - - }; - it('should produce a valid production request', function () { var requests = spec.buildRequests(valid_bid_requests, bidderRequest); expect(requests[0]).to.have.property('method'); @@ -79,7 +102,55 @@ describe('Cpmstar Bid Adapter', function () { expect(requests[0]).to.have.property('bidRequest'); expect(requests[0].url).to.include('https://dev.server.cpmstar.com/view.aspx'); }); - }) + it('should produce a request with support for GDPR', function () { + var gdpr_bidderRequest = deepClone(bidderRequest); + gdpr_bidderRequest.gdprConsent = { + consentString: 'consentString', + gdprApplies: true + }; + var requests = spec.buildRequests(valid_bid_requests, gdpr_bidderRequest); + expect(requests[0]).to.have.property('url'); + expect(requests[0].url).to.include('gdpr_consent=consentString'); + expect(requests[0].url).to.include('gdpr=1'); + }); + it('should produce a request with support for USP', function () { + var usp_bidderRequest = deepClone(bidderRequest); + usp_bidderRequest.uspConsent = '1YYY'; + var requests = spec.buildRequests(valid_bid_requests, usp_bidderRequest); + expect(requests[0]).to.have.property('url'); + expect(requests[0].url).to.include('us_privacy=1YYY'); + }); + it('should produce a request with support for COPPA', function () { + sinon.stub(config, 'getConfig').withArgs('coppa').returns(true); + var requests = spec.buildRequests(valid_bid_requests, bidderRequest); + config.getConfig.restore(); + expect(requests[0]).to.have.property('url'); + expect(requests[0].url).to.include('tfcd=1'); + }); + }); + + it('should produce a request with support for OpenRTB SupplyChain', function () { + var reqs = deepClone(valid_bid_requests); + reqs[0].schain = { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'exchange1.com', + 'sid': '1234', + 'hp': 1 + }, + { + 'asi': 'exchange2.com', + 'sid': 'abcd', + 'hp': 1 + } + ] + }; + var requests = spec.buildRequests(reqs, bidderRequest); + expect(requests[0]).to.have.property('url'); + expect(requests[0].url).to.include('&schain=1.0,1!exchange1.com,1234,1,,,!exchange2.com,abcd,1,,,'); + }); describe('interpretResponse', function () { const request = { @@ -87,23 +158,6 @@ describe('Cpmstar Bid Adapter', function () { mediaType: 'BANNER' } }; - const serverResponse = { - body: [{ - creatives: [{ - cpm: 1, - width: 0, - height: 0, - currency: 'USD', - netRevenue: true, - ttl: 1, - creativeid: '1234', - requestid: '11123', - code: 'no idea', - media: 'banner', - } - ], - }] - }; it('should return a valid bidresponse array', function () { var r = spec.interpretResponse(serverResponse, request) @@ -155,4 +209,23 @@ describe('Cpmstar Bid Adapter', function () { expect(spec.interpretResponse(dealServer, request)[0].dealId).to.equal('deal'); }); }); + + describe('getUserSyncs', function () { + var sres = [deepClone(serverResponse)]; + + it('should return a valid pixel sync', function () { + var syncs = spec.getUserSyncs({ pixelEnabled: true }, sres); + expect(syncs.length).equal(1); + expect(syncs[0].type).equal('image'); + expect(syncs[0].url).equal('https://server.cpmstar.com/pixel.aspx'); + }); + + it('should return a valid iframe sync', function () { + sres[0].body[0].syncs[0].type = 'iframe'; + var syncs = spec.getUserSyncs({ iframeEnabled: true }, sres); + expect(syncs.length).equal(1); + expect(syncs[0].type).equal('iframe'); + expect(syncs[0].url).equal('https://server.cpmstar.com/pixel.aspx'); + }); + }); }); diff --git a/test/spec/modules/craftBidAdapter_spec.js b/test/spec/modules/craftBidAdapter_spec.js new file mode 100644 index 00000000000..ef7dd7c3232 --- /dev/null +++ b/test/spec/modules/craftBidAdapter_spec.js @@ -0,0 +1,152 @@ +import {expect} from 'chai'; +import {spec} from 'modules/craftBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; +import {config} from 'src/config.js'; + +describe('craftAdapter', function () { + let adapter = newBidder(spec); + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + before(function() { + this.windowContext = window.context; + window.context = null; + }); + + after(function() { + window.context = this.windowContext; + }); + let bid = { + bidder: 'craft', + params: { + sitekey: 'craft-prebid-example', + placementId: '1234abcd' + }, + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when params.sitekey not found', function () { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + placementId: '1234abcd' + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when params.placementId not found', function () { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + sitekey: 'craft-prebid-example' + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when AMP cotext found', function () { + window.context = { + pageViewId: 'xxx' + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + let bidRequests = [{ + bidder: 'craft', + params: { + 'sitekey': 'craft-prebid-example', + 'placementId': '1234abcd' + }, + adUnitCode: '/21998384947/prebid-example', + sizes: [[300, 250]], + bidId: '0396fae4eb5f47', + bidderRequestId: '4a859978b5d4bd', + auctionId: '8720f980-4639-4150-923a-e96da2f1de36', + transactionId: 'e0c52da2-c008-491c-a910-c6765d948700', + }]; + let bidderRequest = { + refererInfo: { + referer: 'https://www.gacraft.jp/publish/craft-prebid-example.html' + } + }; + it('sends bid request to ENDPOINT via POST', function () { + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal('https://gacraft.jp/prebid-v3'); + let data = JSON.parse(request.data); + expect(data.tags).to.deep.equals([{ + sitekey: 'craft-prebid-example', + placementId: '1234abcd', + uid: null, + sizes: [[300, 250]], + primary_size: [300, 250], + uuid: '0396fae4eb5f47' + }]); + expect(data.referrer_detection).to.deep.equals({ + rd_ref: 'https://www.gacraft.jp/publish/craft-prebid-example.html' + }); + }); + }); + + describe('interpretResponse', function() { + let serverResponse = { + body: { + tags: [{ + uuid: '0396fae4eb5f47', + bid_key: '72038482-c4c3-4055-9e7e-0579585bb421', + won_url: 'https://www.gacraft.jp/publish/won', + ads: [{ + content_source: 'rtb', + ad_type: 'banner', + creative_id: 9999, + cpm: 10.01, + deal_id: '8DEF60EFDFB5', + rtb: { + banner: { + content: '
', + width: 300, + height: 250 + }, + } + }] + }], + } + }; + let bidderRequest = { + bids: [{ + bidId: '0396fae4eb5f47', + adUnitCode: 'craft-prebid-example' + }] + }; + it('should get correct bid response', function() { + let bids = spec.interpretResponse(serverResponse, {bidderRequest: bidderRequest}); + expect(bids).to.have.lengthOf(1); + expect(bids[0]).to.deep.equals({ + _adUnitCode: 'craft-prebid-example', + _bidKey: '72038482-c4c3-4055-9e7e-0579585bb421', + _prebidWon: 'https://www.gacraft.jp/publish/won', + ad: '', + cpm: 10.01, + creativeId: 9999, + currency: 'JPY', + dealId: '8DEF60EFDFB5', + height: 250, + mediaType: 'banner', + meta: null, + netRevenue: false, + requestId: '0396fae4eb5f47', + ttl: 360, + width: 300, + }); + }); + }); +}); diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index 6ab0159e901..c5068d11d31 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -1173,7 +1173,6 @@ describe('The Criteo bidding adapter', function () { utilsMock.expects('logInfo').withExactArgs('Using Criteo FastBid').once(); utilsMock.expects('logWarn').withExactArgs('No hash found in FastBid').never(); utilsMock.expects('logWarn').withExactArgs('Invalid Criteo FastBid found').never(); - utilsMock.expects('insertElement').once(); tryGetCriteoFastBid(); @@ -1419,14 +1418,14 @@ describe('The Criteo bidding adapter', function () { }); it('should forward bid to pubtag when calling onTimeout', () => { - const timeoutData = { auctionId: 123 }; + const timeoutData = [{ auctionId: 123 }]; const adapter = { handleBidTimeout: function() {} }; const adapterMock = sinon.mock(adapter); adapterMock.expects('handleBidTimeout').once(); const prebidAdapter = { GetAdapter: function() {} }; const prebidAdapterMock = sinon.mock(prebidAdapter); - prebidAdapterMock.expects('GetAdapter').withExactArgs(timeoutData.auctionId).once().returns(adapter); + prebidAdapterMock.expects('GetAdapter').withExactArgs(timeoutData[0].auctionId).once().returns(adapter); global.Criteo = { PubTag: { diff --git a/test/spec/modules/dailyhuntBidAdapter_spec.js b/test/spec/modules/dailyhuntBidAdapter_spec.js index de384d0a1f7..d571150dbee 100644 --- a/test/spec/modules/dailyhuntBidAdapter_spec.js +++ b/test/spec/modules/dailyhuntBidAdapter_spec.js @@ -1,9 +1,8 @@ import { expect } from 'chai'; import { spec } from 'modules/dailyhuntBidAdapter.js'; -const PROD_PREBID_ENDPOINT_URL = 'https://money.dailyhunt.in/openrtb2/auction'; - -const PROD_ENDPOINT_URL = 'https://money.dailyhunt.in/openx/ads/index.php'; +const PROD_PREBID_ENDPOINT_URL = 'https://pbs.dailyhunt.in/openrtb2/auction?partner=dailyhunt'; +const PROD_PREBID_TEST_ENDPOINT_URL = 'https://qa-pbs-van.dailyhunt.in/openrtb2/auction?partner=dailyhunt'; const _encodeURIComponent = function (a) { if (!a) { return } @@ -17,7 +16,9 @@ describe('DailyhuntAdapter', function () { let bid = { 'bidder': 'dailyhunt', 'params': { - partnerId: 'pb-partnerId' + placement_id: 1, + publisher_id: 1, + partner_name: 'dailyhunt' } }; @@ -32,20 +33,92 @@ describe('DailyhuntAdapter', function () { expect(spec.isBidRequestValid(bid)).to.equal(false); }); }); - - describe('buildRequests', function () { + describe('buildRequests', function() { let bidRequests = [ { - 'bidder': 'dailyhunt', - 'params': { - 'placementId': '10433394' + bidder: 'dailyhunt', + params: { + placement_id: 1, + publisher_id: 1, + partner_name: 'dailyhunt', + bidfloor: 0.1, + device: { + ip: '47.9.247.217' + }, + site: { + cat: ['1', '2', '3'] + } }, - 'adUnitCode': 'adunit-code', - 'sizes': [[300, 50]], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - 'transactionId': '04f2659e-c005-4eb1-a57c-fa93145e3843' + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + adUnitCode: 'adunit-code', + sizes: [[300, 50]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + transactionId: '04f2659e-c005-4eb1-a57c-fa93145e3843' + } + ]; + let nativeBidRequests = [ + { + bidder: 'dailyhunt', + params: { + placement_id: 1, + publisher_id: 1, + partner_name: 'dailyhunt', + }, + nativeParams: { + title: { + required: true, + len: 80 + }, + image: { + required: true, + sizes: [150, 50] + }, + }, + mediaTypes: { + native: { + title: { + required: true + }, + } + }, + adUnitCode: 'adunit-code', + sizes: [[300, 250], [300, 50]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + transactionId: '04f2659e-c005-4eb1-a57c-fa93145e3843' + } + ]; + let videoBidRequests = [ + { + bidder: 'dailyhunt', + params: { + placement_id: 1, + publisher_id: 1, + partner_name: 'dailyhunt' + }, + nativeParams: { + video: { + context: 'instream' + } + }, + mediaTypes: { + video: { + context: 'instream' + } + }, + adUnitCode: 'adunit-code', + sizes: [[300, 250], [300, 50]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + transactionId: '04f2659e-c005-4eb1-a57c-fa93145e3843' } ]; let bidderRequest = { @@ -61,29 +134,6 @@ describe('DailyhuntAdapter', function () { 'referer': 'http://m.dailyhunt.in/' } }; - - let nativeBidRequests = [ - { - 'bidder': 'dailyhunt', - 'params': { - 'placementId': '10433394' - }, - nativeParams: { - image: { - required: true, - }, - title: { - required: true, - }, - }, - 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250], [300, 50]], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - 'transactionId': '04f2659e-c005-4eb1-a57c-fa93145e3843' - } - ]; let nativeBidderRequest = { 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', @@ -97,6 +147,19 @@ describe('DailyhuntAdapter', function () { 'referer': 'http://m.dailyhunt.in/' } }; + let videoBidderRequest = { + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'bidderCode': 'dailyhunt', + 'bids': [ + { + ...videoBidRequests[0] + } + ], + 'refererInfo': { + 'referer': 'http://m.dailyhunt.in/' + } + }; it('sends display bid request to ENDPOINT via POST', function () { const request = spec.buildRequests(bidRequests, bidderRequest)[0]; @@ -104,186 +167,234 @@ describe('DailyhuntAdapter', function () { expect(request.method).to.equal('POST'); }); - it('sends native bid request to ENDPOINT via GET', function () { + it('sends native bid request to ENDPOINT via POST', function () { const request = spec.buildRequests(nativeBidRequests, nativeBidderRequest)[0]; - expect(request.url).to.equal(PROD_ENDPOINT_URL); - expect(request.method).to.equal('GET'); + expect(request.url).to.equal(PROD_PREBID_ENDPOINT_URL); + expect(request.method).to.equal('POST'); }); - }) + it('sends video bid request to ENDPOINT via POST', function () { + const request = spec.buildRequests(videoBidRequests, videoBidderRequest)[0]; + expect(request.url).to.equal(PROD_PREBID_ENDPOINT_URL); + expect(request.method).to.equal('POST'); + }); + }); describe('interpretResponse', function () { - let nativeResponse = [ - [ + let bidResponses = { + id: 'da32def7-6779-403c-ada7-0b201dbc9744', + seatbid: [ { - 'ad': { - 'requestId': '12345', - 'type': 'native-banner', - 'aduid': 'notId=ad-123679', - 'srcUrlExpiry': '60', - 'position': 'web', - 'width': 300, - 'height': 250, - 'card-position': 6, - 'positionWithTicker': 6, - 'min-ad-distance': 9, - 'banner-fill': 'fill-width', - 'bannerid': '70459', - 'adTemplate': 'H', - 'showOnlyImage': 'false', - 'id': '4210005ddbed0f096078.05613283', - 'span': 60, - 'useInternalBrowser': 'false', - 'useWideViewPort': 'true', - 'adCacheGood': '1', - 'adCacheAverage': '1', - 'adCacheSlow': '1', - 'allowDelayedAdInsert': 'true', - 'adGroupId': '4210005ddbed0f0982f4.86287578', - 'adContext': null, - 'showPlayIcon': 'false', - 'showBorder': 'false', - 'adid': '123679', - 'typeId': '3', - 'subTypeId': '0', - 'orderId': '1', - 'data-subSlot': 'web-3', - 'data-partner': 'DH', - 'data-origin': 'pbs', - 'pbAdU': '0', - 'price': '1.4', - 'beaconUrl': 'beacon-url', - 'landingUrl': null, - 'content': { - 'bg-color': '#ffffff', - 'bg-color-night': '#000000', - 'language': 'en', - 'sourceAlphabet': 'A', - 'iconLink': 'icon-link', - 'itemTag': { - 'color': '#0889ac', - 'color-night': '#a5a5a5', - 'data': 'Promoted' - }, - 'itemTitle': { - 'color': '#000000', - 'color-night': '#ffffff', - 'data': 'PREBID TEST' - }, - 'itemSubtitle1': { - 'color': '#000000', - 'color-night': '#ffffff', - 'data': 'Lorem Ipsum lorem ipsum' - }, - 'itemSubtitle2': { - 'color': '#4caf79', - 'color-night': '#ffffff', - 'data': 'CLICK ME' + bid: [ + { + id: 'id1', + impid: 'banner-impid', + price: 1.4, + adm: 'adm', + adid: '66658', + crid: 'asd5ddbf014cac993.66466212', + dealid: 'asd5ddbf014cac993.66466212', + w: 300, + h: 250, + nurl: 'winUrl', + ext: { + prebid: { + type: 'banner' + } } }, - 'action': 'action-url', - 'shareability': null - } - } - ] - ]; - - let bannerResponse = { - 'id': 'da32def7-6779-403c-ada7-0b201dbc9744', - 'seatbid': [ - { - 'bid': [ { - 'id': '3db3773286ee59', - 'impid': '1', - 'price': 0.14, - 'adm': "\r\n\r\n\r\n\t\r\n\tWidgets Magazine\r\n\t\r\n\t\r\n\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n
\r\n\r\n
\r\n\r\n\r\n", - 'adid': '66658', - 'crid': 'asd5ddbf014cac993.66466212', - 'dealid': 'asd5ddbf014cac993.66466212', - 'w': 300, - 'h': 250, - 'ext': { - 'prebid': { - 'type': 'banner' + id: '5caccc1f-94a6-4230-a1f9-6186ee65da99', + impid: 'video-impid', + price: 1.4, + nurl: 'winUrl', + adm: 'adm', + adid: '980', + crid: '2394', + w: 300, + h: 250, + ext: { + prebid: { + 'type': 'video' + }, + bidder: { + cacheKey: 'cache_key', + vastUrl: 'vastUrl' } } - } + }, + { + id: '74973faf-cce7-4eff-abd0-b59b8e91ca87', + impid: 'native-impid', + price: 50, + nurl: 'winUrl', + adm: '{"native":{"link":{"url":"url","clicktrackers":[]},"assets":[{"id":1,"required":1,"img":{},"video":{},"data":{},"title":{"text":"TITLE"},"link":{}},{"id":1,"required":1,"img":{},"video":{},"data":{"type":2,"value":"Lorem Ipsum Lorem Ipsum Lorem Ipsum."},"title":{},"link":{}},{"id":1,"required":1,"img":{},"video":{},"data":{"type":12,"value":"Install Here"},"title":{},"link":{}},{"id":1,"required":1,"img":{"type":3,"url":"urk","w":990,"h":505},"video":{},"data":{},"title":{},"link":{}}],"imptrackers":[]}}', + adid: '968', + crid: '2370', + w: 300, + h: 250, + ext: { + prebid: { + type: 'native' + }, + bidder: null + } + }, + { + id: '5caccc1f-94a6-4230-a1f9-6186ee65da99', + impid: 'video-outstream-impid', + price: 1.4, + nurl: 'winUrl', + adm: 'adm', + adid: '980', + crid: '2394', + w: 300, + h: 250, + ext: { + prebid: { + 'type': 'video' + }, + bidder: { + cacheKey: 'cache_key', + vastUrl: 'vastUrl' + } + } + }, ], - 'seat': 'dailyhunt' + seat: 'dailyhunt' } ], - 'ext': { - 'responsetimemillis': { - 'dailyhunt': 119 + ext: { + responsetimemillis: { + dailyhunt: 119 } } }; - it('should get correct native bid response', function () { + it('should get correct bid response', function () { let expectedResponse = [ { - requestId: '12345', - cpm: '10', - creativeId: '70459', + requestId: '1', + cpm: 1.4, + creativeId: 'asd5ddbf014cac993.66466212', + width: 300, + height: 250, + ttl: 360, + netRevenue: true, + currency: 'USD', + ad: 'adm', + mediaType: 'banner', + winUrl: 'winUrl' + }, + { + requestId: '2', + cpm: 1.4, + creativeId: '2394', + width: 300, + height: 250, + ttl: 360, + netRevenue: true, currency: 'USD', + mediaType: 'video', + winUrl: 'winUrl', + videoCacheKey: 'cache_key', + vastUrl: 'vastUrl', + }, + { + requestId: '3', + cpm: 1.4, + creativeId: '2370', + width: 300, + height: 250, ttl: 360, netRevenue: true, + currency: 'USD', mediaType: 'native', + winUrl: 'winUrl', native: { - title: 'PREBID TEST', - body: 'Lorem Ipsum lorem ipsum', - body2: 'Lorem Ipsum lorem ipsum', - cta: 'CLICK ME', - clickUrl: _encodeURIComponent('action-url'), - impressionTrackers: [], + clickUrl: 'https%3A%2F%2Fmontu1996.github.io%2F', clickTrackers: [], + impressionTrackers: [], + javascriptTrackers: [], + title: 'TITLE', + body: 'Lorem Ipsum Lorem Ipsum Lorem Ipsum.', + cta: 'Install Here', image: { - url: 'icon-link', - height: 250, - width: 300 - }, - icon: { - url: 'icon-link', - height: 300, - width: 250 + url: 'url', + height: 505, + width: 990 } } - } - ]; - let bidderRequest = { - bids: [{ - bidId: '3db3773286ee59', - adUnitCode: 'code', - 'requestId': '12345' - }] - } - let result = spec.interpretResponse({ body: nativeResponse }, { bidderRequest }); - expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); - }); - - it('should get correct banner bid response', function () { - let expectedResponse = [ + }, { - requestId: '12345', - cpm: 0.14, - creativeId: 'asd5ddbf014cac993.66466212', + requestId: '4', + cpm: 1.4, + creativeId: '2394', width: 300, height: 250, ttl: 360, netRevenue: true, currency: 'USD', - ad: "\r\n\r\n\r\n\t\r\n\tWidgets Magazine\r\n\t\r\n\t\r\n\t\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n
\r\n\r\n
\r\n\r\n\r\n", - } + mediaType: 'video', + winUrl: 'winUrl', + vastXml: 'adm', + }, ]; let bidderRequest = { - bids: [{ - bidId: '3db3773286ee59', - adUnitCode: 'code', - 'requestId': '12345' - }] + bids: [ + { + bidId: 'banner-impid', + adUnitCode: 'code1', + requestId: '1' + }, + { + bidId: 'video-impid', + adUnitCode: 'code2', + requestId: '2', + mediaTypes: { + video: { + context: 'instream' + } + } + }, + { + bidId: 'native-impid', + adUnitCode: 'code3', + requestId: '3' + }, + { + bidId: 'video-outstream-impid', + adUnitCode: 'code4', + requestId: '4', + mediaTypes: { + video: { + context: 'outstream' + } + } + }, + ] } - let result = spec.interpretResponse({ body: bannerResponse }, bidderRequest); - expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + let result = spec.interpretResponse({ body: bidResponses }, bidderRequest); + result.forEach((r, i) => { + expect(Object.keys(r)).to.have.members(Object.keys(expectedResponse[i])); + }); + }); + }) + describe('onBidWon', function () { + it('should hit win url when bid won', function () { + let bid = { + requestId: '1', + cpm: 1.4, + creativeId: 'asd5ddbf014cac993.66466212', + width: 300, + height: 250, + ttl: 360, + netRevenue: true, + currency: 'USD', + ad: 'adm', + mediaType: 'banner', + winUrl: 'winUrl' + }; + expect(spec.onBidWon(bid)).to.equal(undefined); }); }) }) diff --git a/test/spec/modules/decenteradsBidAdapter_spec.js b/test/spec/modules/decenteradsBidAdapter_spec.js new file mode 100644 index 00000000000..257094cae3a --- /dev/null +++ b/test/spec/modules/decenteradsBidAdapter_spec.js @@ -0,0 +1,207 @@ +import { expect } from 'chai' +import { spec } from '../../../modules/decenteradsBidAdapter.js' +import { deepStrictEqual, notEqual, ok, strictEqual } from 'assert' + +describe('DecenteradsAdapter', () => { + const bid = { + bidId: '9ec5b177515ee2e5', + bidder: 'decenterads', + params: { + placementId: 0, + traffic: 'banner' + } + } + + describe('isBidRequestValid', () => { + it('Should return true if there are bidId, params and placementId parameters present', () => { + strictEqual(true, spec.isBidRequestValid(bid)) + }) + + it('Should return false if at least one of parameters is not present', () => { + const b = { ...bid } + delete b.params.placementId + strictEqual(false, spec.isBidRequestValid(b)) + }) + }) + + describe('buildRequests', () => { + const serverRequest = spec.buildRequests([bid]) + + it('Creates a ServerRequest object with method, URL and data', () => { + ok(serverRequest) + ok(serverRequest.method) + ok(serverRequest.url) + ok(serverRequest.data) + }) + + it('Returns POST method', () => { + strictEqual('POST', serverRequest.method) + }) + + it('Returns valid URL', () => { + strictEqual('https://supply.decenterads.com/?c=o&m=multi', serverRequest.url) + }) + + it('Returns valid data if array of bids is valid', () => { + const { data } = serverRequest + strictEqual('object', typeof data) + deepStrictEqual(['deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements'], Object.keys(data)) + strictEqual('number', typeof data.deviceWidth) + strictEqual('number', typeof data.deviceHeight) + strictEqual('string', typeof data.language) + strictEqual('string', typeof data.host) + strictEqual('string', typeof data.page) + notEqual(-1, [0, 1].indexOf(data.secure)) + + const placement = data.placements[0] + deepStrictEqual(['placementId', 'bidId', 'traffic'], Object.keys(placement)) + strictEqual(0, placement.placementId) + strictEqual('9ec5b177515ee2e5', placement.bidId) + strictEqual('banner', placement.traffic) + }) + + it('Returns empty data if no valid requests are passed', () => { + const { placements } = spec.buildRequests([]).data + + expect(spec.buildRequests([]).data.placements).to.be.an('array') + strictEqual(0, placements.length) + }) + }) + + describe('interpretResponse', () => { + const validData = [ + { + body: [{ + mediaType: 'banner', + width: 300, + height: 250, + cpm: 0.4, + ad: 'Test', + requestId: '9ec5b177515ee2e5', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }, + { + body: [{ + vastUrl: 'decenterads.com', + mediaType: 'video', + cpm: 0.5, + requestId: '9ec5b177515ee2e5', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }, + { + body: [{ + mediaType: 'native', + clickUrl: 'decenterads.com', + title: 'Test', + image: 'decenterads.com', + creativeId: '2', + impressionTrackers: ['decenterads.com'], + ttl: 120, + cpm: 0.4, + requestId: '9ec5b177515ee2e5', + netRevenue: true, + currency: 'USD', + }] + } + ] + + for (const obj of validData) { + const { mediaType } = obj.body[0] + + it(`Should interpret ${mediaType} response`, () => { + const response = spec.interpretResponse(obj) + + expect(response).to.be.an('array') + strictEqual(1, response.length) + + const copy = { ...obj.body[0] } + delete copy.mediaType + deepStrictEqual(copy, response[0]) + }) + } + + const invalidData = [ + { + body: [{ + width: 300, + cpm: 0.4, + ad: 'Test', + requestId: '9ec5b177515ee2e5', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }, + { + body: [{ + mediaType: 'video', + cpm: 0.5, + requestId: '9ec5b177515ee2e5', + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }, + { + body: [{ + mediaType: 'native', + clickUrl: 'decenterads.com', + title: 'Test', + impressionTrackers: ['decenterads.com'], + ttl: 120, + requestId: '9ec5b177515ee2e5', + creativeId: '2', + netRevenue: true, + currency: 'USD', + }] + } + ] + + for (const obj of invalidData) { + const { mediaType } = obj.body[0] + + it(`Should return an empty array if invalid ${mediaType} response is passed `, () => { + const response = spec.interpretResponse(obj) + + expect(response).to.be.an('array') + strictEqual(0, response.length) + }) + } + + it('Should return an empty array if invalid response is passed', () => { + const response = spec.interpretResponse({ + body: [{ + ttl: 120, + creativeId: '2', + netRevenue: true, + currency: 'USD', + dealId: '1' + }] + }) + + expect(response).to.be.an('array') + strictEqual(0, response.length) + }) + }) + + describe('getUserSyncs', () => { + it('Returns valid URL and type', () => { + const expectedResult = [{ type: 'image', url: 'https://supply.decenterads.com/?c=o&m=cookie' }] + deepStrictEqual(expectedResult, spec.getUserSyncs()) + }) + }) +}) diff --git a/test/spec/modules/dfpAdServerVideo_spec.js b/test/spec/modules/dfpAdServerVideo_spec.js index 895416bae2b..c0ecb9cad5e 100644 --- a/test/spec/modules/dfpAdServerVideo_spec.js +++ b/test/spec/modules/dfpAdServerVideo_spec.js @@ -38,7 +38,7 @@ describe('The DFP video support module', function () { expect(queryParams).to.have.property('env', 'vp'); expect(queryParams).to.have.property('gdfp_req', '1'); expect(queryParams).to.have.property('iu', 'my/adUnit'); - expect(queryParams).to.have.property('output', 'xml_vast3'); + expect(queryParams).to.have.property('output', 'vast'); expect(queryParams).to.have.property('sz', '640x480'); expect(queryParams).to.have.property('unviewed_position_start', '1'); expect(queryParams).to.have.property('url'); @@ -375,7 +375,7 @@ describe('The DFP video support module', function () { expect(queryParams).to.have.property('env', 'vp'); expect(queryParams).to.have.property('gdfp_req', '1'); expect(queryParams).to.have.property('iu', 'my/adUnit'); - expect(queryParams).to.have.property('output', 'xml_vast3'); + expect(queryParams).to.have.property('output', 'vast'); expect(queryParams).to.have.property('sz', '640x480'); expect(queryParams).to.have.property('unviewed_position_start', '1'); expect(queryParams).to.have.property('url'); @@ -528,7 +528,7 @@ function createBid(cpm, adUnitCode, durationBucket, priceIndustryDuration, uuid, }, 'customCacheKey': `${priceIndustryDuration}_${uuid}`, 'meta': { - 'iabSubCatId': 'iab-1', + 'primaryCatId': 'iab-1', 'adServerCatId': label }, 'videoCacheKey': '4cf395af-8fee-4960-af0e-88d44e399f14' diff --git a/test/spec/modules/digitrustIdSystem_spec.js b/test/spec/modules/digitrustIdSystem_spec.js deleted file mode 100644 index befd6eb75b6..00000000000 --- a/test/spec/modules/digitrustIdSystem_spec.js +++ /dev/null @@ -1,131 +0,0 @@ -import { - digiTrustIdSubmodule, - surfaceTestHook -} from 'modules/digiTrustIdSystem.js'; - -let assert = require('chai').assert; -let expect = require('chai').expect; -var testHook = null; - -/** -* A mock implementation of IAB Consent Provider -*/ -function mockCmp(command, version, callback, parameter) { - var resultVal; - if (command == 'ping') { - resultVal = { - gdprAppliesGlobally: mockCmp.stubSettings.isGlobal - }; - callback(resultVal); - } else if (command == 'getVendorConsents') { - let cbResult = { - vendorConsents: [] - } - cbResult.vendorConsents[version] = mockCmp.stubSettings.consents; - callback(cbResult); - } -} - -mockCmp.stubSettings = { - isGlobal: false, - consents: true -}; - -function setupCmpMock(isGlobal, consents) { - window.__cmp = mockCmp; - mockCmp.stubSettings.isGlobal = isGlobal; - mockCmp.stubSettings.consents = consents; -} - -describe('DigiTrust Id System', function () { - it('Should create the test hook', function (done) { - testHook = surfaceTestHook(); - assert.isNotNull(testHook, 'The test hook failed to surface'); - var conf = { - init: { - member: 'unit_test', - site: 'foo' - }, - callback: function (result) { - } - }; - testHook.initDigitrustFacade(conf); - window.DigiTrust.getUser(conf); - expect(window.DigiTrust).to.exist; - expect(window.DigiTrust.isMock).to.be.true; - done(); - }); - - it('Should report as client', function (done) { - delete window.DigiTrust; - testHook = surfaceTestHook(); - - var conf = { - init: { - member: 'unit_test', - site: 'foo' - }, - callback: function (result) { - expect(window.DigiTrust).to.exist; - expect(result).to.exist; - expect(window.DigiTrust.isMock).to.be.true; - } - }; - testHook.initDigitrustFacade(conf); - expect(window.DigiTrust).to.exist; - expect(window.DigiTrust.isClient).to.be.true; - done(); - }); - - it('Should allow consent when given', function (done) { - testHook = surfaceTestHook(); - setupCmpMock(true, true); - var handler = function(result) { - expect(result).to.be.true; - done(); - } - - testHook.gdpr.hasConsent(null, handler); - }); - - it('Should consent if does not apply', function (done) { - testHook = surfaceTestHook(); - setupCmpMock(false, true); - var handler = function (result) { - expect(result).to.be.true; - done(); - } - - testHook.gdpr.hasConsent(null, handler); - }); - - it('Should not allow consent when not given', function (done) { - testHook = surfaceTestHook(); - setupCmpMock(true, false); - var handler = function (result) { - expect(result).to.be.false; - done(); - } - - testHook.gdpr.hasConsent(null, handler); - }); - it('Should deny consent if timeout', function (done) { - window.__cmp = function () { }; - var handler = function (result) { - expect(result).to.be.false; - done(); - } - - testHook.gdpr.hasConsent({ consentTimeout: 1 }, handler); - }); - it('Should pass consent test if cmp not present', function (done) { - delete window.__cmp - testHook = surfaceTestHook(); - var handler = function (result) { - expect(result).to.be.true; - done(); - } - - testHook.gdpr.hasConsent(null, handler); - }); -}); diff --git a/test/spec/modules/districtmDmxBidAdapter_spec.js b/test/spec/modules/districtmDmxBidAdapter_spec.js index d8f0beb9a36..90e6957fc2c 100644 --- a/test/spec/modules/districtmDmxBidAdapter_spec.js +++ b/test/spec/modules/districtmDmxBidAdapter_spec.js @@ -1,6 +1,60 @@ import {expect} from 'chai'; import * as _ from 'lodash'; -import {spec, matchRequest, checkDeepArray, defaultSize, upto5, cleanSizes, shuffle} from '../../../modules/districtmDMXBidAdapter.js'; +import {spec, matchRequest, checkDeepArray, defaultSize, upto5, cleanSizes, shuffle, getApi, bindUserId, getPlaybackmethod, getProtocols, cleanVast} from '../../../modules/districtmDMXBidAdapter.js'; + +const sample_vast = ` + + + + + + + + + 00:00:15 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +` const supportedSize = [ { @@ -42,6 +96,30 @@ const bidRequest = [{ 'dmxid': 100001, 'memberid': 100003, }, + 'userId': { + idl_env: {}, + digitrustid: { + data: { + id: {} + } + }, + id5id: { + uid: '' + }, + pubcid: {}, + tdid: {}, + criteoId: {}, + britepoolid: {}, + intentiqid: {}, + lotamePanoramaId: {}, + parrableId: {}, + netId: {}, + sharedid: {}, + lipb: { + lipbid: {} + }, + + }, 'adUnitCode': 'div-gpt-ad-12345678-1', 'transactionId': 'f6d13fa6-ebc1-41ac-9afa-d8171d22d2c2', 'sizes': [ @@ -53,6 +131,31 @@ const bidRequest = [{ 'auctionId': '3d62f2d3-56a2-4991-888e-f7754619ddcf' }]; +const bidRequestVideo = [{ + 'bidder': 'districtmDMX', + 'params': { + 'dmxid': 100001, + 'memberid': 100003, + 'video': { + id: 123, + skipppable: true, + playback_method: ['auto_play_sound_off', 'viewport_sound_off'], + mimes: ['application/javascript', + 'video/mp4'], + } + }, + 'mediaTypes': { video: {context: 'instream', // or 'outstream' + playerSize: [[640, 480]]} }, + 'adUnitCode': 'div-gpt-ad-12345678-1', + 'transactionId': 'f6d13fa6-ebc1-41ac-9afa-d8171d22d2c2', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '29a28a1bbc8a8d', + 'bidderRequestId': '124b579a136515', + 'auctionId': '3d62f2d3-56a2-4991-888e-f7754619ddcf' +}]; const bidRequestNoCoppa = [{ 'bidder': 'districtmDMX', 'params': { @@ -505,6 +608,51 @@ describe('DistrictM Adaptor', function () { expect(upto5([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], bidRequest, bidderRequest, 'https://google').length).to.be.equal(3) }) }) + + describe('test vast tag', function() { + it('img tag should not be present', function() { + expect(cleanVast(sample_vast).indexOf('img') !== -1).to.be.equal(false) + }) + }) + describe('Test getApi function', function() { + const data = { + protocols: ['VPAID_1_0'] + } + it('Will return 1 for vpaid version 1', function() { + expect(getApi(data)[0]).to.be.equal(1) + }) + it('Will return 2 for vpaid default', function() { + expect(getApi({})[0]).to.be.equal(2) + }) + }) + + describe('Test cleanSizes function', function() { + it('sequence will be respected', function() { + expect(cleanSizes(bidderRequest.bids[0].sizes).toString()).to.be.equal('300,250,300,600') + }) + it('sequence will be respected', function() { + expect(cleanSizes([[728, 90], [970, 90], [300, 600], [320, 50]]).toString()).to.be.equal('728,90,320,50,300,600,970,90') + }) + }) + + describe('Test getPlaybackmethod function', function() { + it('getPlaybackmethod will return 2', function() { + expect(getPlaybackmethod([])[0]).to.be.equal(2) + }) + it('getPlaybackmethod will return 6', function() { + expect(getPlaybackmethod(['viewport_sound_off'])[0]).to.be.equal(6) + }) + }) + + describe('Test getProtocols function', function() { + it('getProtocols will return 3', function() { + expect(getProtocols({protocols: ['VAST_3_0']})[0]).to.be.equal(3) + }) + it('getProtocols will return 6', function() { + expect(_.isEqual(getProtocols({}), [2, 3, 5, 6, 7, 8])).to.be.equal(true) + }) + }) + describe('All needed functions are available', function () { it(`isBidRequestValid is present and type function`, function () { expect(districtm.isBidRequestValid).to.exist.and.to.be.a('function') @@ -589,6 +737,12 @@ describe('DistrictM Adaptor', function () { }); }); + describe('bidRequest Video testing', function() { + const request = districtm.buildRequests(bidRequestVideo, bidRequestVideo); + const data = JSON.parse(request.data) + expect(data instanceof Object).to.be.equal(true) + }) + describe(`interpretResponse test usage`, function () { const responseResults = districtm.interpretResponse(responses, {bidderRequest}); const emptyResponseResults = districtm.interpretResponse(emptyResponse, {bidderRequest}); diff --git a/test/spec/modules/dspxBidAdapter_spec.js b/test/spec/modules/dspxBidAdapter_spec.js index 2513a6174cd..cf36c3f62c4 100644 --- a/test/spec/modules/dspxBidAdapter_spec.js +++ b/test/spec/modules/dspxBidAdapter_spec.js @@ -59,8 +59,8 @@ describe('dspxAdapter', function () { 'sizes': [ [300, 250] ], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', + 'bidId': '30b31c1838de1e1', + 'bidderRequestId': '22edbae2733bf61', 'auctionId': '1d1a030790a475' }, { @@ -72,32 +72,117 @@ describe('dspxAdapter', function () { 'sizes': [ [300, 250] ], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475' + 'bidId': '30b31c1838de1e2', + 'bidderRequestId': '22edbae2733bf62', + 'auctionId': '1d1a030790a476' + }, { + 'bidder': 'dspx', + 'params': { + 'placement': '6682', + 'pfilter': { + 'floorprice': 1000000, + 'private_auction': 0, + 'geo': { + 'country': 'DE' + } + }, + 'bcat': 'IAB2,IAB4', + 'dvt': 'desktop' + }, + 'sizes': [ + [300, 250] + ], + 'bidId': '30b31c1838de1e3', + 'bidderRequestId': '22edbae2733bf69', + 'auctionId': '1d1a030790a477' + }, + { + 'bidder': 'dspx', + 'params': { + 'placement': '101', + 'devMode': true + }, + 'sizes': [ + [300, 250] + ], + 'bidId': '30b31c1838de1e4', + 'bidderRequestId': '22edbae2733bf67', + 'auctionId': '1d1a030790a478' + }, + { + 'bidder': 'dspx', + 'params': { + 'placement': '101', + 'devMode': true + }, + 'mediaTypes': { + 'video': { + 'playerSize': [640, 480], + 'context': 'instream' + } + }, + 'bidId': '30b31c1838de1e41', + 'bidderRequestId': '22edbae2733bf67', + 'auctionId': '1d1a030790a478' } ]; - let bidderRequest = { + // With gdprConsent + var bidderRequest = { refererInfo: { referer: 'some_referrer.net' + }, + gdprConsent: { + consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + vendorData: {someData: 'value'}, + gdprApplies: true } - } + }; - const request = spec.buildRequests(bidRequests, bidderRequest); + var request1 = spec.buildRequests([bidRequests[0]], bidderRequest)[0]; it('sends bid request to our endpoint via GET', function () { - expect(request[0].method).to.equal('GET'); - expect(request[0].url).to.equal(ENDPOINT_URL); - let data = request[0].data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid'); - expect(data).to.equal('_f=html&alternative=prebid_js&inventory_item_id=6682&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bprivate_auction%5D=0&pfilter%5Bgeo%5D%5Bcountry%5D=DE&bcat=IAB2%2CIAB4&dvt=desktop'); + expect(request1.method).to.equal('GET'); + expect(request1.url).to.equal(ENDPOINT_URL); + let data = request1.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid'); + expect(data).to.equal('_f=html&alternative=prebid_js&inventory_item_id=6682&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e1&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bprivate_auction%5D=0&pfilter%5Bgeo%5D%5Bcountry%5D=DE&pfilter%5Bgdpr_consent%5D=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&pfilter%5Bgdpr%5D=true&bcat=IAB2%2CIAB4&dvt=desktop'); }); + var request2 = spec.buildRequests([bidRequests[1]], bidderRequest)[0]; it('sends bid request to our DEV endpoint via GET', function () { - expect(request[1].method).to.equal('GET'); - expect(request[1].url).to.equal(ENDPOINT_URL_DEV); - let data = request[1].data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid'); - expect(data).to.equal('_f=html&alternative=prebid_js&inventory_item_id=101&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e&prebidDevMode=1'); + expect(request2.method).to.equal('GET'); + expect(request2.url).to.equal(ENDPOINT_URL_DEV); + let data = request2.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid'); + expect(data).to.equal('_f=html&alternative=prebid_js&inventory_item_id=101&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e2&pfilter%5Bgdpr_consent%5D=BOJ%2FP2HOJ%2FP2HABABMAAAAAZ%2BA%3D%3D&pfilter%5Bgdpr%5D=true&prebidDevMode=1'); + }); + + // Without gdprConsent + var bidderRequestWithoutGdpr = { + refererInfo: { + referer: 'some_referrer.net' + } + }; + var request3 = spec.buildRequests([bidRequests[2]], bidderRequestWithoutGdpr)[0]; + it('sends bid request without gdprConsent to our endpoint via GET', function () { + expect(request3.method).to.equal('GET'); + expect(request3.url).to.equal(ENDPOINT_URL); + let data = request3.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid'); + expect(data).to.equal('_f=html&alternative=prebid_js&inventory_item_id=6682&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e3&pfilter%5Bfloorprice%5D=1000000&pfilter%5Bprivate_auction%5D=0&pfilter%5Bgeo%5D%5Bcountry%5D=DE&bcat=IAB2%2CIAB4&dvt=desktop'); + }); + + var request4 = spec.buildRequests([bidRequests[3]], bidderRequestWithoutGdpr)[0]; + it('sends bid request without gdprConsent to our DEV endpoint via GET', function () { + expect(request4.method).to.equal('GET'); + expect(request4.url).to.equal(ENDPOINT_URL_DEV); + let data = request4.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid'); + expect(data).to.equal('_f=html&alternative=prebid_js&inventory_item_id=101&srw=300&srh=250&idt=100&bid_id=30b31c1838de1e4&prebidDevMode=1'); + }); + + var request5 = spec.buildRequests([bidRequests[4]], bidderRequestWithoutGdpr)[0]; + it('sends bid video request to our rads endpoint via GET', function () { + expect(request5.method).to.equal('GET'); + let data = request5.data.replace(/rnd=\d+\&/g, '').replace(/ref=.*\&bid/g, 'bid'); + expect(data).to.equal('_f=vast2&alternative=prebid_js&inventory_item_id=101&srw=640&srh=480&idt=100&bid_id=30b31c1838de1e41&prebidDevMode=1'); }); }); @@ -117,6 +202,21 @@ describe('dspxAdapter', function () { 'zone': '6682' } }; + let serverVideoResponse = { + 'body': { + 'cpm': 5000000, + 'crid': 100500, + 'width': '300', + 'height': '250', + 'vastXml': '{"reason":7001,"status":"accepted"}', + 'requestId': '220ed41385952a', + 'type': 'vast2', + 'currency': 'EUR', + 'ttl': 60, + 'netRevenue': true, + 'zone': '6682' + } + }; let expectedResponse = [{ requestId: '23beaa6af6cdde', @@ -130,6 +230,19 @@ describe('dspxAdapter', function () { ttl: 300, type: 'sspHTML', ad: '' + }, { + requestId: '23beaa6af6cdde', + cpm: 0.5, + width: 0, + height: 0, + creativeId: 100500, + dealId: '', + currency: 'EUR', + netRevenue: true, + ttl: 300, + type: 'vast2', + vastXml: '{"reason":7001,"status":"accepted"}', + mediaType: 'video' }]; it('should get the correct bid response by display ad', function () { @@ -144,6 +257,24 @@ describe('dspxAdapter', function () { expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); }); + it('should get the correct dspx video bid response by display ad', function () { + let bidRequest = [{ + 'method': 'GET', + 'url': ENDPOINT_URL, + 'mediaTypes': { + 'video': { + 'playerSize': [640, 480], + 'context': 'instream' + } + }, + 'data': { + 'bid_id': '30b31c1838de1e' + } + }]; + let result = spec.interpretResponse(serverVideoResponse, bidRequest[0]); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[1])); + }); + it('handles empty bid response', function () { let response = { body: {} diff --git a/test/spec/modules/edgequeryxBidAdapter_spec.js b/test/spec/modules/edgequeryxBidAdapter_spec.js new file mode 100644 index 00000000000..a66c546bd7c --- /dev/null +++ b/test/spec/modules/edgequeryxBidAdapter_spec.js @@ -0,0 +1,116 @@ +import { + expect +} from 'chai'; +import { + spec +} from 'modules/edgequeryxBidAdapter.js'; +import { + newBidder +} from 'src/adapters/bidderFactory.js'; +import { + config +} from 'src/config.js'; +import * as utils from 'src/utils.js'; +import { requestBidsHook } from 'modules/consentManagement.js'; + +// Default params with optional ones +describe('Edge Query X bid adapter tests', function () { + var DEFAULT_PARAMS = [{ + bidId: 'abcd1234', + mediaTypes: { + banner: { + sizes: [ + [1, 1] + ] + } + }, + bidder: 'edgequeryx', + params: { + accountId: 'test', + widgetId: 'test' + }, + requestId: 'efgh5678', + transactionId: 'zsfgzzg' + }]; + var BID_RESPONSE = { + body: { + requestId: 'abcd1234', + cpm: 22, + width: 1, + height: 1, + creativeId: 'EQXTest', + currency: 'EUR', + netRevenue: true, + ttl: 360, + ad: '< --- awesome script --- >' + } + }; + + it('Verify build request', function () { + config.setConfig({ + 'currency': { + 'adServerCurrency': 'EUR' + } + }); + const request = spec.buildRequests(DEFAULT_PARAMS); + expect(request[0]).to.have.property('url').and.to.equal('https://deep.edgequery.io/prebid/x'); + expect(request[0]).to.have.property('method').and.to.equal('POST'); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('accountId').and.to.equal('test'); + expect(requestContent).to.have.property('widgetId').and.to.equal('test'); + expect(requestContent).to.have.property('sizes'); + expect(requestContent.sizes[0]).to.have.property('w').and.to.equal(1); + expect(requestContent.sizes[0]).to.have.property('h').and.to.equal(1); + }); + + it('Verify parse response', function () { + const request = spec.buildRequests(DEFAULT_PARAMS); + const bids = spec.interpretResponse(BID_RESPONSE, request[0]); + expect(bids).to.have.lengthOf(1); + const bid = bids[0]; + expect(bid.cpm).to.equal(22); + expect(bid.ad).to.equal('< --- awesome script --- >'); + expect(bid.width).to.equal(1); + expect(bid.height).to.equal(1); + expect(bid.creativeId).to.equal('EQXTest'); + expect(bid.currency).to.equal('EUR'); + expect(bid.netRevenue).to.equal(true); + expect(bid.ttl).to.equal(360); + expect(bid.requestId).to.equal(DEFAULT_PARAMS[0].bidId); + + expect(function () { + spec.interpretResponse(BID_RESPONSE, { + data: 'invalid Json' + }) + }).to.not.throw(); + }); + + it('Verifies bidder code', function () { + expect(spec.code).to.equal('edgequeryx'); + }); + + it('Verifies bidder aliases', function () { + expect(spec.aliases).to.have.lengthOf(1); + expect(spec.aliases[0]).to.equal('eqx'); + }); + + it('Verifies if bid request valid', function () { + expect(spec.isBidRequestValid(DEFAULT_PARAMS[0])).to.equal(true); + expect(spec.isBidRequestValid({})).to.equal(false); + expect(spec.isBidRequestValid({ + params: {} + })).to.equal(false); + expect(spec.isBidRequestValid({ + params: { + widgetyId: 'abcdef' + } + })).to.equal(false); + expect(spec.isBidRequestValid({ + params: { + widgetId: 'test', + accountId: 'test' + } + })).to.equal(true); + }); +}); diff --git a/test/spec/modules/eids_spec.js b/test/spec/modules/eids_spec.js index ed32ecc51d2..26dbad2f153 100644 --- a/test/spec/modules/eids_spec.js +++ b/test/spec/modules/eids_spec.js @@ -29,26 +29,64 @@ describe('eids array generation for known sub-modules', function() { }); }); - it('id5Id', function() { + describe('id5Id', function() { + it('does not include an ext if not provided', function() { + const userId = { + id5id: { + uid: 'some-random-id-value' + } + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'id5-sync.com', + uids: [{ id: 'some-random-id-value', atype: 1 }] + }); + }); + + it('includes ext if provided', function() { + const userId = { + id5id: { + uid: 'some-random-id-value', + ext: { + linkType: 0 + } + } + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'id5-sync.com', + uids: [{ id: 'some-random-id-value', atype: 1 }], + ext: { + linkType: 0 + } + }); + }); + }); + + it('parrableId', function() { const userId = { - id5id: 'some-random-id-value' + parrableId: { + eid: 'some-random-id-value' + } }; const newEids = createEidsArray(userId); expect(newEids.length).to.equal(1); expect(newEids[0]).to.deep.equal({ - source: 'id5-sync.com', + source: 'parrable.com', uids: [{id: 'some-random-id-value', atype: 1}] }); }); - it('parrableId', function() { + it('merkleId', function() { const userId = { - parrableid: 'some-random-id-value' + merkleId: 'some-random-id-value' }; const newEids = createEidsArray(userId); expect(newEids.length).to.equal(1); expect(newEids[0]).to.deep.equal({ - source: 'parrable.com', + source: 'merkleinc.com', uids: [{id: 'some-random-id-value', atype: 1}] }); }); @@ -107,19 +145,15 @@ describe('eids array generation for known sub-modules', function() { }); }); - it('DigiTrust; getValue call', function() { + it('lotamePanoramaId', function () { const userId = { - digitrustid: { - data: { - id: 'some-random-id-value' - } - } + lotamePanoramaId: 'some-random-id-value', }; const newEids = createEidsArray(userId); expect(newEids.length).to.equal(1); expect(newEids[0]).to.deep.equal({ - source: 'digitru.st', - uids: [{id: 'some-random-id-value', atype: 1}] + source: 'crwdcntrl.net', + uids: [{ id: 'some-random-id-value', atype: 1 }], }); }); @@ -146,8 +180,123 @@ describe('eids array generation for known sub-modules', function() { uids: [{id: 'some-random-id-value', atype: 1}] }); }); -}); + it('Sharedid', function() { + const userId = { + sharedid: { + id: 'test_sharedId', + third: 'test_sharedId' + } + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'sharedid.org', + uids: [{ + id: 'test_sharedId', + atype: 1, + ext: { + third: 'test_sharedId' + } + }] + }); + }); + it('Sharedid: Not Synched', function() { + const userId = { + sharedid: { + id: 'test_sharedId' + } + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'sharedid.org', + uids: [{ + id: 'test_sharedId', + atype: 1 + }] + }); + }); + + it('zeotapIdPlus', function() { + const userId = { + IDP: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'zeotap.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }); + }); + + it('haloId', function() { + const userId = { + haloId: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'audigent.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }); + }); + it('quantcastId', function() { + const userId = { + quantcastId: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'quantcast.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }); + }); + it('pubProvidedId', function() { + const userId = { + pubProvidedId: [{ + source: 'example.com', + uids: [{ + id: 'value read from cookie or local storage', + ext: { + stype: 'ppuid' + } + }] + }, { + source: 'id-partner.com', + uids: [{ + id: 'value read from cookie or local storage' + }] + }] + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(2); + expect(newEids[0]).to.deep.equal({ + source: 'example.com', + uids: [{ + id: 'value read from cookie or local storage', + ext: { + stype: 'ppuid' + } + }] + }); + expect(newEids[1]).to.deep.equal({ + source: 'id-partner.com', + uids: [{ + id: 'value read from cookie or local storage' + }] + }); + }); +}); describe('Negative case', function() { it('eids array generation for UN-known sub-module', function() { // UnknownCommonId diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js index 7be8a2ce5ac..138786b9c74 100644 --- a/test/spec/modules/emx_digitalBidAdapter_spec.js +++ b/test/spec/modules/emx_digitalBidAdapter_spec.js @@ -612,12 +612,23 @@ describe('emx_digital Adapter', function () { }); describe('getUserSyncs', function () { - let syncOptionsIframe = { iframeEnabled: true }; - let syncOptionsPixel = { pixelEnabled: true }; - it('Should push the correct sync type depending on the config', function () { - let iframeSync = spec.getUserSyncs(syncOptionsIframe); - expect(iframeSync.length).to.equal(1); - expect(iframeSync[0].type).to.equal('iframe'); + it('should register the iframe sync url', function () { + let syncs = spec.getUserSyncs({ + iframeEnabled: true + }); + expect(syncs).to.not.be.an('undefined'); + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('iframe'); + }); + + it('should pass gdpr params', function () { + let syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, { + gdprApplies: false, consentString: 'test' + }); + expect(syncs).to.not.be.an('undefined'); + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.contains('gdpr=0'); }); }); }); diff --git a/test/spec/modules/eplanningBidAdapter_spec.js b/test/spec/modules/eplanningBidAdapter_spec.js index ff03bf033af..f267680b46b 100644 --- a/test/spec/modules/eplanningBidAdapter_spec.js +++ b/test/spec/modules/eplanningBidAdapter_spec.js @@ -343,13 +343,13 @@ describe('E-Planning Adapter', function () { it('should return ur parameter with current window url', function () { const ur = spec.buildRequests(bidRequests, bidderRequest).data.ur; - expect(ur).to.equal(encodeURIComponent(bidderRequest.refererInfo.referer)); + expect(ur).to.equal(bidderRequest.refererInfo.referer); }); it('should return fr parameter when there is a referrer', function () { const request = spec.buildRequests(bidRequests, bidderRequest); const dataRequest = request.data; - expect(dataRequest.fr).to.equal(encodeURIComponent(refererUrl)); + expect(dataRequest.fr).to.equal(refererUrl); }); it('should return crs parameter with document charset', function () { diff --git a/test/spec/modules/fidelityBidAdapter_spec.js b/test/spec/modules/fidelityBidAdapter_spec.js index 1232c20b0d7..304a98675b3 100644 --- a/test/spec/modules/fidelityBidAdapter_spec.js +++ b/test/spec/modules/fidelityBidAdapter_spec.js @@ -109,7 +109,7 @@ describe('FidelityAdapter', function () { expect(payload.schain).to.equal(schainString); }); - it('should add consent information to the request', function () { + it('should add consent information to the request - TCF v1', function () { let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; let uspConsentString = '1YN-'; bidderRequest.gdprConsent = { @@ -118,9 +118,39 @@ describe('FidelityAdapter', function () { consentString: consentString, vendorData: { vendorConsents: { - '408': 1 + '408': true }, }, + apiVersion: 1 + }; + bidderRequest.uspConsent = uspConsentString; + const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + const payload = request.data; + expect(payload.gdpr).to.exist.and.to.be.a('number'); + expect(payload.gdpr).to.equal(1); + expect(payload.consent_str).to.exist.and.to.be.a('string'); + expect(payload.consent_str).to.equal(consentString); + expect(payload.consent_given).to.exist.and.to.be.a('number'); + expect(payload.consent_given).to.equal(1); + expect(payload.us_privacy).to.exist.and.to.be.a('string'); + expect(payload.us_privacy).to.equal(uspConsentString); + }); + + it('should add consent information to the request - TCF v2', function () { + let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; + let uspConsentString = '1YN-'; + bidderRequest.gdprConsent = { + gdprApplies: true, + allowAuctionWithoutConsent: true, + consentString: consentString, + vendorData: { + vendor: { + consents: { + '408': true + } + }, + }, + apiVersion: 2 }; bidderRequest.uspConsent = uspConsentString; const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); diff --git a/test/spec/modules/fintezaAnalyticsAdapter_spec.js b/test/spec/modules/fintezaAnalyticsAdapter_spec.js index 29136c85241..4c76f79f518 100644 --- a/test/spec/modules/fintezaAnalyticsAdapter_spec.js +++ b/test/spec/modules/fintezaAnalyticsAdapter_spec.js @@ -12,7 +12,7 @@ function setCookie(name, value, expires) { document.cookie = name + '=' + value + '; path=/' + (expires ? ('; expires=' + expires.toUTCString()) : '') + - '; SameSite=None'; + '; SameSite=Lax'; } describe('finteza analytics adapter', function () { diff --git a/test/spec/modules/freeWheelAdserverVideo_spec.js b/test/spec/modules/freeWheelAdserverVideo_spec.js index 172909f99ca..0a215092e18 100644 --- a/test/spec/modules/freeWheelAdserverVideo_spec.js +++ b/test/spec/modules/freeWheelAdserverVideo_spec.js @@ -342,7 +342,7 @@ function createBid(cpm, adUnitCode, durationBucket, priceIndustryDuration, uuid, }, 'customCacheKey': `${priceIndustryDuration}_${uuid}`, 'meta': { - 'iabSubCatId': 'iab-1', + 'primaryCatId': 'iab-1', 'adServerCatId': industry }, 'videoCacheKey': '4cf395af-8fee-4960-af0e-88d44e399f14' diff --git a/test/spec/modules/freewheel-sspBidAdapter_spec.js b/test/spec/modules/freewheel-sspBidAdapter_spec.js index ffb9f1fe431..3047b635d13 100644 --- a/test/spec/modules/freewheel-sspBidAdapter_spec.js +++ b/test/spec/modules/freewheel-sspBidAdapter_spec.js @@ -107,7 +107,8 @@ describe('freewheelSSP BidAdapter Test', () => { expect(payload.reqType).to.equal('AdsSetup'); expect(payload.protocolVersion).to.equal('2.0'); expect(payload.zoneId).to.equal('277225'); - expect(payload.componentId).to.equal('mustang'); + expect(payload.componentId).to.equal('prebid'); + expect(payload.componentSubId).to.equal('mustang'); expect(payload.playerSize).to.equal('300x600'); }); @@ -126,7 +127,8 @@ describe('freewheelSSP BidAdapter Test', () => { expect(payload.reqType).to.equal('AdsSetup'); expect(payload.protocolVersion).to.equal('2.0'); expect(payload.zoneId).to.equal('277225'); - expect(payload.componentId).to.equal('mustang'); + expect(payload.componentId).to.equal('prebid'); + expect(payload.componentSubId).to.equal('mustang'); expect(payload.playerSize).to.equal('300x600'); expect(payload._fw_us_privacy).to.exist.and.to.be.a('string'); expect(payload._fw_us_privacy).to.equal(uspConsentString); @@ -145,7 +147,8 @@ describe('freewheelSSP BidAdapter Test', () => { expect(payload.reqType).to.equal('AdsSetup'); expect(payload.protocolVersion).to.equal('2.0'); expect(payload.zoneId).to.equal('277225'); - expect(payload.componentId).to.equal('mustang'); + expect(payload.componentId).to.equal('prebid'); + expect(payload.componentSubId).to.equal('mustang'); expect(payload.playerSize).to.equal('300x600'); expect(payload._fw_gdpr_consent).to.exist.and.to.be.a('string'); expect(payload._fw_gdpr_consent).to.equal(gdprConsentString); @@ -178,7 +181,8 @@ describe('freewheelSSP BidAdapter Test', () => { expect(payload.reqType).to.equal('AdsSetup'); expect(payload.protocolVersion).to.equal('2.0'); expect(payload.zoneId).to.equal('277225'); - expect(payload.componentId).to.equal('mustang'); + expect(payload.componentId).to.equal('prebid'); + expect(payload.componentSubId).to.equal('mustang'); expect(payload.playerSize).to.equal('300x600'); }); @@ -197,7 +201,8 @@ describe('freewheelSSP BidAdapter Test', () => { expect(payload.reqType).to.equal('AdsSetup'); expect(payload.protocolVersion).to.equal('2.0'); expect(payload.zoneId).to.equal('277225'); - expect(payload.componentId).to.equal('mustang'); + expect(payload.componentId).to.equal('prebid'); + expect(payload.componentSubId).to.equal('mustang'); expect(payload.playerSize).to.equal('300x600'); expect(payload._fw_us_privacy).to.exist.and.to.be.a('string'); expect(payload._fw_us_privacy).to.equal(uspConsentString); @@ -216,7 +221,8 @@ describe('freewheelSSP BidAdapter Test', () => { expect(payload.reqType).to.equal('AdsSetup'); expect(payload.protocolVersion).to.equal('2.0'); expect(payload.zoneId).to.equal('277225'); - expect(payload.componentId).to.equal('mustang'); + expect(payload.componentId).to.equal('prebid'); + expect(payload.componentSubId).to.equal('mustang'); expect(payload.playerSize).to.equal('300x600'); expect(payload._fw_gdpr_consent).to.exist.and.to.be.a('string'); expect(payload._fw_gdpr_consent).to.equal(gdprConsentString); diff --git a/test/spec/modules/gamoshiBidAdapter_spec.js b/test/spec/modules/gamoshiBidAdapter_spec.js index 79f58470cb3..2996b853046 100644 --- a/test/spec/modules/gamoshiBidAdapter_spec.js +++ b/test/spec/modules/gamoshiBidAdapter_spec.js @@ -423,7 +423,7 @@ describe('GamoshiAdapter', () => { it('build request with ID5 Id', () => { const bidRequestClone = utils.deepClone(bidRequest); bidRequestClone.userId = {}; - bidRequestClone.userId.id5id = 'id5-user-id'; + bidRequestClone.userId.id5id = { uid: 'id5-user-id' }; let request = spec.buildRequests([bidRequestClone], bidRequestClone)[0]; expect(request.data.user.ext.eids).to.deep.equal([{ 'source': 'id5-sync.com', diff --git a/test/spec/modules/gdprEnforcement_spec.js b/test/spec/modules/gdprEnforcement_spec.js index 5b46441cbbb..82cb70f42be 100644 --- a/test/spec/modules/gdprEnforcement_spec.js +++ b/test/spec/modules/gdprEnforcement_spec.js @@ -1,11 +1,24 @@ -import { deviceAccessHook, setEnforcementConfig, userSyncHook, userIdHook } from 'modules/gdprEnforcement.js'; +import { + deviceAccessHook, + setEnforcementConfig, + userSyncHook, + userIdHook, + makeBidRequestsHook, + validateRules, + enforcementRules, + purpose1Rule, + purpose2Rule, + enableAnalyticsHook, + getGvlid, + internal +} from 'modules/gdprEnforcement.js'; import { config } from 'src/config.js'; import adapterManager, { gdprDataHandler } from 'src/adapterManager.js'; import * as utils from 'src/utils.js'; import { validateStorageEnforcement } from 'src/storageManager.js'; -import { executeStorageCallbacks } from 'src/prebid.js'; +import events from 'src/events.js'; -describe('gdpr enforcement', function() { +describe('gdpr enforcement', function () { let nextFnSpy; let logWarnSpy; let gdprDataHandlerStub; @@ -34,11 +47,12 @@ describe('gdpr enforcement', function() { 'consents': { '1': true, '2': true, - '3': true + '3': true, + '7': true }, 'legitimateInterests': { '1': false, - '2': false, + '2': true, '3': false } }, @@ -46,7 +60,9 @@ describe('gdpr enforcement', function() { 'consents': { '1': true, '2': true, - '3': false + '3': false, + '4': true, + '5': false }, 'legitimateInterests': { '1': false, @@ -81,23 +97,38 @@ describe('gdpr enforcement', function() { } }; - after(function() { - validateStorageEnforcement.getHooks({hook: deviceAccessHook}).remove(); - $$PREBID_GLOBAL$$.requestBids.getHooks({hook: executeStorageCallbacks}).remove(); + after(function () { + validateStorageEnforcement.getHooks({ hook: deviceAccessHook }).remove(); + $$PREBID_GLOBAL$$.requestBids.getHooks().remove(); + adapterManager.makeBidRequests.getHooks({ hook: makeBidRequestsHook }).remove(); }) - describe('deviceAccessHook', function() { - beforeEach(function() { + describe('deviceAccessHook', function () { + let adapterManagerStub; + + function getBidderSpec(gvlid) { + return { + getSpec: () => { + return { + gvlid + } + } + } + } + + beforeEach(function () { nextFnSpy = sinon.spy(); gdprDataHandlerStub = sinon.stub(gdprDataHandler, 'getConsentData'); logWarnSpy = sinon.spy(utils, 'logWarn'); + adapterManagerStub = sinon.stub(adapterManager, 'getBidAdapter'); }); - afterEach(function() { + afterEach(function () { config.resetConfig(); gdprDataHandler.getConsentData.restore(); logWarnSpy.restore(); + adapterManagerStub.restore(); }); - it('should not allow device access when device access flag is set to false', function() { + it('should not allow device access when device access flag is set to false', function () { config.setConfig({ deviceAccess: false, consentManagement: { @@ -118,10 +149,12 @@ describe('gdpr enforcement', function() { hasEnforcementHook: true, valid: false } - expect(nextFnSpy.calledWith(undefined, result)); + sinon.assert.calledWith(nextFnSpy, undefined, undefined, result); }); - it('should only check for consent for vendor exceptions when enforcePurpose and enforceVendor are false', function() { + it('should only check for consent for vendor exceptions when enforcePurpose and enforceVendor are false', function () { + adapterManagerStub.withArgs('appnexus').returns(getBidderSpec(1)); + adapterManagerStub.withArgs('rubicon').returns(getBidderSpec(5)); setEnforcementConfig({ gdpr: { rules: [{ @@ -143,7 +176,9 @@ describe('gdpr enforcement', function() { expect(logWarnSpy.callCount).to.equal(0); }); - it('should check consent for all vendors when enforcePurpose and enforceVendor are true', function() { + it('should check consent for all vendors when enforcePurpose and enforceVendor are true', function () { + adapterManagerStub.withArgs('appnexus').returns(getBidderSpec(1)); + adapterManagerStub.withArgs('rubicon').returns(getBidderSpec(3)); setEnforcementConfig({ gdpr: { rules: [{ @@ -164,7 +199,8 @@ describe('gdpr enforcement', function() { expect(logWarnSpy.callCount).to.equal(1); }); - it('should allow device access when gdprApplies is false and hasDeviceAccess flag is true', function() { + it('should allow device access when gdprApplies is false and hasDeviceAccess flag is true', function () { + adapterManagerStub.withArgs('appnexus').returns(getBidderSpec(1)); setEnforcementConfig({ gdpr: { rules: [{ @@ -187,15 +223,83 @@ describe('gdpr enforcement', function() { hasEnforcementHook: true, valid: true } - expect(nextFnSpy.calledWith(undefined, result)); + sinon.assert.calledWith(nextFnSpy, 1, 'appnexus', result); + }); + + it('should use gvlMapping set by publisher', function() { + config.setConfig({ + 'gvlMapping': { + 'appnexus': 4 + } + }); + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: [] + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.gdprApplies = true; + consentData.apiVersion = 2; + gdprDataHandlerStub.returns(consentData); + + deviceAccessHook(nextFnSpy, 1, 'appnexus'); + expect(nextFnSpy.calledOnce).to.equal(true); + let result = { + hasEnforcementHook: true, + valid: true + } + sinon.assert.calledWith(nextFnSpy, 4, 'appnexus', result); + config.resetConfig(); + }); + + it('should use gvl id of alias and not of parent', function() { + let curBidderStub = sinon.stub(config, 'getCurrentBidder'); + curBidderStub.returns('appnexus-alias'); + adapterManager.aliasBidAdapter('appnexus', 'appnexus-alias'); + config.setConfig({ + 'gvlMapping': { + 'appnexus-alias': 4 + } + }); + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: [] + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.gdprApplies = true; + consentData.apiVersion = 2; + gdprDataHandlerStub.returns(consentData); + + deviceAccessHook(nextFnSpy, 1, 'appnexus'); + expect(nextFnSpy.calledOnce).to.equal(true); + let result = { + hasEnforcementHook: true, + valid: true + } + sinon.assert.calledWith(nextFnSpy, 4, 'appnexus', result); + config.resetConfig(); + curBidderStub.restore(); }); }); - describe('userSyncHook', function() { + describe('userSyncHook', function () { let curBidderStub; let adapterManagerStub; - beforeEach(function() { + beforeEach(function () { gdprDataHandlerStub = sinon.stub(gdprDataHandler, 'getConsentData'); logWarnSpy = sinon.spy(utils, 'logWarn'); curBidderStub = sinon.stub(config, 'getCurrentBidder'); @@ -203,7 +307,7 @@ describe('gdpr enforcement', function() { nextFnSpy = sinon.spy(); }); - afterEach(function() { + afterEach(function () { config.getCurrentBidder.restore(); config.resetConfig(); gdprDataHandler.getConsentData.restore(); @@ -211,7 +315,7 @@ describe('gdpr enforcement', function() { logWarnSpy.restore(); }); - it('should allow bidder to do user sync if consent is true', function() { + it('should allow bidder to do user sync if consent is true', function () { setEnforcementConfig({ gdpr: { rules: [{ @@ -230,7 +334,7 @@ describe('gdpr enforcement', function() { curBidderStub.returns('sampleBidder1'); adapterManagerStub.withArgs('sampleBidder1').returns({ - getSpec: function() { + getSpec: function () { return { 'gvlid': 1 } @@ -240,7 +344,7 @@ describe('gdpr enforcement', function() { curBidderStub.returns('sampleBidder2'); adapterManagerStub.withArgs('sampleBidder2').returns({ - getSpec: function() { + getSpec: function () { return { 'gvlid': 3 } @@ -250,7 +354,7 @@ describe('gdpr enforcement', function() { expect(nextFnSpy.calledTwice).to.equal(true); }); - it('should not allow bidder to do user sync if user has denied consent', function() { + it('should not allow bidder to do user sync if user has denied consent', function () { setEnforcementConfig({ gdpr: { rules: [{ @@ -269,7 +373,7 @@ describe('gdpr enforcement', function() { curBidderStub.returns('sampleBidder1'); adapterManagerStub.withArgs('sampleBidder1').returns({ - getSpec: function() { + getSpec: function () { return { 'gvlid': 1 } @@ -279,7 +383,7 @@ describe('gdpr enforcement', function() { curBidderStub.returns('sampleBidder2'); adapterManagerStub.withArgs('sampleBidder2').returns({ - getSpec: function() { + getSpec: function () { return { 'gvlid': 3 } @@ -290,7 +394,7 @@ describe('gdpr enforcement', function() { expect(logWarnSpy.callCount).to.equal(1); }); - it('should not check vendor consent when enforceVendor is false', function() { + it('should not check vendor consent when enforceVendor is false', function () { setEnforcementConfig({ gdpr: { rules: [{ @@ -309,7 +413,7 @@ describe('gdpr enforcement', function() { curBidderStub.returns('sampleBidder1'); adapterManagerStub.withArgs('sampleBidder1').returns({ - getSpec: function() { + getSpec: function () { return { 'gvlid': 1 } @@ -319,7 +423,7 @@ describe('gdpr enforcement', function() { curBidderStub.returns('sampleBidder2'); adapterManagerStub.withArgs('sampleBidder2').returns({ - getSpec: function() { + getSpec: function () { return { 'gvlid': 3 } @@ -331,16 +435,16 @@ describe('gdpr enforcement', function() { }); }); - describe('userIdHook', function() { - beforeEach(function() { + describe('userIdHook', function () { + beforeEach(function () { logWarnSpy = sinon.spy(utils, 'logWarn'); nextFnSpy = sinon.spy(); }); - afterEach(function() { + afterEach(function () { config.resetConfig(); logWarnSpy.restore(); }); - it('should allow user id module if consent is given', function() { + it('should allow user id module if consent is given', function () { setEnforcementConfig({ gdpr: { rules: [{ @@ -362,10 +466,14 @@ describe('gdpr enforcement', function() { } }] userIdHook(nextFnSpy, submodules, consentData); + // Should pass back hasValidated flag since version 2 + const args = nextFnSpy.getCalls()[0].args; + expect(args[1].hasValidated).to.be.true; expect(nextFnSpy.calledOnce).to.equal(true); + sinon.assert.calledWith(nextFnSpy, submodules, { ...consentData, hasValidated: true }); }); - it('should allow userId module if gdpr not in scope', function() { + it('should allow userId module if gdpr not in scope', function () { let submodules = [{ submodule: { gvlid: 1, @@ -374,11 +482,14 @@ describe('gdpr enforcement', function() { }]; let consentData = null; userIdHook(nextFnSpy, submodules, consentData); + // Should not pass back hasValidated flag since version 2 + const args = nextFnSpy.getCalls()[0].args; + expect(args[1]).to.be.null; expect(nextFnSpy.calledOnce).to.equal(true); - expect(nextFnSpy.calledWith(undefined, submodules, consentData)); + sinon.assert.calledWith(nextFnSpy, submodules, consentData); }); - it('should not allow user id module if user denied consent', function() { + it('should not allow user id module if user denied consent', function () { setEnforcementConfig({ gdpr: { rules: [{ @@ -393,6 +504,7 @@ describe('gdpr enforcement', function() { consentData.vendorData = staticConfig.consentData.getTCData; consentData.apiVersion = 2; consentData.gdprApplies = true; + let submodules = [{ submodule: { gvlid: 1, @@ -412,7 +524,602 @@ describe('gdpr enforcement', function() { name: 'sampleUserId' } }] - expect(nextFnSpy.calledWith(undefined, expectedSubmodules, consentData)); + sinon.assert.calledWith(nextFnSpy, expectedSubmodules, { ...consentData, hasValidated: true }); + }); + }); + + describe('makeBidRequestsHook', function () { + let sandbox; + let adapterManagerStub; + let emitEventSpy; + + const MOCK_AD_UNITS = [{ + code: 'ad-unit-1', + mediaTypes: {}, + bids: [{ + bidder: 'bidder_1' // has consent + }, { + bidder: 'bidder_2' // doesn't have consent, but liTransparency is true. Bidder remains active. + }] + }, { + code: 'ad-unit-2', + mediaTypes: {}, + bids: [{ + bidder: 'bidder_2' + }, { + bidder: 'bidder_3' + }] + }]; + + beforeEach(function () { + sandbox = sinon.createSandbox(); + gdprDataHandlerStub = sandbox.stub(gdprDataHandler, 'getConsentData'); + adapterManagerStub = sandbox.stub(adapterManager, 'getBidAdapter'); + logWarnSpy = sandbox.spy(utils, 'logWarn'); + nextFnSpy = sandbox.spy(); + emitEventSpy = sandbox.spy(events, 'emit'); + }); + afterEach(function () { + config.resetConfig(); + sandbox.restore(); + }); + + it('should block bidder which does not have consent and allow bidder which has consent (liTransparency is established)', function () { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'basicAds', + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: [] + }] + } + }); + const consentData = {}; + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.apiVersion = 2; + consentData.gdprApplies = true; + + gdprDataHandlerStub.returns(consentData); + adapterManagerStub.withArgs('bidder_1').returns({ + getSpec: function () { + return { 'gvlid': 4 } + } + }); + adapterManagerStub.withArgs('bidder_2').returns({ + getSpec: function () { + return { 'gvlid': 5 } + } + }); + adapterManagerStub.withArgs('bidder_3').returns({ + getSpec: function () { + return { 'gvlid': undefined } + } + }); + makeBidRequestsHook(nextFnSpy, MOCK_AD_UNITS, []); + + // Assertions + expect(nextFnSpy.calledOnce).to.equal(true); + sinon.assert.calledWith(nextFnSpy, [{ + code: 'ad-unit-1', + mediaTypes: {}, + bids: [ + sinon.match({ bidder: 'bidder_1' }), + sinon.match({ bidder: 'bidder_2' }) + ] + }, { + code: 'ad-unit-2', + mediaTypes: {}, + bids: [ + sinon.match({ bidder: 'bidder_2' }), + sinon.match({ bidder: 'bidder_3' }) // should be allowed even though it's doesn't have a gvlId because liTransparency is established. + ] + }], []); + }); + + it('should block bidder which does not have consent and allow bidder which has consent (liTransparency is NOT established)', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'basicAds', + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: ['bidder_3'] + }] + } + }); + const consentData = {}; + + // set li for purpose 2 to false + const newConsentData = utils.deepClone(staticConfig); + newConsentData.consentData.getTCData.purpose.legitimateInterests['2'] = false; + + consentData.vendorData = newConsentData.consentData.getTCData; + consentData.apiVersion = 2; + consentData.gdprApplies = true; + + gdprDataHandlerStub.returns(consentData); + adapterManagerStub.withArgs('bidder_1').returns({ + getSpec: function () { + return { 'gvlid': 4 } + } + }); + adapterManagerStub.withArgs('bidder_2').returns({ + getSpec: function () { + return { 'gvlid': 5 } + } + }); + adapterManagerStub.withArgs('bidder_3').returns({ + getSpec: function () { + return { 'gvlid': undefined } + } + }); + + makeBidRequestsHook(nextFnSpy, MOCK_AD_UNITS, []); + + // Assertions + expect(nextFnSpy.calledOnce).to.equal(true); + sinon.assert.calledWith(nextFnSpy, [{ + code: 'ad-unit-1', + mediaTypes: {}, + bids: [ + sinon.match({ bidder: 'bidder_1' }), // 'bidder_2' is not present because it doesn't have vendorConsent + ] + }, { + code: 'ad-unit-2', + mediaTypes: {}, + bids: [ + sinon.match({ bidder: 'bidder_3' }), // 'bidder_3' is allowed despite gvlId being undefined because it's part of vendorExceptions + ] + }], []); + + expect(logWarnSpy.calledOnce).to.equal(true); + }); + + it('should skip validation checks if GDPR version is not equal to "2"', function () { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforePurpose: false, + enforceVendor: false, + vendorExceptions: [] + }] + } + }); + + const consentData = {}; + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.apiVersion = 1; + consentData.gdprApplies = true; + gdprDataHandlerStub.returns(consentData); + + makeBidRequestsHook(nextFnSpy, MOCK_AD_UNITS, []); + + // Assertions + expect(nextFnSpy.calledOnce).to.equal(true); + sinon.assert.calledWith(nextFnSpy, sinon.match.array.deepEquals(MOCK_AD_UNITS), []); + expect(emitEventSpy.notCalled).to.equal(true); + expect(logWarnSpy.notCalled).to.equal(true); + }); + }); + + describe('enableAnalyticsHook', function () { + let sandbox; + let adapterManagerStub; + + const MOCK_ANALYTICS_ADAPTER_CONFIG = [{ + provider: 'analyticsAdapter_A', + options: {} + }, { + provider: 'analyticsAdapter_B', + options: {} + }, { + provider: 'analyticsAdapter_C', + options: {} + }]; + + beforeEach(function () { + sandbox = sinon.createSandbox(); + gdprDataHandlerStub = sandbox.stub(gdprDataHandler, 'getConsentData'); + adapterManagerStub = sandbox.stub(adapterManager, 'getAnalyticsAdapter'); + logWarnSpy = sandbox.spy(utils, 'logWarn'); + nextFnSpy = sandbox.spy(); + }); + + afterEach(function() { + config.resetConfig(); + sandbox.restore(); + }); + + it('should block analytics adapter which does not have consent and allow the one(s) which have consent', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'measurement', + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: ['analyticsAdapter_B'] + }] + } + }); + + const consentData = {}; + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.apiVersion = 2; + consentData.gdprApplies = true; + + gdprDataHandlerStub.returns(consentData); + adapterManagerStub.withArgs('analyticsAdapter_A').returns({ gvlid: 3 }); + adapterManagerStub.withArgs('analyticsAdapter_B').returns({ gvlid: 5 }); + adapterManagerStub.withArgs('analyticsAdapter_C').returns({ gvlid: 1 }); + + enableAnalyticsHook(nextFnSpy, MOCK_ANALYTICS_ADAPTER_CONFIG); + + // Assertions + expect(nextFnSpy.calledOnce).to.equal(true); + sinon.assert.calledWith(nextFnSpy, [{ + provider: 'analyticsAdapter_B', + options: {} + }, { + provider: 'analyticsAdapter_C', + options: {} + }]); + expect(logWarnSpy.calledOnce).to.equal(true); + }); + }); + + describe('validateRules', function () { + const createGdprRule = (purposeName = 'storage', enforcePurpose = true, enforceVendor = true, vendorExceptions = []) => ({ + purpose: purposeName, + enforcePurpose: enforcePurpose, + enforceVendor: enforceVendor, + vendorExceptions: vendorExceptions + }); + + const consentData = { + vendorData: staticConfig.consentData.getTCData, + apiVersion: 2, + gdprApplies: true + }; + + // Bidder - 'bidderA' has vendorConsent + const vendorAllowedModule = 'bidderA'; + const vendorAllowedGvlId = 1; + + // Bidder = 'bidderB' doesn't have vendorConsent + const vendorBlockedModule = 'bidderB'; + const vendorBlockedGvlId = 3; + + const consentDataWithPurposeConsentFalse = utils.deepClone(consentData); + consentDataWithPurposeConsentFalse.vendorData.purpose.consents['1'] = false; + + it('should return true when enforcePurpose=true AND purposeConsent[p]==true AND enforceVendor[p,v]==true AND vendorConsent[v]==true', function () { + // 'enforcePurpose' and 'enforceVendor' both are 'true' + const gdprRule = createGdprRule('storage', true, true, []); + + // case 1 - Both purpose consent and vendor consent is 'true'. validateRules must return 'true' + let isAllowed = validateRules(gdprRule, consentData, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(true); + + // case 2 - Purpose consent is 'true' but vendor consent is 'false'. validateRules must return 'false' + isAllowed = validateRules(gdprRule, consentData, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(false); + + // case 3 - Purpose consent is 'false' but vendor consent is 'true'. validateRules must return 'false' + isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(false); + + // case 4 - Both purpose consent and vendor consent is 'false'. validateRules must return 'false' + isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(false); + }); + + it('should return true when enforcePurpose=true AND purposeConsent[p]==true AND enforceVendor[p,v]==false', function () { + // 'enforcePurpose' is 'true' and 'enforceVendor' is 'false' + const gdprRule = createGdprRule('storage', true, false, []); + + // case 1 - Both purpose consent and vendor consent is 'true'. validateRules must return 'true' + let isAllowed = validateRules(gdprRule, consentData, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(true); + + // case 2 - Purpose consent is 'true' but vendor consent is 'false'. validateRules must return 'true' because vendorConsent doens't matter + isAllowed = validateRules(gdprRule, consentData, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(true); + + // case 3 - Purpose consent is 'false' but vendor consent is 'true'. validateRules must return 'false' because vendorConsent doesn't matter + isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(false); + + // case 4 - Both purpose consent and vendor consent is 'false'. validateRules must return 'false' and vendorConsent doesn't matter + isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorBlockedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(false); + }); + + it('should return true when enforcePurpose=false AND enforceVendor[p,v]==true AND vendorConsent[v]==true', function () { + // 'enforcePurpose' is 'false' and 'enforceVendor' is 'true' + const gdprRule = createGdprRule('storage', false, true, []); + + // case 1 - Both purpose consent and vendor consent is 'true'. validateRules must return 'true' + let isAllowed = validateRules(gdprRule, consentData, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(true); + + // case 2 - Purpose consent is 'true' but vendor consent is 'false'. validateRules must return 'false' because purposeConsent doesn't matter + isAllowed = validateRules(gdprRule, consentData, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(false); + + // case 3 - urpose consent is 'false' but vendor consent is 'true'. validateRules must return 'true' because purposeConsent doesn't matter + isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(true); + + // case 4 - Both purpose consent and vendor consent is 'false'. validateRules must return 'false' and purposeConsent doesn't matter + isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(false); + }); + + it('should return true when enforcePurpose=false AND enforceVendor[p,v]==false', function () { + // 'enforcePurpose' is 'false' and 'enforceVendor' is 'false' + const gdprRule = createGdprRule('storage', false, false, []); + + // case 1 - Both purpose consent and vendor consent is 'true'. validateRules must return 'true', both the consents do not matter. + let isAllowed = validateRules(gdprRule, consentData, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(true); + + // case 2 - Purpose consent is 'true' but vendor consent is 'false'. validateRules must return 'true', both the consents do not matter. + isAllowed = validateRules(gdprRule, consentData, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(true); + + // case 3 - urpose consent is 'false' but vendor consent is 'true'. validateRules must return 'true', both the consents do not matter. + isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(true); + + // case 4 - Both purpose consent and vendor consent is 'false'. validateRules must return 'true', both the consents do not matter. + isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(true); + }); + + it('should return true when "vendorExceptions" contains the name of the vendor under test', function () { + // 'vendorExceptions' contains 'bidderB' which doesn't have vendor consent. + const gdprRule = createGdprRule('storage', false, true, [vendorBlockedModule]); + + /* 'bidderB' gets a free pass since it's included in the 'vendorExceptions' array. validateRules must disregard + user's choice for purpose and vendor consent and return 'true' for this bidder(s) */ + const isAllowed = validateRules(gdprRule, consentData, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(true); + }); + + describe('Purpose 2 special case', function () { + const consentDataWithLIFalse = utils.deepClone(consentData); + consentDataWithLIFalse.vendorData.purpose.legitimateInterests['2'] = false; + + const consentDataWithPurposeConsentFalse = utils.deepClone(consentData); + consentDataWithPurposeConsentFalse.vendorData.purpose.consents['2'] = false; + + const consentDataWithPurposeConsentFalseAndLIFalse = utils.deepClone(consentData); + consentDataWithPurposeConsentFalseAndLIFalse.vendorData.purpose.legitimateInterests['2'] = false; + consentDataWithPurposeConsentFalseAndLIFalse.vendorData.purpose.consents['2'] = false; + + it('should return true when (enforcePurpose=true AND purposeConsent[p]===true AND enforceVendor[p.v]===true AND vendorConsent[v]===true) OR (purposesLITransparency[p]===true)', function () { + // both 'enforcePurpose' and 'enforceVendor' is 'true' + const gdprRule = createGdprRule('basicAds', true, true, []); + + // case 1 - Both purpose consent and vendor consent is 'true', but legitimateInterests for purpose 2 is 'false'. validateRules must return 'true'. + let isAllowed = validateRules(gdprRule, consentDataWithLIFalse, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(true); + + // case 2 - Purpose consent is 'true' but vendor consent is 'false', but legitimateInterests for purpose 2 is 'true'. validateRules must return 'true'. + isAllowed = validateRules(gdprRule, consentData, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(true); + + // case 3 - Purpose consent is 'true' and vendor consent is 'true', as well as legitimateInterests for purpose 2 is 'true'. validateRules must return 'true'. + isAllowed = validateRules(gdprRule, consentData, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(true); + + // case 4 - Purpose consent is 'true' and vendor consent is 'false', and legitimateInterests for purpose 2 is 'false'. validateRules must return 'false'. + isAllowed = validateRules(gdprRule, consentDataWithLIFalse, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(false); + }); + + it('should return true when (enforcePurpose=true AND purposeConsent[p]===true AND enforceVendor[p.v]===false) OR (purposesLITransparency[p]===true)', function () { + // 'enforcePurpose' is 'true' and 'enforceVendor' is 'false' + const gdprRule = createGdprRule('basicAds', true, false, []); + + // case 1 - Purpose consent is 'true', vendor consent doesn't matter and legitimateInterests for purpose 2 is 'true'. validateRules must return 'true'. + let isAllowed = validateRules(gdprRule, consentData, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(true); + + // case 2 - Purpose consent is 'false', vendor consent doesn't matter and legitimateInterests for purpose 2 is 'true'. validateRules must return 'true'. + isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalse, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(true); + + // case 3 - Purpose consent is 'false', vendor consent doesn't matter and legitimateInterests for purpose 2 is 'false'. validateRules must return 'false'. + isAllowed = validateRules(gdprRule, consentDataWithPurposeConsentFalseAndLIFalse, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(false); + }); + + it('should return true when (enforcePurpose=false AND enforceVendor[p,v]===true AND vendorConsent[v]===true) OR (purposesLITransparency[p]===true)', function () { + // 'enforcePurpose' is 'false' and 'enforceVendor' is 'true' + const gdprRule = createGdprRule('basicAds', false, true, []); + + // case - 1 Vendor consent is 'true', purpose consent doesn't matter and legitimateInterests for purpose 2 is 'true'. validateRules must return 'true'. + let isAllowed = validateRules(gdprRule, consentData, vendorAllowedModule, vendorAllowedGvlId); + expect(isAllowed).to.equal(true); + + // case 2 - Vendor consent is 'false', purpose consent doesn't matter and legitimateInterests for purpose 2 is 'true'. validateRules must return 'true'. + isAllowed = validateRules(gdprRule, consentData, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(true); + + // case 3 - Vendor consent is 'false', purpose consent doesn't matter and legitimateInterests for purpose 2 is 'false'. validateRules must return 'false'. + isAllowed = validateRules(gdprRule, consentDataWithLIFalse, vendorBlockedModule, vendorBlockedGvlId); + expect(isAllowed).to.equal(false); + }); + }); + }) + + describe('setEnforcementConfig', function () { + let sandbox; + const DEFAULT_RULES = [{ + purpose: 'storage', + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: [] + }, { + purpose: 'basicAds', + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: [] + }]; + beforeEach(function () { + sandbox = sinon.createSandbox(); + logWarnSpy = sandbox.spy(utils, 'logWarn'); + }); + afterEach(function () { + config.resetConfig(); + sandbox.restore(); + }); + + it('should enforce TCF2 Purpose1 and Purpose 2 if no "rules" found in the config', function () { + setEnforcementConfig({ + gdpr: { + cmpApi: 'iab', + allowAuctionWithoutConsent: true, + timeout: 5000 + } + }); + + expect(logWarnSpy.calledOnce).to.equal(true); + expect(enforcementRules).to.deep.equal(DEFAULT_RULES); + }); + + it('should enforce TCF2 Purpose 2 also if only Purpose 1 is defined in "rules"', function () { + const purpose1RuleDefinedInConfig = { + purpose: 'storage', + enforcePurpose: false, + enforceVendor: true, + vendorExceptions: ['bidderA'] + } + setEnforcementConfig({ + gdpr: { + rules: [purpose1RuleDefinedInConfig] + } + }); + + expect(purpose1Rule).to.deep.equal(purpose1RuleDefinedInConfig); + expect(purpose2Rule).to.deep.equal(DEFAULT_RULES[1]); + }); + + it('should enforce TCF2 Purpose 1 also if only Purpose 2 is defined in "rules"', function () { + const purpose2RuleDefinedInConfig = { + purpose: 'basicAds', + enforcePurpose: false, + enforceVendor: true, + vendorExceptions: ['bidderA'] + } + setEnforcementConfig({ + gdpr: { + rules: [purpose2RuleDefinedInConfig] + } + }); + + expect(purpose1Rule).to.deep.equal(DEFAULT_RULES[0]); + expect(purpose2Rule).to.deep.equal(purpose2RuleDefinedInConfig); + }); + + it('should use the "rules" defined in config if a definition found', function() { + const rules = [{ + purpose: 'storage', + enforcePurpose: false, + enforceVendor: false + }, { + purpose: 'basicAds', + enforcePurpose: false, + enforceVendor: false + }] + setEnforcementConfig({gdpr: { rules }}); + + expect(enforcementRules).to.deep.equal(rules); + }); + }); + + describe('TCF2FinalResults', function() { + let sandbox; + beforeEach(function() { + sandbox = sinon.createSandbox(); + sandbox.spy(events, 'emit'); + }); + afterEach(function() { + config.resetConfig(); + sandbox.restore(); + }); + it('should emit TCF2 enforcement data on auction end', function() { + const rules = [{ + purpose: 'storage', + enforcePurpose: false, + enforceVendor: false + }, { + purpose: 'basicAds', + enforcePurpose: false, + enforceVendor: false + }] + setEnforcementConfig({gdpr: { rules }}); + + events.emit('auctionEnd', {}) + + // Assertions + sinon.assert.calledWith(events.emit.getCall(1), 'tcf2Enforcement', sinon.match.object); + }) + }); + + describe('getGvlid', function() { + let sandbox; + let getGvlidForBidAdapterStub; + let getGvlidForUserIdModuleStub; + let getGvlidForAnalyticsAdapterStub; + beforeEach(function() { + sandbox = sinon.createSandbox(); + getGvlidForBidAdapterStub = sandbox.stub(internal, 'getGvlidForBidAdapter'); + getGvlidForUserIdModuleStub = sandbox.stub(internal, 'getGvlidForUserIdModule'); + getGvlidForAnalyticsAdapterStub = sandbox.stub(internal, 'getGvlidForAnalyticsAdapter'); + }); + afterEach(function() { + sandbox.restore(); + config.resetConfig(); + }); + + it('should return "null" if called without passing any argument', function() { + const gvlid = getGvlid(); + expect(gvlid).to.equal(null); + }); + + it('should return "null" if GVL ID is not defined for any of these modules: Bid adapter, UserId submodule and Analytics adapter', function() { + getGvlidForBidAdapterStub.withArgs('moduleA').returns(null); + getGvlidForUserIdModuleStub.withArgs('moduleA').returns(null); + getGvlidForAnalyticsAdapterStub.withArgs('moduleA').returns(null); + + const gvlid = getGvlid('moduleA'); + expect(gvlid).to.equal(null); + }); + + it('should return the GVL ID from gvlMapping if it is defined in setConfig', function() { + config.setConfig({ + gvlMapping: { + moduleA: 1 + } + }); + + // Actual GVL ID for moduleA is 2, as defined on its the bidAdapter.js file. + getGvlidForBidAdapterStub.withArgs('moduleA').returns(2); + + const gvlid = getGvlid('moduleA'); + expect(gvlid).to.equal(1); + }); + + it('should return the GVL ID by calling getGvlidForBidAdapter -> getGvlidForUserIdModule -> getGvlidForAnalyticsAdapter in sequence', function() { + getGvlidForBidAdapterStub.withArgs('moduleA').returns(null); + getGvlidForUserIdModuleStub.withArgs('moduleA').returns(null); + getGvlidForAnalyticsAdapterStub.withArgs('moduleA').returns(7); + + expect(getGvlid('moduleA')).to.equal(7); }); }); }); diff --git a/test/spec/modules/gjirafaBidAdapter_spec.js b/test/spec/modules/gjirafaBidAdapter_spec.js new file mode 100644 index 00000000000..db9b82e0a10 --- /dev/null +++ b/test/spec/modules/gjirafaBidAdapter_spec.js @@ -0,0 +1,146 @@ +import { expect } from 'chai'; +import { spec } from 'modules/gjirafaBidAdapter'; + +describe('gjirafaAdapterTest', () => { + describe('bidRequestValidity', () => { + it('bidRequest with propertyId and placementId', () => { + expect(spec.isBidRequestValid({ + bidder: 'gjirafa', + params: { + propertyId: '{propertyId}', + placementId: '{placementId}' + } + })).to.equal(true); + }); + + it('bidRequest without propertyId', () => { + expect(spec.isBidRequestValid({ + bidder: 'gjirafa', + params: { + placementId: '{placementId}' + } + })).to.equal(false); + }); + + it('bidRequest without placementId', () => { + expect(spec.isBidRequestValid({ + bidder: 'gjirafa', + params: { + propertyId: '{propertyId}', + } + })).to.equal(false); + }); + + it('bidRequest without propertyId or placementId', () => { + expect(spec.isBidRequestValid({ + bidder: 'gjirafa', + params: { + propertyId: '{propertyId}', + } + })).to.equal(false); + }); + }); + + describe('bidRequest', () => { + const bidRequests = [{ + 'bidder': 'gjirafa', + 'params': { + 'propertyId': '{propertyId}', + 'placementId': '{placementId}' + }, + 'adUnitCode': 'hb-leaderboard', + 'transactionId': 'b6b889bb-776c-48fd-bc7b-d11a1cf0425e', + 'sizes': [[728, 90]], + 'bidId': '10bdc36fe0b48c8', + 'bidderRequestId': '70deaff71c281d', + 'auctionId': 'f9012acc-b6b7-4748-9098-97252914f9dc' + }]; + + it('bidRequest HTTP method', () => { + const requests = spec.buildRequests(bidRequests); + requests.forEach(function (requestItem) { + expect(requestItem.method).to.equal('POST'); + }); + }); + + it('bidRequest url', () => { + const endpointUrl = 'https://central.gjirafa.com/bid'; + const requests = spec.buildRequests(bidRequests); + requests.forEach(function (requestItem) { + expect(requestItem.url).to.match(new RegExp(`${endpointUrl}`)); + }); + }); + + it('bidRequest data', () => { + const requests = spec.buildRequests(bidRequests); + requests.forEach(function (requestItem) { + expect(requestItem.data).to.exist; + }); + }); + + it('bidRequest sizes', () => { + const requests = spec.buildRequests(bidRequests); + requests.forEach(function (requestItem) { + expect(requestItem.data.placements).to.exist; + expect(requestItem.data.placements.length).to.equal(1); + expect(requestItem.data.placements[0].sizes).to.equal('728x90'); + }); + }); + }); + + describe('interpretResponse', () => { + const bidRequest = { + 'method': 'POST', + 'url': 'https://central.gjirafa.com/bid', + 'data': { + 'sizes': '728x90', + 'adUnitId': 'hb-leaderboard', + 'placementId': '{placementId}', + 'propertyId': '{propertyId}', + 'pageViewGuid': '{pageViewGuid}', + 'url': 'http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true', + 'requestid': '26ee8fe87940da7', + 'bidid': '2962dbedc4768bf' + } + }; + + const bidResponse = { + body: [{ + 'CPM': 1, + 'Width': 728, + 'Height': 90, + 'Referrer': 'http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true', + 'Ad': '
Test ad
', + 'CreativeId': '123abc', + 'NetRevenue': false, + 'Currency': 'EUR', + 'TTL': 360 + }], + headers: {} + }; + + it('all keys present', () => { + const result = spec.interpretResponse(bidResponse, bidRequest); + + let keys = [ + 'requestId', + 'cpm', + 'width', + 'height', + 'creativeId', + 'currency', + 'netRevenue', + 'ttl', + 'referrer', + 'ad', + 'vastUrl', + 'mediaType' + ]; + + let resultKeys = Object.keys(result[0]); + resultKeys.forEach(function (key) { + expect(keys.indexOf(key) !== -1).to.equal(true); + }); + }) + }); +}); diff --git a/test/spec/modules/glimpseBidAdapter_spec.js b/test/spec/modules/glimpseBidAdapter_spec.js new file mode 100644 index 00000000000..cc11efcb2af --- /dev/null +++ b/test/spec/modules/glimpseBidAdapter_spec.js @@ -0,0 +1,179 @@ +import { expect } from 'chai'; +import { spec } from 'modules/glimpseBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; + +/** + * Test Helpers + */ + +const API = 'https://api.glimpseprotocol.io/cloud/v1/vault/prebid'; + +const templateBidRequest = { + bidder: 'glimpse', + params: { + placementId: 'glimpse-demo-300x250', + }, + adUnitCode: 'banner-div-a', + sizes: [[300, 250]], + bidId: '26a80b71cfd671', + bidderRequestId: '133baeded6ac94', + auctionId: '96692a73-307b-44b8-8e4f-ddfb40341570', +}; + +const templateBidderRequest = { + bidderCode: 'glimpse', + auctionId: '96692a73-307b-44b8-8e4f-ddfb40341570', + bidderRequestId: '133baeded6ac94', + timeout: 3000, + gdprConsent: { + apiVersion: 2, + consentString: + 'COzP517OzP517AcABBENAlCsAP_AAAAAAAwIF8NX-T5eL2vju2Zdt7JEaYwfZxyigOgThgQIsW8NwIeFbBoGP2EgHBG4JCQAGBAkkgCBAQMsHGBcCQAAgIgRiRKMYE2MjzNKBJJAigkbc0FACDVunsHS2ZCY70-8O__bPAviADAvUC-AAAAA.YAAAAAAAAAAA', + gdprApplies: true, + vendorData: {}, + }, + refererInfo: { + referer: 'https://demo.glimpseprotocol.io/prebid/desktop', + reachedTop: true, + numIframes: 0, + stack: ['https://demo.glimpseprotocol.io/prebid/desktop'], + }, +}; + +const templateBidResponse = { + ad: '
HelloWorld
', + adUnitCode: 'banner-div-a', + bidder: 'glimpse', + cpm: 1.04, + creativeId: 'glimpse-demo-300x250', + currency: 'GBP', + height: 250, + mediaType: 'banner', + netRevenue: true, + pbAg: '1.04', + pbDg: '1.04', + pbHg: '1.04', + pbLg: '1.00', + pbMg: '1.05', + requestId: '133baeded6ac94', + ttl: 60, + width: 300, +}; + +const copyBidResponse = () => ({ ...templateBidResponse }); +const copyBidderRequest = () => ({ ...templateBidderRequest, bids: copyBidRequests() }); +const copyBidRequest = () => ({ ...templateBidRequest }); + +const copyBidRequests = () => [copyBidRequest()]; +const copyBidResponses = () => ({ + body: [copyBidResponse()], +}); + +/** + * Tests + */ + +describe('GlimpseProtocolAdapter', function () { + const adapter = newBidder(spec); + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + expect(adapter.getSpec).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + it('should return true when params.placementId is valid', function () { + expect(spec.isBidRequestValid(templateBidRequest)).to.equal(true); + }); + + it('should return false when params.placementId is invalid', function () { + let bid = copyBidRequest(); + delete bid.params; + bid.params = { + placementId: 0, + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when params is not passed', function () { + let bid = copyBidRequest(); + delete bid.params; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when params.placementId is not passed', function () { + let bid = copyBidRequest(); + delete bid.params.placementId; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + const bidRequest = copyBidRequest(); + const bidRequests = [bidRequest]; + + it('should add version and source information', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + + expect(payload.sdk).to.exist; + expect(payload.sdk).to.deep.equal({ + source: 'pbjs', + version: '$prebid.version$', + }); + }); + + it('should send request to API via POST', function () { + const request = spec.buildRequests(bidRequests); + expect(request.url).to.equal(API); + expect(request.method).to.equal('POST'); + }); + + it('should add GDPR consent', function () { + const bidderRequest = copyBidderRequest(); + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.gdprConsent).to.exist; + const { gdprConsent } = payload; + expect(gdprConsent.gdprApplies).to.be.true; + expect(gdprConsent.consentString).to.equal(bidderRequest.gdprConsent.consentString); + }); + + it('should add referer info', function () { + const bidderRequest = copyBidderRequest(); + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.refererInfo.referer).to.equal(templateBidderRequest.refererInfo.referer); + }); + }); + + describe('interpretResponse', function () { + it('should handle valid bid responses', function () { + const response = copyBidResponses(); + + const bids = spec.interpretResponse(response); + expect(bids).to.have.length(1); + expect(bids[0].adUnitCode).to.equal(templateBidRequest.adUnitCode); + }); + + it('should handle no bid responses', function () { + const response = copyBidResponses(); + response.body = []; + + const bids = spec.interpretResponse(response); + expect(bids).to.have.length(0); + }); + + it('should return no bid on an invalid response', function () { + const response = copyBidResponses(); + delete response.body; + + const bids = spec.interpretResponse(response); + expect(bids).to.have.length(0); + }); + }); +}); diff --git a/test/spec/modules/gmosspBidAdapter_spec.js b/test/spec/modules/gmosspBidAdapter_spec.js new file mode 100644 index 00000000000..5de3db623c5 --- /dev/null +++ b/test/spec/modules/gmosspBidAdapter_spec.js @@ -0,0 +1,162 @@ +import { expect } from 'chai'; +import { spec } from 'modules/gmosspBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import * as utils from 'src/utils.js'; + +const ENDPOINT = 'https://sp.gmossp-sp.jp/hb/prebid/query.ad'; + +describe('GmosspAdapter', function () { + const adapter = newBidder(spec); + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + let bid = { + bidder: 'gmossp', + params: { + sid: '123456' + } + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', function () { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + const bidRequests = [ + { + bidder: 'gmossp', + params: { + sid: '123456' + }, + adUnitCode: 'adunit-code', + sizes: [ + [300, 250], + [320, 50], + [320, 100], + ], + bidId: '2b84475b5b636e', + bidderRequestId: '1f4001782ac16c', + auctionId: 'aba03555-4802-4c45-9f15-05ffa8594cff', + transactionId: '791e9d84-af92-4903-94da-24c7426d9d0c' + } + ]; + + const bidderRequest = { + refererInfo: { + referer: 'https://hoge.com' + } + }; + + it('sends bid request to ENDPOINT via GET', function () { + const requests = spec.buildRequests(bidRequests, bidderRequest); + expect(requests[0].url).to.equal(ENDPOINT); + expect(requests[0].method).to.equal('GET'); + expect(requests[0].data).to.equal('tid=791e9d84-af92-4903-94da-24c7426d9d0c&bid=2b84475b5b636e&ver=$prebid.version$&sid=123456&url=https%3A%2F%2Fhoge.com&cur=JPY&dnt=0&'); + }); + }); + + describe('interpretResponse', function () { + const bidderRequests = [ + { + bidder: 'gmossp', + params: { + sid: '123456' + }, + adUnitCode: 'adunit-code', + sizes: [ + [300, 250], + [320, 50], + [320, 100], + ], + bidId: '2b84475b5b636e', + bidderRequestId: '1f4001782ac16c', + auctionId: 'aba03555-4802-4c45-9f15-05ffa8594cff', + transactionId: '791e9d84-af92-4903-94da-24c7426d9d0c' + } + ]; + + it('should get correct banner bid response', function() { + const response = { + bid: '2b84475b5b636e', + price: 20, + w: 300, + h: 250, + ad: '
', + creativeId: '985ec572b32be309.76973017', + cur: 'JPY', + dealId: '', + imps: [ + 'https://sp.gmossp-sp.jp/hb/prebid/imp.ad' + ], + syncs: [ + 'https://sync.dsp.reemo-ad.jp' + ], + ttl: 300 + }; + + const expectedResponse = [ + { + requestId: '2b84475b5b636e', + cpm: 20, + currency: 'JPY', + width: 300, + height: 250, + ad: '
', + creativeId: '985ec572b32be309.76973017', + netRevenue: true, + ttl: 300 + } + ]; + + const result = spec.interpretResponse({ body: response }, bidderRequests); + expect(result).to.have.lengthOf(1); + + response.imps.forEach(impTracker => { + const tracker = utils.createTrackPixelHtml(impTracker); + expectedResponse[0].ad += tracker; + }); + + expect(result).to.deep.have.same.members(expectedResponse); + }); + + it('handles nobid responses', function () { + const response = ''; + + const result = spec.interpretResponse({ body: response }, bidderRequests); + expect(result.length).to.equal(0); + }); + }); + + describe('getUserSyncs', function () { + const bidResponse = { + body: { + ad: {}, + syncs: [ + 'https://hoge.com' + ] + } + }; + it('should return returns pixel syncs', function () { + const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: true }, [bidResponse]); + expect(syncs).to.deep.equal([ + { + type: 'image', + url: 'https://hoge.com' + } + ]) + }) + }); +}); diff --git a/test/spec/modules/gptPreAuction_spec.js b/test/spec/modules/gptPreAuction_spec.js new file mode 100644 index 00000000000..16b84467af2 --- /dev/null +++ b/test/spec/modules/gptPreAuction_spec.js @@ -0,0 +1,191 @@ +import { + appendGptSlots, + appendPbAdSlot, + _currentConfig, + makeBidRequestsHook +} from 'modules/gptPreAuction.js'; +import { config } from 'src/config.js'; +import { makeSlot } from '../integration/faker/googletag.js'; + +describe('GPT pre-auction module', () => { + let sandbox; + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + afterEach(() => { + sandbox.restore(); + config.setConfig({ gptPreAuction: { enabled: false } }); + }); + + const testSlots = [ + makeSlot({ code: 'slotCode1', divId: 'div1' }), + makeSlot({ code: 'slotCode2', divId: 'div2' }), + makeSlot({ code: 'slotCode3', divId: 'div3' }) + ]; + + describe('appendPbAdSlot', () => { + // sets up our document body to test the pbAdSlot dom actions against + document.body.innerHTML = '
test1
' + + '
test2
' + + '
test2
'; + + it('should be unchanged if already defined on adUnit', () => { + const adUnit = { fpd: { context: { pbAdSlot: '12345' } } }; + appendPbAdSlot(adUnit); + expect(adUnit.fpd.context.pbAdSlot).to.equal('12345'); + }); + + it('should use adUnit.code if matching id exists', () => { + const adUnit = { code: 'foo1', fpd: { context: {} } }; + appendPbAdSlot(adUnit); + expect(adUnit.fpd.context.pbAdSlot).to.equal('bar1'); + }); + + it('should use the gptSlot.adUnitPath if the adUnit.code matches a div id but does not have a data-adslotid', () => { + const adUnit = { code: 'foo3', mediaTypes: { banner: { sizes: [[250, 250]] } }, fpd: { context: { adServer: { name: 'gam', adSlot: '/baz' } } } }; + appendPbAdSlot(adUnit); + expect(adUnit.fpd.context.pbAdSlot).to.equal('/baz'); + }); + + it('should use the video adUnit.code (which *should* match the configured "adSlotName", but is not being tested) if there is no matching div with "data-adslotid" defined', () => { + const adUnit = { code: 'foo4', mediaTypes: { video: { sizes: [[250, 250]] } }, fpd: { context: {} } }; + adUnit.code = 'foo5'; + appendPbAdSlot(adUnit, undefined); + expect(adUnit.fpd.context.pbAdSlot).to.equal('foo5'); + }); + + it('should use the adUnit.code if all other sources failed', () => { + const adUnit = { code: 'foo4', fpd: { context: {} } }; + appendPbAdSlot(adUnit, undefined); + expect(adUnit.fpd.context.pbAdSlot).to.equal('foo4'); + }); + + it('should use the customPbAdSlot function if one is given', () => { + config.setConfig({ + gptPreAuction: { + customPbAdSlot: () => 'customPbAdSlotName' + } + }); + + const adUnit = { code: 'foo1', fpd: { context: {} } }; + appendPbAdSlot(adUnit); + expect(adUnit.fpd.context.pbAdSlot).to.equal('customPbAdSlotName'); + }); + }); + + describe('appendGptSlots', () => { + it('should not add adServer object to context if no slots defined', () => { + const adUnit = { code: 'adUnitCode', fpd: { context: {} } }; + appendGptSlots([adUnit]); + expect(adUnit.fpd.context.adServer).to.be.undefined; + }); + + it('should not add adServer object to context if no slot matches', () => { + window.googletag.pubads().setSlots(testSlots); + const adUnit = { code: 'adUnitCode', fpd: { context: {} } }; + appendGptSlots([adUnit]); + expect(adUnit.fpd.context.adServer).to.be.undefined; + }); + + it('should add adServer object to context if matching slot is found', () => { + window.googletag.pubads().setSlots(testSlots); + const adUnit = { code: 'slotCode2', fpd: { context: {} } }; + appendGptSlots([adUnit]); + expect(adUnit.fpd.context.adServer).to.be.an('object'); + expect(adUnit.fpd.context.adServer).to.deep.equal({ name: 'gam', adSlot: 'slotCode2' }); + }); + + it('should use the customGptSlotMatching function if one is given', () => { + config.setConfig({ + gptPreAuction: { + customGptSlotMatching: slot => + adUnitCode => adUnitCode.toUpperCase() === slot.getAdUnitPath().toUpperCase() + } + }); + + window.googletag.pubads().setSlots(testSlots); + const adUnit = { code: 'SlOtCoDe1', fpd: { context: {} } }; + appendGptSlots([adUnit]); + expect(adUnit.fpd.context.adServer).to.be.an('object'); + expect(adUnit.fpd.context.adServer).to.deep.equal({ name: 'gam', adSlot: 'slotCode1' }); + }); + }); + + describe('handleSetGptConfig', () => { + it('should enable the module by default', () => { + config.setConfig({ gptPreAuction: {} }); + expect(_currentConfig.enabled).to.equal(true); + }); + + it('should disable the module if told to in set config', () => { + config.setConfig({ gptPreAuction: { enabled: false } }); + expect(_currentConfig).to.be.an('object').that.is.empty; + }); + + it('should accept custom functions in config', () => { + config.setConfig({ + gptPreAuction: { + customGptSlotMatching: () => 'customGptSlot', + customPbAdSlot: () => 'customPbAdSlot' + } + }); + + expect(_currentConfig.enabled).to.equal(true); + expect(_currentConfig.customGptSlotMatching).to.a('function'); + expect(_currentConfig.customPbAdSlot).to.a('function'); + expect(_currentConfig.customGptSlotMatching()).to.equal('customGptSlot'); + expect(_currentConfig.customPbAdSlot()).to.equal('customPbAdSlot'); + }); + + it('should check that custom functions in config are type function', () => { + config.setConfig({ + gptPreAuction: { + customGptSlotMatching: 12345, + customPbAdSlot: 'test' + } + }); + expect(_currentConfig).to.deep.equal({ + enabled: true, + customGptSlotMatching: false, + customPbAdSlot: false + }); + }); + }); + + describe('makeBidRequestsHook', () => { + let returnedAdUnits; + const runMakeBidRequests = adUnits => { + const next = adUnits => { + returnedAdUnits = adUnits; + }; + makeBidRequestsHook(next, adUnits); + }; + + it('should append PB Ad Slot and GPT Slot info to first-party data in each ad unit', () => { + const testAdUnits = [{ + code: 'adUnit1', + fpd: { context: { pbAdSlot: '12345' } } + }, { + code: 'slotCode1', + fpd: { context: { pbAdSlot: '67890' } } + }, { + code: 'slotCode3', + }]; + + const expectedAdUnits = [{ + code: 'adUnit1', + fpd: { context: { pbAdSlot: '12345' } } + }, { + code: 'slotCode1', + fpd: { context: { pbAdSlot: '67890', adServer: { name: 'gam', adSlot: 'slotCode1' } } } + }, { + code: 'slotCode3', + fpd: { context: { pbAdSlot: 'slotCode3', adServer: { name: 'gam', adSlot: 'slotCode3' } } } + }]; + + window.googletag.pubads().setSlots(testSlots); + runMakeBidRequests(testAdUnits); + expect(returnedAdUnits).to.deep.equal(expectedAdUnits); + }); + }); +}); diff --git a/test/spec/modules/gridBidAdapter_spec.js b/test/spec/modules/gridBidAdapter_spec.js index 4f53d9dcb25..1cfca4779ad 100644 --- a/test/spec/modules/gridBidAdapter_spec.js +++ b/test/spec/modules/gridBidAdapter_spec.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { spec, resetUserSync, getSyncUrl } from 'modules/gridBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; +import { config } from 'src/config.js'; describe('TheMediaGrid Adapter', function () { const adapter = newBidder(spec); @@ -102,7 +103,7 @@ describe('TheMediaGrid Adapter', function () { ]; it('should attach valid params to the tag', function () { - const request = spec.buildRequests([bidRequests[0]], bidderRequest); + const [request] = spec.buildRequests([bidRequests[0]], bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('u', referrer); @@ -114,7 +115,7 @@ describe('TheMediaGrid Adapter', function () { }); it('sizes must be added from mediaTypes', function () { - const request = spec.buildRequests([bidRequests[0], bidRequests[1]], bidderRequest); + const [request] = spec.buildRequests([bidRequests[0], bidRequests[1]], bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('u', referrer); @@ -124,7 +125,7 @@ describe('TheMediaGrid Adapter', function () { }); it('sizes must not be duplicated', function () { - const request = spec.buildRequests(bidRequests, bidderRequest); + const [request] = spec.buildRequests(bidRequests, bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('u', referrer); @@ -134,7 +135,7 @@ describe('TheMediaGrid Adapter', function () { }); it('if gdprConsent is present payload must have gdpr params', function () { - const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: true}, refererInfo: bidderRequest.refererInfo}); + const [request] = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: true}, refererInfo: bidderRequest.refererInfo}); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('u', referrer); @@ -143,7 +144,7 @@ describe('TheMediaGrid Adapter', function () { }); it('if gdprApplies is false gdpr_applies must be 0', function () { - const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: false}}); + const [request] = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: false}}); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('gdpr_consent', 'AAA'); @@ -151,7 +152,7 @@ describe('TheMediaGrid Adapter', function () { }); it('if gdprApplies is undefined gdpr_applies must be 1', function () { - const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA'}}); + const [request] = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA'}}); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('gdpr_consent', 'AAA'); @@ -160,11 +161,451 @@ describe('TheMediaGrid Adapter', function () { it('if usPrivacy is present payload must have us_privacy param', function () { const bidderRequestWithUSP = Object.assign({uspConsent: '1YNN'}, bidderRequest); - const request = spec.buildRequests(bidRequests, bidderRequestWithUSP); + const [request] = spec.buildRequests(bidRequests, bidderRequestWithUSP); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('us_privacy', '1YNN'); }); + + it('should convert keyword params to proper form and attaches to request', function () { + const bidRequestWithKeywords = [].concat(bidRequests); + bidRequestWithKeywords[1] = Object.assign({}, + bidRequests[1], + { + params: { + uid: '1', + keywords: { + single: 'val', + singleArr: ['val'], + singleArrNum: [3], + multiValMixed: ['value1', 2, 'value3'], + singleValNum: 123, + emptyStr: '', + emptyArr: [''], + badValue: {'foo': 'bar'} // should be dropped + } + } + } + ); + + const [request] = spec.buildRequests(bidRequestWithKeywords, bidderRequest); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload.keywords).to.be.an('string'); + payload.keywords = JSON.parse(payload.keywords); + + expect(payload.keywords).to.deep.equal([{ + 'key': 'single', + 'value': ['val'] + }, { + 'key': 'singleArr', + 'value': ['val'] + }, { + 'key': 'singleArrNum', + 'value': ['3'] + }, { + 'key': 'multiValMixed', + 'value': ['value1', '2', 'value3'] + }, { + 'key': 'singleValNum', + 'value': ['123'] + }, { + 'key': 'emptyStr' + }, { + 'key': 'emptyArr' + }]); + }); + + it('should mix keyword param with keywords from config', function () { + const getConfigStub = sinon.stub(config, 'getConfig').callsFake( + arg => arg === 'fpd.user' ? {'keywords': ['a', 'b']} : arg === 'fpd.context' ? {'keywords': ['any words']} : null); + + const bidRequestWithKeywords = [].concat(bidRequests); + bidRequestWithKeywords[1] = Object.assign({}, + bidRequests[1], + { + params: { + uid: '1', + keywords: { + single: 'val', + singleArr: ['val'], + multiValMixed: ['value1', 2, 'value3'] + } + } + } + ); + + const [request] = spec.buildRequests(bidRequestWithKeywords, bidderRequest); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload.keywords).to.be.an('string'); + payload.keywords = JSON.parse(payload.keywords); + + expect(payload.keywords).to.deep.equal([{ + 'key': 'single', + 'value': ['val'] + }, { + 'key': 'singleArr', + 'value': ['val'] + }, { + 'key': 'multiValMixed', + 'value': ['value1', '2', 'value3'] + }, { + 'key': 'user', + 'value': ['a', 'b'] + }, { + 'key': 'context', + 'value': ['any words'] + }]); + + getConfigStub.restore(); + }); + }); + + describe('buildRequests in new format', function () { + function parseRequest(data) { + return JSON.parse(data); + } + const bidderRequest = { + refererInfo: {referer: 'https://example.com'}, + bidderRequestId: '22edbae2733bf6', + auctionId: '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + timeout: 3000 + }; + const referrer = encodeURIComponent(bidderRequest.refererInfo.referer); + let bidRequests = [ + { + 'bidder': 'grid', + 'params': { + 'uid': '1', + 'useNewFormat': true + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, + 'bidId': '42dbe3a7168a6a', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + }, + { + 'bidder': 'grid', + 'params': { + 'uid': '2', + 'useNewFormat': true + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + }, + { + 'bidder': 'grid', + 'params': { + 'uid': '11', + 'useNewFormat': true + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'mediaTypes': { + 'video': { + 'playerSize': [[400, 600]], + 'mimes': ['video/mp4', 'video/webm', 'application/javascript', 'video/ogg'] + } + }, + 'bidId': '3150ccb55da321', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + }, + { + 'bidder': 'grid', + 'params': { + 'uid': '3', + 'useNewFormat': true + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'mediaTypes': { + 'video': { + 'playerSize': [[400, 600]] + }, + 'banner': { + 'sizes': [[728, 90]] + } + }, + 'bidId': '3150ccb55da321', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '9e2dfbfe-00c7-4f5e-9850-4044df3229c7', + } + ]; + + it('should attach valid params to the tag', function () { + const [request] = spec.buildRequests([bidRequests[0]], bidderRequest); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.deep.equal({ + 'id': bidderRequest.bidderRequestId, + 'site': { + 'page': referrer + }, + 'tmax': bidderRequest.timeout, + 'source': { + 'tid': bidderRequest.auctionId, + 'ext': {'wrapper': 'Prebid_js', 'wrapper_version': '$prebid.version$'} + }, + 'imp': [{ + 'id': bidRequests[0].bidId, + 'tagid': bidRequests[0].params.uid, + 'ext': {'divid': bidRequests[0].adUnitCode}, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }] + }); + }); + + it('make possible to process request without mediaTypes', function () { + const [request] = spec.buildRequests([bidRequests[0], bidRequests[1]], bidderRequest); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.deep.equal({ + 'id': bidderRequest.bidderRequestId, + 'site': { + 'page': referrer + }, + 'tmax': bidderRequest.timeout, + 'source': { + 'tid': bidderRequest.auctionId, + 'ext': {'wrapper': 'Prebid_js', 'wrapper_version': '$prebid.version$'} + }, + 'imp': [{ + 'id': bidRequests[0].bidId, + 'tagid': bidRequests[0].params.uid, + 'ext': {'divid': bidRequests[0].adUnitCode}, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }, { + 'id': bidRequests[1].bidId, + 'tagid': bidRequests[1].params.uid, + 'ext': {'divid': bidRequests[1].adUnitCode}, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }] + }); + }); + + it('should attach valid params to the video tag', function () { + const [request] = spec.buildRequests(bidRequests.slice(0, 3), bidderRequest); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.deep.equal({ + 'id': bidderRequest.bidderRequestId, + 'site': { + 'page': referrer + }, + 'tmax': bidderRequest.timeout, + 'source': { + 'tid': bidderRequest.auctionId, + 'ext': {'wrapper': 'Prebid_js', 'wrapper_version': '$prebid.version$'} + }, + 'imp': [{ + 'id': bidRequests[0].bidId, + 'tagid': bidRequests[0].params.uid, + 'ext': {'divid': bidRequests[0].adUnitCode}, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }, { + 'id': bidRequests[1].bidId, + 'tagid': bidRequests[1].params.uid, + 'ext': {'divid': bidRequests[1].adUnitCode}, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }, { + 'id': bidRequests[2].bidId, + 'tagid': bidRequests[2].params.uid, + 'ext': {'divid': bidRequests[2].adUnitCode}, + 'video': { + 'w': 400, + 'h': 600, + 'mimes': ['video/mp4', 'video/webm', 'application/javascript', 'video/ogg'] + } + }] + }); + }); + + it('should support mixed mediaTypes', function () { + const [request] = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.deep.equal({ + 'id': bidderRequest.bidderRequestId, + 'site': { + 'page': referrer + }, + 'tmax': bidderRequest.timeout, + 'source': { + 'tid': bidderRequest.auctionId, + 'ext': {'wrapper': 'Prebid_js', 'wrapper_version': '$prebid.version$'} + }, + 'imp': [{ + 'id': bidRequests[0].bidId, + 'tagid': bidRequests[0].params.uid, + 'ext': {'divid': bidRequests[0].adUnitCode}, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }, { + 'id': bidRequests[1].bidId, + 'tagid': bidRequests[1].params.uid, + 'ext': {'divid': bidRequests[1].adUnitCode}, + 'banner': { + 'w': 300, + 'h': 250, + 'format': [{'w': 300, 'h': 250}, {'w': 300, 'h': 600}] + } + }, { + 'id': bidRequests[2].bidId, + 'tagid': bidRequests[2].params.uid, + 'ext': {'divid': bidRequests[2].adUnitCode}, + 'video': { + 'w': 400, + 'h': 600, + 'mimes': ['video/mp4', 'video/webm', 'application/javascript', 'video/ogg'], + } + }, { + 'id': bidRequests[3].bidId, + 'tagid': bidRequests[3].params.uid, + 'ext': {'divid': bidRequests[3].adUnitCode}, + 'banner': { + 'w': 728, + 'h': 90, + 'format': [{'w': 728, 'h': 90}] + }, + 'video': { + 'w': 400, + 'h': 600 + } + }] + }); + }); + + it('if gdprConsent is present payload must have gdpr params', function () { + const gdprBidderRequest = Object.assign({gdprConsent: {consentString: 'AAA', gdprApplies: true}}, bidderRequest); + const [request] = spec.buildRequests(bidRequests, gdprBidderRequest); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.have.property('user'); + expect(payload.user).to.have.property('ext'); + expect(payload.user.ext).to.have.property('consent', 'AAA'); + expect(payload).to.have.property('regs'); + expect(payload.regs).to.have.property('ext'); + expect(payload.regs.ext).to.have.property('gdpr', 1); + }); + + it('if usPrivacy is present payload must have us_privacy param', function () { + const bidderRequestWithUSP = Object.assign({uspConsent: '1YNN'}, bidderRequest); + const [request] = spec.buildRequests(bidRequests, bidderRequestWithUSP); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.have.property('regs'); + expect(payload.regs).to.have.property('ext'); + expect(payload.regs.ext).to.have.property('us_privacy', '1YNN'); + }); + + it('if userId is present payload must have user.ext param with right keys', function () { + const bidRequestsWithUserIds = bidRequests.map((bid) => { + return Object.assign({ + userId: { + id5id: { uid: 'id5id_1' }, + tdid: 'tdid_1', + digitrustid: {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}, + lipb: {lipbid: 'lipb_1'} + } + }, bid); + }); + const [request] = spec.buildRequests(bidRequestsWithUserIds, bidderRequest); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.have.property('user'); + expect(payload.user).to.have.property('ext'); + expect(payload.user.ext).to.have.property('unifiedid', 'tdid_1'); + expect(payload.user.ext).to.have.property('id5id', 'id5id_1'); + expect(payload.user.ext).to.have.property('digitrustid', 'DTID'); + expect(payload.user.ext).to.have.property('liveintentid', 'lipb_1'); + }); + + it('if schain is present payload must have source.ext.schain param', function () { + const schain = { + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + hp: 1 + } + ] + }; + const bidRequestsWithSChain = bidRequests.map((bid) => { + return Object.assign({ + schain: schain + }, bid); + }); + const [request] = spec.buildRequests(bidRequestsWithSChain, bidderRequest); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.have.property('source'); + expect(payload.source).to.have.property('ext'); + expect(payload.source.ext).to.have.property('schain'); + expect(payload.source.ext.schain).to.deep.equal(schain); + }); + + it('if content and segment is present in realTimeData.jwTargeting, payload must have right params', function () { + const jsContent = {id: 'test_jw_content_id'}; + const jsSegments = ['test_seg_1', 'test_seg_2']; + const bidRequestsWithUserIds = bidRequests.map((bid) => { + return Object.assign({ + realTimeData: { + jwTargeting: { + segments: jsSegments, + content: jsContent + } + } + }, bid); + }); + const [request] = spec.buildRequests(bidRequestsWithUserIds, bidderRequest); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.have.property('user'); + expect(payload.user.data).to.deep.equal([{ + name: 'iow_labs_pub_data', + segment: [ + {name: 'jwpseg', value: jsSegments[0]}, + {name: 'jwpseg', value: jsSegments[1]} + ] + }]); + expect(payload).to.have.property('site'); + expect(payload.site.content).to.deep.equal(jsContent); + }); }); describe('interpretResponse', function () { @@ -193,7 +634,7 @@ describe('TheMediaGrid Adapter', function () { 'auctionId': '1cbd2feafe5e8b', } ]; - const request = spec.buildRequests(bidRequests); + const [request] = spec.buildRequests(bidRequests); const expectedResponse = [ { 'requestId': '659423fff799cb', @@ -251,7 +692,7 @@ describe('TheMediaGrid Adapter', function () { 'auctionId': '1fa09aee5c8c99', } ]; - const request = spec.buildRequests(bidRequests); + const [request] = spec.buildRequests(bidRequests); const expectedResponse = [ { 'requestId': '300bfeb0d71a5b', @@ -340,7 +781,7 @@ describe('TheMediaGrid Adapter', function () { {'bid': [{'price': 1.15, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 11, content_type: 'video', w: 300, h: 600}], 'seat': '2'}, {'bid': [{'price': 1.00, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 12, content_type: 'video'}], 'seat': '2'} ]; - const request = spec.buildRequests(bidRequests); + const [request] = spec.buildRequests(bidRequests); const expectedResponse = [ { 'requestId': '659423fff799cb', @@ -401,7 +842,7 @@ describe('TheMediaGrid Adapter', function () { 'auctionId': '1fa09aee5c84d34', } ]; - const request = spec.buildRequests(bidRequests); + const [request] = spec.buildRequests(bidRequests); const result = spec.interpretResponse({'body': {'seatbid': responses.slice(2)}}, request); expect(result.length).to.equal(0); }); @@ -471,7 +912,7 @@ describe('TheMediaGrid Adapter', function () { 'auctionId': '32a1f276cb87cb8', } ]; - const request = spec.buildRequests(bidRequests); + const [request] = spec.buildRequests(bidRequests); const expectedResponse = [ { 'requestId': '2164be6358b9', @@ -575,7 +1016,7 @@ describe('TheMediaGrid Adapter', function () { 'auctionId': '35bcbc0f7e79c', } ]; - const request = spec.buildRequests(bidRequests); + const [request] = spec.buildRequests(bidRequests); const expectedResponse = [ { 'requestId': '5126e301f4be', diff --git a/test/spec/modules/gumgumBidAdapter_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js index a2fbc2cf029..701ce9a7e81 100644 --- a/test/spec/modules/gumgumBidAdapter_spec.js +++ b/test/spec/modules/gumgumBidAdapter_spec.js @@ -3,6 +3,7 @@ import { newBidder } from 'src/adapters/bidderFactory.js'; import { spec } from 'modules/gumgumBidAdapter.js'; const ENDPOINT = 'https://g2.gumgum.com/hbid/imp'; +const JCSI = { t: 0, rq: 8, pbv: '$prebid.version$' } describe('gumgumAdapter', function () { const adapter = newBidder(spec); @@ -32,7 +33,11 @@ describe('gumgumAdapter', function () { }; it('should return true when required params found', function () { + const zoneBid = { ...bid, params: { 'zone': '123' } }; + const pubIdBid = { ...bid, params: { 'pubId': '123' } }; expect(spec.isBidRequestValid(bid)).to.equal(true); + expect(spec.isBidRequestValid(zoneBid)).to.equal(true); + expect(spec.isBidRequestValid(pubIdBid)).to.equal(true); }); it('should return true when required params found', function () { @@ -45,6 +50,17 @@ describe('gumgumAdapter', function () { expect(spec.isBidRequestValid(bid)).to.equal(true); }); + it('should return true when inslot sends sizes and trackingid', function () { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + 'inSlot': '789', + 'sizes': [[0, 1], [2, 3], [4, 5], [6, 7]] + }; + + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + it('should return false when no unit type is specified', function () { let bid = Object.assign({}, bid); delete bid.params; @@ -63,9 +79,24 @@ describe('gumgumAdapter', function () { }; expect(spec.isBidRequestValid(bid)).to.equal(false); }); + + it('should return false if invalid request id is found', function () { + const bidRequest = { + id: 12345, + sizes: [[300, 250], [1, 1]], + url: ENDPOINT, + method: 'GET', + pi: 3, + data: { t: '10433394' } + }; + let body; + spec.interpretResponse({ body }, bidRequest); // empty response + expect(spec.isBidRequestValid(bid)).to.be.equal(false); + }); }); describe('buildRequests', function () { + let sizesArray = [[300, 250], [300, 600]]; let bidRequests = [ { 'bidder': 'gumgum', @@ -73,7 +104,7 @@ describe('gumgumAdapter', function () { 'inSlot': '9' }, 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250], [300, 600]], + 'sizes': sizesArray, 'bidId': '30b31c1838de1e', 'schain': { 'ver': '1.0', @@ -99,6 +130,109 @@ describe('gumgumAdapter', function () { } } ]; + const vidMediaTypes = { + video: { + playerSize: [640, 480], + context: 'instream', + minduration: 1, + maxduration: 2, + linearity: 1, + startdelay: 1, + placement: 123456, + protocols: [1, 2] + } + }; + + describe('zone param', function () { + const zoneParam = { 'zone': '123a' }; + + it('should set t and pi param', function () { + const request = { ...bidRequests[0], params: zoneParam }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.t).to.equal(zoneParam.zone); + expect(bidRequest.data.pi).to.equal(2); + }); + it('should set the correct pi param if slot param is found', function () { + const request = { ...bidRequests[0], params: { ...zoneParam, 'slot': 1 } }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.pi).to.equal(3); + }); + it('should set the correct pi param if native param is found', function () { + const request = { ...bidRequests[0], params: { ...zoneParam, 'native': 2 } }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.pi).to.equal(5); + }); + it('should set the correct pi param for video', function () { + const request = { ...bidRequests[0], params: zoneParam, mediaTypes: vidMediaTypes }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.pi).to.equal(7); + }); + it('should set the correct pi param for invideo', function () { + const invideo = { video: { ...vidMediaTypes.video, linearity: 2 } }; + const request = { ...bidRequests[0], params: zoneParam, mediaTypes: invideo }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.pi).to.equal(6); + }); + }); + + describe('pubId zone', function () { + const pubIdParam = { 'pubId': 'abc' }; + + it('should set t param', function () { + const request = { ...bidRequests[0], params: pubIdParam }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.pubId).to.equal(pubIdParam.pubId); + }); + + it('should set the correct pi depending on what is found in mediaTypes', function () { + const request = { ...bidRequests[0], params: pubIdParam }; + const bidRequest = spec.buildRequests([request])[0]; + const vidRequest = { ...bidRequests[0], mediaTypes: vidMediaTypes, params: { 'videoPubID': 123 } }; + const vidBidRequest = spec.buildRequests([vidRequest])[0]; + + expect(bidRequest.data.pi).to.equal(2); + expect(vidBidRequest.data.pi).to.equal(7); + }); + }); + + it('should return a defined sizes field for video', function () { + const request = { ...bidRequests[0], mediaTypes: vidMediaTypes, params: { 'videoPubID': 123 } }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.sizes).to.equal(vidMediaTypes.video.playerSize); + }); + it('should handle multiple sizes for inslot', function () { + const mediaTypes = { banner: { sizes: [[300, 250], [300, 600]] } } + const request = { ...bidRequests[0], mediaTypes }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.bf).to.equal('300x250,300x600'); + }); + describe('floorModule', function () { + const floorTestData = { + 'currency': 'USD', + 'floor': 1.50 + }; + bidRequests[0].getFloor = _ => { + return floorTestData; + }; + it('should return the value from getFloor if present', function () { + const request = spec.buildRequests(bidRequests)[0]; + expect(request.data.fp).to.equal(floorTestData.floor); + }); + it('should return the getFloor.floor value if it is greater than bidfloor', function () { + const bidfloor = 0.80; + const request = { ...bidRequests[0] }; + request.params.bidfloor = bidfloor; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.fp).to.equal(floorTestData.floor); + }); + it('should return the bidfloor value if it is greater than getFloor.floor', function () { + const bidfloor = 1.80; + const request = { ...bidRequests[0] }; + request.params.bidfloor = bidfloor; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.fp).to.equal(bidfloor); + }); + }); it('sends bid request to ENDPOINT via GET', function () { const request = spec.buildRequests(bidRequests)[0]; @@ -118,6 +252,25 @@ describe('gumgumAdapter', function () { expect(bidRequest.data).to.include.any.keys('t'); expect(bidRequest.data).to.include.any.keys('fp'); }); + it('should set iriscat parameter if iriscat param is found and is of type string', function () { + const iriscat = 'segment'; + const request = { ...bidRequests[0] }; + request.params = { ...request.params, iriscat }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.iriscat).to.equal(iriscat); + }); + it('should not send iriscat parameter if iriscat param is not found', function () { + const request = { ...bidRequests[0] }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.iriscat).to.be.undefined; + }); + it('should not send iriscat parameter if iriscat param is not of type string', function () { + const iriscat = 123; + const request = { ...bidRequests[0] }; + request.params = { ...request.params, iriscat }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data.iriscat).to.be.undefined; + }); it('should send pubId if inScreenPubID param is specified', function () { const request = Object.assign({}, bidRequests[0]); delete request.params; @@ -129,6 +282,13 @@ describe('gumgumAdapter', function () { expect(bidRequest.data.pubId).to.equal(request.params.inScreenPubID); expect(bidRequest.data).to.not.include.any.keys('t'); }); + it('should send pubId if videoPubID param is specified', function () { + const request = { ...bidRequests[0], mediaTypes: vidMediaTypes, params: { 'videoPubID': 123 } }; + const bidRequest = spec.buildRequests([request])[0]; + expect(bidRequest.data).to.include.any.keys('pubId'); + expect(bidRequest.data.pubId).to.equal(request.params.videoPubID); + expect(bidRequest.data).to.not.include.any.keys('t'); + }); it('should set a ni parameter in bid request if ICV request param is found', function () { const request = Object.assign({}, bidRequests[0]); delete request.params; @@ -159,6 +319,7 @@ describe('gumgumAdapter', function () { 'video': '10433395' }; const bidRequest = spec.buildRequests([request])[0]; + // 7 is video product line expect(bidRequest.data.pi).to.eq(7); expect(bidRequest.data.mind).to.eq(videoVals.minduration); expect(bidRequest.data.maxd).to.eq(videoVals.maxduration); @@ -169,6 +330,37 @@ describe('gumgumAdapter', function () { expect(bidRequest.data.viw).to.eq(videoVals.playerSize[0].toString()); expect(bidRequest.data.vih).to.eq(videoVals.playerSize[1].toString()); }); + it('should add parameters associated with invideo if invideo request param is found', function () { + const inVideoVals = { + playerSize: [640, 480], + context: 'instream', + minduration: 1, + maxduration: 2, + linearity: 1, + startdelay: 1, + placement: 123456, + protocols: [1, 2] + }; + const request = Object.assign({}, bidRequests[0]); + delete request.params; + request.mediaTypes = { + video: inVideoVals + }; + request.params = { + 'inVideo': '10433395' + }; + const bidRequest = spec.buildRequests([request])[0]; + // 6 is invideo product line + expect(bidRequest.data.pi).to.eq(6); + expect(bidRequest.data.mind).to.eq(inVideoVals.minduration); + expect(bidRequest.data.maxd).to.eq(inVideoVals.maxduration); + expect(bidRequest.data.li).to.eq(inVideoVals.linearity); + expect(bidRequest.data.sd).to.eq(inVideoVals.startdelay); + expect(bidRequest.data.pt).to.eq(inVideoVals.placement); + expect(bidRequest.data.pr).to.eq(inVideoVals.protocols.join(',')); + expect(bidRequest.data.viw).to.eq(inVideoVals.playerSize[0].toString()); + expect(bidRequest.data.vih).to.eq(inVideoVals.playerSize[1].toString()); + }); it('should not add additional parameters depending on params field', function () { const request = spec.buildRequests(bidRequests)[0]; expect(request.data).to.not.include.any.keys('ni'); @@ -228,12 +420,13 @@ describe('gumgumAdapter', function () { expect(bidRequest.data).to.not.include.any.keys('ns'); } }); - it('has jcsi param correctly encoded', function () { - const jcsi = JSON.stringify({ t: 0, rq: 8 }); - const encodedJCSI = encodeURIComponent(jcsi); + it('adds jcsi param with correct keys', function () { + const expectedKeys = Object.keys(JCSI).sort(); + const jcsi = JSON.stringify(JCSI); const bidRequest = spec.buildRequests(bidRequests)[0]; - expect(bidRequest.data.jcsi).to.not.contain(/\{.*\}/); - expect(bidRequest.data.jcsi).to.eq(encodedJCSI); + const actualKeys = Object.keys(JSON.parse(bidRequest.data.jcsi)).sort(); + expect(actualKeys).to.eq(actualKeys); + expect(bidRequest.data.jcsi).to.eq(jcsi); }); }) @@ -258,6 +451,7 @@ describe('gumgumAdapter', function () { 'css': 'html { overflow-y: auto }', 'js': 'console.log("environment", env);' }, + 'jcsi': { t: 0, rq: 8 }, 'thms': 10000 } let bidRequest = { @@ -309,6 +503,12 @@ describe('gumgumAdapter', function () { expect(result.length).to.equal(0); }); + it('handles empty response', function () { + let body; + let result = spec.interpretResponse({ body }, bidRequest); + expect(result.length).to.equal(0); + }); + it('returns 1x1 when eligible product and size available', function () { let inscreenBidRequest = { id: 12346, @@ -344,7 +544,14 @@ describe('gumgumAdapter', function () { let result = spec.interpretResponse({ body: inscreenServerResponse }, inscreenBidRequest); expect(result[0].width).to.equal('1'); expect(result[0].height).to.equal('1'); - }) + }); + + it('updates jcsi object when the server response jcsi prop is found', function () { + const response = Object.assign({ cw: 'AD_JSON' }, serverResponse); + const bidResponse = spec.interpretResponse({ body: response }, bidRequest)[0].ad; + const decodedResponse = JSON.parse(atob(bidResponse)); + expect(decodedResponse.jcsi).to.eql(JCSI); + }); }) describe('getUserSyncs', function () { const syncOptions = { diff --git a/test/spec/modules/h12mediaBidAdapter_spec.js b/test/spec/modules/h12mediaBidAdapter_spec.js new file mode 100644 index 00000000000..08a83ce981f --- /dev/null +++ b/test/spec/modules/h12mediaBidAdapter_spec.js @@ -0,0 +1,388 @@ +import {expect} from 'chai'; +import {spec} from 'modules/h12mediaBidAdapter'; +import {newBidder} from 'src/adapters/bidderFactory'; + +describe('H12 Media Adapter', function () { + const DEFAULT_CURRENCY = 'USD'; + const DEFAULT_TTL = 360; + const DEFAULT_NET_REVENUE = false; + const adapter = newBidder('spec'); + + const validBid = { + adUnitCode: 'div-gpt-ad-1460505748561-0', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + bidder: 'h12media', + bidId: '1c5e8a1a84522d', + bidderRequestId: '1d0c4017f02458', + auctionId: '9adc85ed-43ee-4a78-816b-52b7e578f313', + params: { + pubid: 123321, + }, + }; + + const validBid2 = { + adUnitCode: 'div-gpt-ad-1460505748561-1', + mediaTypes: { + banner: {} + }, + bidder: 'h12media', + bidId: '2c5e8a1a84522d', + bidderRequestId: '2d0c4017f02458', + auctionId: '9adc85ed-43ee-4a78-816b-52b7e578f314', + params: { + pubid: 123321, + size: '100x200' + }, + }; + + const invalidBid = { + adUnitCode: 'div-gpt-ad-1460505748561-2', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + bidder: 'h12media', + bidId: '3c5e8a1a84522d', + bidderRequestId: '3d0c4017f02458', + auctionId: '9adc85ed-43ee-4a78-816b-52b7e578f315', + }; + + const bidderRequest = { + refererInfo: { + referer: 'https://localhost' + }, + gdprConsent: { + gdprApplies: 1, + consentString: 'concentDataString', + vendorData: { + vendorConsents: { + '90': 1 + }, + }, + }, + uspConsent: 'consentUspString' + }; + + const serverResponse = { + currency: 'EUR', + netRevenue: true, + ttl: 500, + bids: [{ + bidId: validBid.bidId, + cpm: 0.33, + width: 300, + height: 600, + creativeId: '335566', + ad: '
my ad
', + usersync: [ + {url: 'https://cookiesync.3rdpartypartner.com/?3rdparty_partner_user_id={user_id}&partner_id=h12media&gdpr_applies={gdpr}&gdpr_consent_string={gdpr_cs}', type: 'image'}, + {url: 'https://cookiesync.3rdpartypartner.com/?3rdparty_partner_user_id={user_id}&partner_id=h12media&gdpr_applies={gdpr}&gdpr_consent_string={gdpr_cs}', type: 'iframe'} + ], + meta: { + advertiserId: '54321', + advertiserName: 'My advertiser', + advertiserDomains: ['test.com'] + } + }] + }; + + const serverResponse2 = { + bids: [{ + bidId: validBid2.bidId, + cpm: 0.33, + width: 300, + height: 600, + creativeId: '335566', + ad: '
my ad 2
', + }] + }; + + function removeElement(id) { + if (document.getElementById(id)) { + document.body.removeChild(document.getElementById(id)); + } + } + + function createElement(id) { + const div = document.createElement('div'); + div.id = id; + div.style.width = '50px'; + div.style.height = '50px'; + if (frameElement) { + frameElement.style.width = '100px'; + frameElement.style.height = '100px'; + } + div.style.background = 'black'; + document.body.appendChild(div); + return div; + } + function createElementVisible(id) { + const element = createElement(id); + sandbox.stub(element, 'getBoundingClientRect').returns({ + x: 10, + y: 10, + }); + return element; + } + function createElementInvisible(id) { + const element = document.createElement('div'); + element.id = id; + document.body.appendChild(element); + element.style.display = 'none'; + return element; + } + + function createElementHidden(id) { + const element = createElement(id); + document.body.appendChild(element); + element.style.visibility = 'hidden'; + sandbox.stub(element, 'getBoundingClientRect').returns({ + x: 100, + y: 100, + }); + return element; + } + + let sandbox; + + beforeEach(function () { + sandbox = sinon.sandbox.create(); + }); + + afterEach(function () { + removeElement(validBid.adUnitCode); + removeElement(validBid2.adUnitCode); + removeElement(invalidBid.adUnitCode); + sandbox.restore(); + }); + + after(function() { + sandbox.reset(); + }) + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + it('should return true when bid is valid', function () { + expect(spec.isBidRequestValid(validBid)).to.equal(true); + }); + + it('should return false when bid does not have pubid parameter', function () { + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + it('should return adUnit size', function () { + createElementVisible(validBid.adUnitCode); + createElementVisible(validBid2.adUnitCode); + const requests = spec.buildRequests([validBid, validBid2], bidderRequest); + const requestsData = requests.data; + + expect(requestsData.bidrequests[0]).to.include({adunitSize: validBid.mediaTypes.banner.sizes}); + }); + + it('should return empty bid size', function () { + createElementVisible(validBid.adUnitCode); + createElementVisible(validBid2.adUnitCode); + const requests = spec.buildRequests([validBid, validBid2], bidderRequest); + const requestsData = requests.data; + + expect(requestsData.bidrequests[1]).to.deep.include({adunitSize: []}); + }); + + it('should return bid size from params', function () { + createElementVisible(validBid.adUnitCode); + createElementVisible(validBid2.adUnitCode); + const requests = spec.buildRequests([validBid, validBid2], bidderRequest); + const requestsData = requests.data; + + expect(requestsData.bidrequests[1]).to.include({size: validBid2.params.size}); + }); + + it('should return GDPR info', function () { + createElementVisible(validBid.adUnitCode); + createElementVisible(validBid2.adUnitCode); + const requests = spec.buildRequests([validBid, validBid2], bidderRequest); + const requestsData = requests.data; + + expect(requestsData).to.include({gdpr: true, gdpr_cs: bidderRequest.gdprConsent.consentString}); + }); + + it('should not have error on empty GDPR', function () { + createElementVisible(validBid.adUnitCode); + createElementVisible(validBid2.adUnitCode); + const bidderRequestWithoutGDRP = {...bidderRequest, gdprConsent: null}; + const requests = spec.buildRequests([validBid, validBid2], bidderRequestWithoutGDRP); + const requestsData = requests.data; + + expect(requestsData).to.include({gdpr: false}); + }); + + it('should create single POST', function () { + createElementVisible(validBid.adUnitCode); + createElementVisible(validBid2.adUnitCode); + const requests = spec.buildRequests([validBid, validBid2], bidderRequest); + + expect(requests.method).to.equal('POST'); + }); + }); + + describe('creative viewability', function () { + it('should return coords', function () { + createElementVisible(validBid.adUnitCode); + const requests = spec.buildRequests([validBid], bidderRequest); + const requestsData = requests.data; + + expect(requestsData.bidrequests[0]).to.deep.include({coords: {x: 10, y: 10}}); + }); + + it('should define not iframe', function () { + createElementVisible(validBid.adUnitCode); + createElementVisible(validBid2.adUnitCode); + const requests = spec.buildRequests([validBid, validBid2], bidderRequest); + const requestsData = requests.data; + + expect(requestsData).to.include({isiframe: false}); + }); + + it('should define visible element', function () { + createElementVisible(validBid.adUnitCode); + const requests = spec.buildRequests([validBid], bidderRequest); + const requestsData = requests.data; + + expect(requestsData.bidrequests[0]).to.include({ishidden: false}); + }); + + it('should define invisible element', function () { + createElementInvisible(validBid.adUnitCode); + const requests = spec.buildRequests([validBid], bidderRequest); + const requestsData = requests.data; + + expect(requestsData.bidrequests[0]).to.include({ishidden: true}); + }); + + it('should define hidden element', function () { + createElementHidden(validBid.adUnitCode); + const requests = spec.buildRequests([validBid], bidderRequest); + const requestsData = requests.data; + + expect(requestsData.bidrequests[0]).to.include({ishidden: true}); + }); + }); + + describe('interpretResponse', function () { + it('should return no bids if the response is not valid', function () { + const bidResponse = spec.interpretResponse({ body: null }, validBid); + + expect(bidResponse.length).to.equal(0); + }); + + it('should return no bids if the response is empty', function () { + const bidResponse = spec.interpretResponse({ body: [] }, { validBid }); + + expect(bidResponse.length).to.equal(0); + }); + + it('should return valid bid responses', function () { + createElementVisible(validBid.adUnitCode); + createElementVisible(validBid2.adUnitCode); + const request = spec.buildRequests([validBid, validBid2], bidderRequest); + const bidResponse = spec.interpretResponse({body: serverResponse}, request); + + expect(bidResponse[0]).to.deep.include({ + requestId: validBid.bidId, + ad: serverResponse.bids[0].ad, + mediaType: 'banner', + creativeId: serverResponse.bids[0].creativeId, + cpm: serverResponse.bids[0].cpm, + width: serverResponse.bids[0].width, + height: serverResponse.bids[0].height, + currency: 'EUR', + netRevenue: true, + ttl: 500, + meta: serverResponse.bids[0].meta, + pubid: validBid.params.pubid + }); + }); + + it('should return default bid params', function () { + createElementVisible(validBid.adUnitCode); + createElementVisible(validBid2.adUnitCode); + const request = spec.buildRequests([validBid, validBid2], bidderRequest); + const bidResponse = spec.interpretResponse({body: serverResponse2}, request); + + expect(bidResponse[0]).to.deep.include({ + requestId: validBid2.bidId, + ad: serverResponse2.bids[0].ad, + mediaType: 'banner', + creativeId: serverResponse2.bids[0].creativeId, + cpm: serverResponse2.bids[0].cpm, + width: serverResponse2.bids[0].width, + height: serverResponse2.bids[0].height, + meta: serverResponse2.bids[0].meta, + pubid: validBid2.params.pubid, + currency: DEFAULT_CURRENCY, + netRevenue: DEFAULT_NET_REVENUE, + ttl: DEFAULT_TTL, + }); + }); + }); + + describe('getUserSyncs', function () { + let syncOptions + beforeEach(function () { + syncOptions = { + enabledBidders: ['h12media'], + pixelEnabled: true, + iframeEnabled: true + } + }); + + it('should success with usersync pixel url', function () { + const result = { + type: 'image', + url: `https://cookiesync.3rdpartypartner.com/?3rdparty_partner_user_id={user_id}&partner_id=h12media&gdpr_applies=${bidderRequest.gdprConsent.gdprApplies}&gdpr_consent_string=${bidderRequest.gdprConsent.consentString}`, + }; + const syncs = spec.getUserSyncs(syncOptions, [{body: serverResponse}], bidderRequest.gdprConsent); + + expect(syncs).to.deep.include(result); + }); + + it('should success with usersync iframe url', function () { + const result = { + type: 'iframe', + url: `https://cookiesync.3rdpartypartner.com/?3rdparty_partner_user_id={user_id}&partner_id=h12media&gdpr_applies=${bidderRequest.gdprConsent.gdprApplies}&gdpr_consent_string=${bidderRequest.gdprConsent.consentString}`, + }; + const syncs = spec.getUserSyncs(syncOptions, [{body: serverResponse}], bidderRequest.gdprConsent); + + expect(syncs).to.deep.include(result); + }); + + it('should success without GDRP', function () { + const result = { + type: 'iframe', + url: `https://cookiesync.3rdpartypartner.com/?3rdparty_partner_user_id={user_id}&partner_id=h12media&gdpr_applies=false&gdpr_consent_string=`, + }; + + expect(spec.getUserSyncs(syncOptions, [{body: serverResponse}], null)).to.deep.include(result); + }); + + it('should success without usersync url', function () { + expect(spec.getUserSyncs(syncOptions, [{body: serverResponse2}], bidderRequest.gdprConsent)).to.deep.equal([]); + }); + + it('should return empty usersync on empty response', function () { + expect(spec.getUserSyncs(syncOptions, [{body: {}}])).to.deep.equal([]); + }); + }); +}); diff --git a/test/spec/modules/id5IdSystem_spec.js b/test/spec/modules/id5IdSystem_spec.js new file mode 100644 index 00000000000..cea6bdf92b9 --- /dev/null +++ b/test/spec/modules/id5IdSystem_spec.js @@ -0,0 +1,388 @@ +import { init, requestBidsHook, setSubmoduleRegistry, coreStorage } from 'modules/userId/index.js'; +import { config } from 'src/config.js'; +import { id5IdSubmodule } from 'modules/id5IdSystem.js'; +import { server } from 'test/mocks/xhr.js'; +import events from 'src/events.js'; +import CONSTANTS from 'src/constants.json'; + +let expect = require('chai').expect; + +describe('ID5 ID System', function() { + const ID5_MODULE_NAME = 'id5Id'; + const ID5_EIDS_NAME = ID5_MODULE_NAME.toLowerCase(); + const ID5_SOURCE = 'id5-sync.com'; + const ID5_PARTNER = 173; + const ID5_ENDPOINT = `https://id5-sync.com/g/v2/${ID5_PARTNER}.json`; + const ID5_COOKIE_NAME = 'id5idcookie'; + const ID5_NB_COOKIE_NAME = `id5id.1st_${ID5_PARTNER}_nb`; + const ID5_EXPIRED_COOKIE_DATE = 'Thu, 01 Jan 1970 00:00:01 GMT'; + const ID5_STORED_ID = 'storedid5id'; + const ID5_STORED_SIGNATURE = '123456'; + const ID5_STORED_OBJ = { + 'universal_uid': ID5_STORED_ID, + 'signature': ID5_STORED_SIGNATURE + }; + const ID5_LEGACY_STORED_OBJ = { + 'ID5ID': ID5_STORED_ID + } + const ID5_RESPONSE_ID = 'newid5id'; + const ID5_RESPONSE_SIGNATURE = 'abcdef'; + const ID5_JSON_RESPONSE = { + 'universal_uid': ID5_RESPONSE_ID, + 'signature': ID5_RESPONSE_SIGNATURE, + 'link_type': 0 + }; + + function getId5FetchConfig(storageName = ID5_COOKIE_NAME, storageType = 'cookie') { + return { + name: ID5_MODULE_NAME, + params: { + partner: ID5_PARTNER + }, + storage: { + name: storageName, + type: storageType, + expires: 90 + } + } + } + function getId5ValueConfig(value) { + return { + name: ID5_MODULE_NAME, + value: { + id5id: { + uid: value + } + } + } + } + function getUserSyncConfig(userIds) { + return { + userSync: { + userIds: userIds, + syncDelay: 0 + } + } + } + function getFetchCookieConfig() { + return getUserSyncConfig([getId5FetchConfig()]); + } + function getFetchLocalStorageConfig() { + return getUserSyncConfig([getId5FetchConfig(ID5_COOKIE_NAME, 'html5')]); + } + function getValueConfig(value) { + return getUserSyncConfig([getId5ValueConfig(value)]); + } + function getAdUnitMock(code = 'adUnit-code') { + return { + code, + mediaTypes: {banner: {}, native: {}}, + sizes: [[300, 200], [300, 600]], + bids: [{bidder: 'sampleBidder', params: {placementId: 'banner-only-bidder'}}] + }; + } + + describe('Xhr Requests from getId()', function() { + const responseHeader = { 'Content-Type': 'application/json' }; + let callbackSpy = sinon.spy(); + + beforeEach(function() { + callbackSpy.resetHistory(); + }); + afterEach(function () { + + }); + + it('should fail if no partner is provided in the config', function() { + expect(id5IdSubmodule.getId()).to.be.eq(undefined); + }); + + it('should call the ID5 server with 1puid field for legacy storedObj format', function () { + let submoduleCallback = id5IdSubmodule.getId(getId5FetchConfig().params, undefined, ID5_LEGACY_STORED_OBJ).callback; + submoduleCallback(callbackSpy); + + let request = server.requests[0]; + let requestBody = JSON.parse(request.requestBody); + expect(request.url).to.contain(ID5_ENDPOINT); + expect(request.withCredentials).to.be.true; + expect(requestBody.s).to.eq(''); + expect(requestBody.partner).to.eq(ID5_PARTNER); + expect(requestBody['1puid']).to.eq(ID5_STORED_ID); + + request.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); + expect(callbackSpy.calledOnce).to.be.true; + expect(callbackSpy.lastCall.lastArg).to.deep.equal(ID5_JSON_RESPONSE); + }); + + it('should call the ID5 server with signature field for new storedObj format', function () { + let submoduleCallback = id5IdSubmodule.getId(getId5FetchConfig().params, undefined, ID5_STORED_OBJ).callback; + submoduleCallback(callbackSpy); + + let request = server.requests[0]; + let requestBody = JSON.parse(request.requestBody); + expect(request.url).to.contain(ID5_ENDPOINT); + expect(request.withCredentials).to.be.true; + expect(requestBody.s).to.eq(ID5_STORED_SIGNATURE); + expect(requestBody.partner).to.eq(ID5_PARTNER); + expect(requestBody['1puid']).to.eq(''); + + request.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); + expect(callbackSpy.calledOnce).to.be.true; + expect(callbackSpy.lastCall.lastArg).to.deep.equal(ID5_JSON_RESPONSE); + }); + + it('should call the ID5 server with pd field when pd config is set', function () { + const pubData = 'b50ca08271795a8e7e4012813f23d505193d75c0f2e2bb99baa63aa822f66ed3'; + + let config = getId5FetchConfig().params; + config.pd = pubData; + + let submoduleCallback = id5IdSubmodule.getId(config, undefined, ID5_STORED_OBJ).callback; + submoduleCallback(callbackSpy); + + let request = server.requests[0]; + let requestBody = JSON.parse(request.requestBody); + expect(request.url).to.contain(ID5_ENDPOINT); + expect(request.withCredentials).to.be.true; + expect(requestBody.s).to.eq(ID5_STORED_SIGNATURE); + expect(requestBody.pd).to.eq(pubData); + expect(requestBody['1puid']).to.eq(''); + + request.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); + expect(callbackSpy.calledOnce).to.be.true; + expect(callbackSpy.lastCall.lastArg).to.deep.equal(ID5_JSON_RESPONSE); + }); + + it('should call the ID5 server with empty pd field when pd config is not set', function () { + let config = getId5FetchConfig().params; + config.pd = undefined; + + let submoduleCallback = id5IdSubmodule.getId(config, undefined, ID5_STORED_OBJ).callback; + submoduleCallback(callbackSpy); + + let request = server.requests[0]; + let requestBody = JSON.parse(request.requestBody); + expect(request.url).to.contain(ID5_ENDPOINT); + expect(request.withCredentials).to.be.true; + expect(requestBody.pd).to.eq(''); + + request.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); + expect(callbackSpy.calledOnce).to.be.true; + expect(callbackSpy.lastCall.lastArg).to.deep.equal(ID5_JSON_RESPONSE); + }); + + it('should call the ID5 server with nb=1 when no stored value exists', function () { + coreStorage.setCookie(ID5_NB_COOKIE_NAME, '', ID5_EXPIRED_COOKIE_DATE); + + let submoduleCallback = id5IdSubmodule.getId(getId5FetchConfig().params, undefined, ID5_STORED_OBJ).callback; + submoduleCallback(callbackSpy); + + let request = server.requests[0]; + let requestBody = JSON.parse(request.requestBody); + expect(request.url).to.contain(ID5_ENDPOINT); + expect(request.withCredentials).to.be.true; + expect(requestBody.nbPage).to.eq(1); + + request.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); + expect(callbackSpy.calledOnce).to.be.true; + expect(callbackSpy.lastCall.lastArg).to.deep.equal(ID5_JSON_RESPONSE); + + expect(coreStorage.getCookie(ID5_NB_COOKIE_NAME)).to.be.eq('0'); + }); + + it('should call the ID5 server with incremented nb when stored value exists', function () { + let expStr = (new Date(Date.now() + 25000).toUTCString()); + coreStorage.setCookie(ID5_NB_COOKIE_NAME, '1', expStr); + + let submoduleCallback = id5IdSubmodule.getId(getId5FetchConfig().params, undefined, ID5_STORED_OBJ).callback; + submoduleCallback(callbackSpy); + + let request = server.requests[0]; + let requestBody = JSON.parse(request.requestBody); + expect(request.url).to.contain(ID5_ENDPOINT); + expect(request.withCredentials).to.be.true; + expect(requestBody.nbPage).to.eq(2); + + request.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); + expect(callbackSpy.calledOnce).to.be.true; + expect(callbackSpy.lastCall.lastArg).to.deep.equal(ID5_JSON_RESPONSE); + + expect(coreStorage.getCookie(ID5_NB_COOKIE_NAME)).to.be.eq('0'); + }); + }); + + describe('Request Bids Hook', function() { + let adUnits; + + beforeEach(function() { + sinon.stub(events, 'getEvents').returns([]); + coreStorage.setCookie(ID5_COOKIE_NAME, '', ID5_EXPIRED_COOKIE_DATE); + coreStorage.setCookie(`${ID5_COOKIE_NAME}_last`, '', ID5_EXPIRED_COOKIE_DATE); + coreStorage.setCookie(ID5_NB_COOKIE_NAME, '', ID5_EXPIRED_COOKIE_DATE); + adUnits = [getAdUnitMock()]; + }); + afterEach(function() { + events.getEvents.restore(); + coreStorage.setCookie(ID5_COOKIE_NAME, '', ID5_EXPIRED_COOKIE_DATE); + coreStorage.setCookie(`${ID5_COOKIE_NAME}_last`, '', ID5_EXPIRED_COOKIE_DATE); + coreStorage.setCookie(ID5_NB_COOKIE_NAME, '', ID5_EXPIRED_COOKIE_DATE); + }); + + it('should add stored ID from cookie to bids', function (done) { + let expStr = (new Date(Date.now() + 25000).toUTCString()); + coreStorage.setCookie(ID5_COOKIE_NAME, JSON.stringify(ID5_STORED_OBJ), expStr); + + setSubmoduleRegistry([id5IdSubmodule]); + init(config); + config.setConfig(getFetchCookieConfig()); + + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property(`userId.${ID5_EIDS_NAME}`); + expect(bid.userId.id5id.uid).to.equal(ID5_STORED_ID); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: ID5_SOURCE, + uids: [{ id: ID5_STORED_ID, atype: 1 }], + ext: { + linkType: 0 + } + }); + }); + }); + done(); + }, { adUnits }); + }); + + it('should add config value ID to bids', function (done) { + setSubmoduleRegistry([id5IdSubmodule]); + init(config); + config.setConfig(getValueConfig(ID5_STORED_ID)); + + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property(`userId.${ID5_EIDS_NAME}`); + expect(bid.userId.id5id.uid).to.equal(ID5_STORED_ID); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: ID5_SOURCE, + uids: [{ id: ID5_STORED_ID, atype: 1 }] + }); + }); + }); + done(); + }, { adUnits }); + }); + + it('should set nb=1 in cookie when no stored value exists', function () { + let expStr = (new Date(Date.now() + 25000).toUTCString()); + coreStorage.setCookie(ID5_COOKIE_NAME, JSON.stringify(ID5_STORED_OBJ), expStr); + coreStorage.setCookie(ID5_NB_COOKIE_NAME, '', ID5_EXPIRED_COOKIE_DATE); + + setSubmoduleRegistry([id5IdSubmodule]); + init(config); + config.setConfig(getFetchCookieConfig()); + + let innerAdUnits; + requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); + + expect(coreStorage.getCookie(ID5_NB_COOKIE_NAME)).to.be.eq('1'); + }); + + it('should increment nb in cookie when stored value exists', function () { + let expStr = (new Date(Date.now() + 25000).toUTCString()); + coreStorage.setCookie(ID5_COOKIE_NAME, JSON.stringify(ID5_STORED_OBJ), expStr); + coreStorage.setCookie(ID5_NB_COOKIE_NAME, '1', expStr); + + setSubmoduleRegistry([id5IdSubmodule]); + init(config); + config.setConfig(getFetchCookieConfig()); + + let innerAdUnits; + requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); + + expect(coreStorage.getCookie(ID5_NB_COOKIE_NAME)).to.be.eq('2'); + }); + + it('should call ID5 servers with signature and incremented nb post auction if refresh needed', function () { + let expStr = (new Date(Date.now() + 25000).toUTCString()); + coreStorage.setCookie(ID5_COOKIE_NAME, JSON.stringify(ID5_STORED_OBJ), expStr); + coreStorage.setCookie(`${ID5_COOKIE_NAME}_last`, (new Date(Date.now() - 50000).toUTCString()), expStr); + coreStorage.setCookie(ID5_NB_COOKIE_NAME, '1', expStr); + + let id5Config = getFetchCookieConfig(); + id5Config.userSync.userIds[0].storage.refreshInSeconds = 2; + + setSubmoduleRegistry([id5IdSubmodule]); + init(config); + config.setConfig(id5Config); + + let innerAdUnits; + requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); + + expect(coreStorage.getCookie(ID5_NB_COOKIE_NAME)).to.be.eq('2'); + + expect(server.requests).to.be.empty; + events.emit(CONSTANTS.EVENTS.AUCTION_END, {}); + + let request = server.requests[0]; + let requestBody = JSON.parse(request.requestBody); + expect(request.url).to.contain(ID5_ENDPOINT); + expect(requestBody.s).to.eq(ID5_STORED_SIGNATURE); + expect(requestBody.nbPage).to.eq(2); + + const responseHeader = { 'Content-Type': 'application/json' }; + request.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); + + expect(coreStorage.getCookie(ID5_COOKIE_NAME)).to.be.eq(JSON.stringify(ID5_JSON_RESPONSE)); + expect(coreStorage.getCookie(ID5_NB_COOKIE_NAME)).to.be.eq('0'); + }); + + it('should call ID5 servers with 1puid and nb=1 post auction if refresh needed for legacy stored object', function () { + let expStr = (new Date(Date.now() + 25000).toUTCString()); + coreStorage.setCookie(ID5_COOKIE_NAME, JSON.stringify(ID5_LEGACY_STORED_OBJ), expStr); + coreStorage.setCookie(`${ID5_COOKIE_NAME}_last`, (new Date(Date.now() - 50000).toUTCString()), expStr); + + let id5Config = getFetchCookieConfig(); + id5Config.userSync.userIds[0].storage.refreshInSeconds = 2; + + setSubmoduleRegistry([id5IdSubmodule]); + init(config); + config.setConfig(id5Config); + + let innerAdUnits; + requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); + + expect(coreStorage.getCookie(ID5_NB_COOKIE_NAME)).to.be.eq('1'); + + expect(server.requests).to.be.empty; + events.emit(CONSTANTS.EVENTS.AUCTION_END, {}); + + let request = server.requests[0]; + let requestBody = JSON.parse(request.requestBody); + expect(request.url).to.contain(ID5_ENDPOINT); + expect(requestBody['1puid']).to.eq(ID5_STORED_ID); + expect(requestBody.nbPage).to.eq(1); + + const responseHeader = { 'Content-Type': 'application/json' }; + request.respond(200, responseHeader, JSON.stringify(ID5_JSON_RESPONSE)); + + expect(coreStorage.getCookie(ID5_COOKIE_NAME)).to.be.eq(JSON.stringify(ID5_JSON_RESPONSE)); + expect(coreStorage.getCookie(ID5_NB_COOKIE_NAME)).to.be.eq('0'); + }); + }); + + describe('Decode stored object', function() { + const expectedDecodedObject = { id5id: { uid: ID5_STORED_ID, ext: { linkType: 0 } } }; + + it('should properly decode from a stored object', function() { + expect(id5IdSubmodule.decode(ID5_STORED_OBJ)).to.deep.equal(expectedDecodedObject); + }); + it('should properly decode from a legacy stored object', function() { + expect(id5IdSubmodule.decode(ID5_LEGACY_STORED_OBJ)).to.deep.equal(expectedDecodedObject); + }); + it('should return undefined if passed a string', function() { + expect(id5IdSubmodule.decode('somestring')).to.eq(undefined); + }); + }); +}); diff --git a/test/spec/modules/identityLinkIdSystem_spec.js b/test/spec/modules/identityLinkIdSystem_spec.js new file mode 100644 index 00000000000..9f36ba92558 --- /dev/null +++ b/test/spec/modules/identityLinkIdSystem_spec.js @@ -0,0 +1,127 @@ +import {identityLinkSubmodule} from 'modules/identityLinkIdSystem.js'; +import * as utils from 'src/utils.js'; +import {server} from 'test/mocks/xhr.js'; + +const pid = '14'; +const defaultConfigParams = {pid: pid}; +const responseHeader = {'Content-Type': 'application/json'} + +describe('IdentityLinkId tests', function () { + let logErrorStub; + + beforeEach(function () { + logErrorStub = sinon.stub(utils, 'logError'); + }); + + afterEach(function () { + logErrorStub.restore(); + }); + + it('should log an error if no configParams were passed when getId', function () { + identityLinkSubmodule.getId(); + expect(logErrorStub.calledOnce).to.be.true; + }); + + it('should log an error if pid configParam was not passed when getId', function () { + identityLinkSubmodule.getId({}); + expect(logErrorStub.calledOnce).to.be.true; + }); + + it('should call the LiveRamp envelope endpoint', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.rlcdn.com/api/identity/envelope?pid=14'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should NOT call the LiveRamp envelope endpoint if gdpr applies but consent string is empty string', function () { + let consentData = { + gdprApplies: true, + consentString: '' + }; + let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams, consentData); + expect(submoduleCallback).to.be.undefined; + }); + + it('should NOT call the LiveRamp envelope endpoint if gdpr applies but consent string is missing', function () { + let consentData = { gdprApplies: true }; + let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams, consentData); + expect(submoduleCallback).to.be.undefined; + }); + + it('should call the LiveRamp envelope endpoint with IAB consent string v1', function () { + let callBackSpy = sinon.spy(); + let consentData = { + gdprApplies: true, + consentString: 'BOkIpDSOkIpDSADABAENCc-AAAApOAFAAMAAsAMIAcAA_g' + }; + let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams, consentData).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.rlcdn.com/api/identity/envelope?pid=14&ct=1&cv=BOkIpDSOkIpDSADABAENCc-AAAApOAFAAMAAsAMIAcAA_g'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should call the LiveRamp envelope endpoint with IAB consent string v2', function () { + let callBackSpy = sinon.spy(); + let consentData = { + gdprApplies: true, + consentString: 'CO4VThZO4VTiuADABBENAzCgAP_AAEOAAAAAAwwAgAEABhAAgAgAAA.YAAAAAAAAAA', + vendorData: { + tcfPolicyVersion: 2 + } + }; + let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams, consentData).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.rlcdn.com/api/identity/envelope?pid=14&ct=4&cv=CO4VThZO4VTiuADABBENAzCgAP_AAEOAAAAAAwwAgAEABhAAgAgAAA.YAAAAAAAAAA'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should not throw Uncaught TypeError when envelope endpoint returns empty response', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.rlcdn.com/api/identity/envelope?pid=14'); + request.respond( + 204, + responseHeader, + '' + ); + expect(callBackSpy.calledOnce).to.be.true; + expect(request.response).to.equal(''); + expect(logErrorStub.calledOnce).to.not.be.true; + }); + + it('should log an error and continue to callback if ajax request errors', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = identityLinkSubmodule.getId(defaultConfigParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.rlcdn.com/api/identity/envelope?pid=14'); + request.respond( + 503, + responseHeader, + 'Unavailable' + ); + expect(callBackSpy.calledOnce).to.be.true; + }); +}); diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js index 1466b509c54..5a20944a6ed 100644 --- a/test/spec/modules/improvedigitalBidAdapter_spec.js +++ b/test/spec/modules/improvedigitalBidAdapter_spec.js @@ -778,10 +778,15 @@ describe('Improve Digital Adapter Tests', function () { expect(bids[0].dealId).to.not.exist; response.body.bid[0].lid = 268515; - response.body.bid[0].buying_type = 'classic'; + response.body.bid[0].buying_type = 'rtb'; bids = spec.interpretResponse(response, {bidderRequest}); expect(bids[0].dealId).to.not.exist; + response.body.bid[0].lid = 268515; + response.body.bid[0].buying_type = 'classic'; + bids = spec.interpretResponse(response, {bidderRequest}); + expect(bids[0].dealId).to.equal(268515); + response.body.bid[0].lid = 268515; response.body.bid[0].buying_type = 'deal_id'; bids = spec.interpretResponse(response, {bidderRequest}); @@ -798,7 +803,7 @@ describe('Improve Digital Adapter Tests', function () { expect(bids[0].dealId).to.not.exist; response.body.bid[0].lid = [ 268515, 12456, 34567 ]; - response.body.bid[0].buying_type = [ 'classic', 'deal_id', 'deal_id' ]; + response.body.bid[0].buying_type = [ 'rtb', 'deal_id', 'deal_id' ]; bids = spec.interpretResponse(response, {bidderRequest}); expect(bids[0].dealId).to.equal(12456); }); diff --git a/test/spec/modules/inmarBidAdapter_spec.js b/test/spec/modules/inmarBidAdapter_spec.js new file mode 100644 index 00000000000..86b7ab3a8af --- /dev/null +++ b/test/spec/modules/inmarBidAdapter_spec.js @@ -0,0 +1,251 @@ +// import or require modules necessary for the test, e.g.: +import {expect} from 'chai'; // may prefer 'assert' in place of 'expect' +import { + spec +} from 'modules/inmarBidAdapter.js'; +import {config} from 'src/config.js'; + +describe('Inmar adapter tests', function () { + var DEFAULT_PARAMS_NEW_SIZES = [{ + adUnitCode: 'test-div', + bidId: '2c7c8e9c900244', + mediaTypes: { + banner: { + sizes: [ + [300, 250], [300, 600], [728, 90], [970, 250]] + } + }, + bidder: 'inmar', + params: { + adnetId: 'ADb1f40rmi', + partnerId: 12345 + }, + auctionId: '0cb3144c-d084-4686-b0d6-f5dbe917c563', + bidRequestsCount: 1, + bidderRequestId: '1858b7382993ca', + transactionId: '29df2112-348b-4961-8863-1b33684d95e6', + user: {} + }]; + + var DEFAULT_PARAMS_VIDEO = [{ + adUnitCode: 'test-div', + bidId: '2c7c8e9c900244', + mediaTypes: { + video: { + context: 'instream', // or 'outstream' + playerSize: [640, 480], + mimes: ['video/mp4'] + } + }, + bidder: 'inmar', + params: { + adnetId: 'ADb1f40rmi', + partnerId: 12345 + }, + auctionId: '0cb3144c-d084-4686-b0d6-f5dbe917c563', + bidRequestsCount: 1, + bidderRequestId: '1858b7382993ca', + transactionId: '29df2112-348b-4961-8863-1b33684d95e6', + user: {} + }]; + + var DEFAULT_PARAMS_WO_OPTIONAL = [{ + adUnitCode: 'test-div', + bidId: '2c7c8e9c900244', + sizes: [ + [300, 250], + [300, 600], + [728, 90], + [970, 250] + ], + bidder: 'inmar', + params: { + adnetId: 'ADb1f40rmi', + partnerId: 12345, + }, + auctionId: '851adee7-d843-48f9-a7e9-9ff00573fcbf', + bidRequestsCount: 1, + bidderRequestId: '1858b7382993ca', + transactionId: '29df2112-348b-4961-8863-1b33684d95e6' + }]; + + var BID_RESPONSE = { + body: { + cpm: 1.50, + ad: '', + meta: { + mediaType: 'banner', + }, + width: 300, + height: 250, + creativeId: '189198063', + netRevenue: true, + currency: 'USD', + ttl: 300, + dealId: 'dealId' + + } + }; + + var BID_RESPONSE_VIDEO = { + body: { + cpm: 1.50, + meta: { + mediaType: 'video', + }, + width: 1, + height: 1, + creativeId: '189198063', + netRevenue: true, + currency: 'USD', + ttl: 300, + vastUrl: 'https://vast.com/vast.xml', + dealId: 'dealId' + } + }; + + it('Verify build request to prebid 3.0 display test', function() { + const request = spec.buildRequests(DEFAULT_PARAMS_NEW_SIZES, { + gdprConsent: { + consentString: 'BOZcQl_ObPFjWAeABAESCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NohBgA', + gdprApplies: true + }, + refererInfo: { + referer: 'https://domain.com', + numIframes: 0 + } + }); + + expect(request).to.have.property('method').and.to.equal('POST'); + const requestContent = JSON.parse(request.data); + expect(requestContent.bidRequests[0].params).to.have.property('adnetId').and.to.equal('ADb1f40rmi'); + expect(requestContent.bidRequests[0].params).to.have.property('partnerId').and.to.equal(12345); + expect(requestContent.bidRequests[0]).to.have.property('auctionId').and.to.equal('0cb3144c-d084-4686-b0d6-f5dbe917c563'); + expect(requestContent.bidRequests[0]).to.have.property('bidId').and.to.equal('2c7c8e9c900244'); + expect(requestContent.bidRequests[0]).to.have.property('bidRequestsCount').and.to.equal(1); + expect(requestContent.bidRequests[0]).to.have.property('bidder').and.to.equal('inmar'); + expect(requestContent.bidRequests[0]).to.have.property('bidderRequestId').and.to.equal('1858b7382993ca'); + expect(requestContent.bidRequests[0]).to.have.property('adUnitCode').and.to.equal('test-div'); + expect(requestContent.refererInfo).to.have.property('referer').and.to.equal('https://domain.com'); + expect(requestContent.bidRequests[0].mediaTypes.banner).to.have.property('sizes'); + expect(requestContent.bidRequests[0].mediaTypes.banner.sizes[0]).to.have.ordered.members([300, 250]); + expect(requestContent.bidRequests[0].mediaTypes.banner.sizes[1]).to.have.ordered.members([300, 600]); + expect(requestContent.bidRequests[0].mediaTypes.banner.sizes[2]).to.have.ordered.members([728, 90]); + expect(requestContent.bidRequests[0].mediaTypes.banner.sizes[3]).to.have.ordered.members([970, 250]); + expect(requestContent.bidRequests[0]).to.have.property('transactionId').and.to.equal('29df2112-348b-4961-8863-1b33684d95e6'); + expect(requestContent.refererInfo).to.have.property('numIframes').and.to.equal(0); + }) + + it('Verify interprete response', function () { + const request = spec.buildRequests(DEFAULT_PARAMS_NEW_SIZES, { + gdprConsent: { + consentString: 'BOZcQl_ObPFjWAeABAESCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NohBgA', + gdprApplies: true + }, + refererInfo: { + referer: 'https://domain.com', + numIframes: 0 + } + }); + + const bids = spec.interpretResponse(BID_RESPONSE, request); + expect(bids).to.have.lengthOf(1); + const bid = bids[0]; + expect(bid.cpm).to.equal(1.50); + expect(bid.ad).to.equal(''); + expect(bid.meta.mediaType).to.equal('banner'); + expect(bid.width).to.equal(300); + expect(bid.height).to.equal(250); + expect(bid.creativeId).to.equal('189198063'); + expect(bid.netRevenue).to.equal(true); + expect(bid.currency).to.equal('USD'); + expect(bid.ttl).to.equal(300); + expect(bid.dealId).to.equal('dealId'); + }); + + it('no banner media response', function () { + const request = spec.buildRequests(DEFAULT_PARAMS_NEW_SIZES, { + gdprConsent: { + consentString: 'BOZcQl_ObPFjWAeABAESCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NohBgA', + gdprApplies: true + }, + refererInfo: { + referer: 'https://domain.com', + numIframes: 0 + } + }); + + const bids = spec.interpretResponse(BID_RESPONSE_VIDEO, request); + const bid = bids[0]; + expect(bid.vastUrl).to.equal('https://vast.com/vast.xml'); + }); + + it('Verifies bidder_code', function () { + expect(spec.code).to.equal('inmar'); + }); + + it('Verifies bidder aliases', function () { + expect(spec.aliases).to.have.lengthOf(1); + expect(spec.aliases[0]).to.equal('inm'); + }); + + it('Verifies if bid request is valid', function () { + expect(spec.isBidRequestValid(DEFAULT_PARAMS_NEW_SIZES[0])).to.equal(true); + expect(spec.isBidRequestValid(DEFAULT_PARAMS_WO_OPTIONAL[0])).to.equal(true); + expect(spec.isBidRequestValid({})).to.equal(false); + expect(spec.isBidRequestValid({ + params: {} + })).to.equal(false); + expect(spec.isBidRequestValid({ + params: { + adnetId: 'ADb1f40rmi' + } + })).to.equal(false); + expect(spec.isBidRequestValid({ + params: { + partnerId: 12345 + } + })).to.equal(false); + expect(spec.isBidRequestValid({ + params: { + adnetId: 'ADb1f40rmi', + partnerId: 12345 + } + })).to.equal(true); + }); + + it('Verifies user syncs image', function () { + var syncs = spec.getUserSyncs({ + iframeEnabled: false, + pixelEnabled: true + }, [BID_RESPONSE], { + consentString: 'BOZcQl_ObPFjWAeABAESCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NohBgA', + referer: 'http://domain.com', + gdprApplies: true + }) + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('image'); + + syncs = spec.getUserSyncs({ + iframeEnabled: false, + pixelEnabled: true + }, [BID_RESPONSE], { + consentString: '', + referer: 'http://domain.com', + gdprApplies: true + }) + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('image'); + + syncs = spec.getUserSyncs({ + iframeEnabled: false, + pixelEnabled: true + }, [], { + consentString: null, + referer: 'http://domain.com', + gdprApplies: true + }) + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('image'); + }); +}); diff --git a/test/spec/modules/inskinBidAdapter_spec.js b/test/spec/modules/inskinBidAdapter_spec.js index 1be79a5a963..e817b3e3b81 100644 --- a/test/spec/modules/inskinBidAdapter_spec.js +++ b/test/spec/modules/inskinBidAdapter_spec.js @@ -215,6 +215,91 @@ describe('InSkin BidAdapter', function () { expect(payload.consent.gdprConsentString).to.exist.and.to.equal(consentString); expect(payload.consent.gdprConsentRequired).to.exist.and.to.be.true; }); + + it('should not add keywords if TCF v2 purposes are granted', function () { + const bidderRequest2 = Object.assign({}, bidderRequest, { + gdprConsent: { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + vendor: { + consents: { + 150: true + } + }, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true, + 6: true, + 7: true, + 8: true, + 9: true, + 10: true + } + } + }, + apiVersion: 2 + } + }); + + const request = spec.buildRequests(bidRequests, bidderRequest2); + const payload = JSON.parse(request.data); + + expect(payload.keywords).to.be.an('array').that.is.empty; + expect(payload.placements[0].properties).to.be.undefined; + }); + + it('should add keywords if TCF v2 purposes are not granted', function () { + const bidderRequest2 = Object.assign({}, bidderRequest, { + gdprConsent: { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + vendor: { + consents: { + 150: false + } + }, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true, + 6: true, + 7: true, + 8: true, + 9: true, + 10: true + } + } + }, + apiVersion: 2 + } + }); + + const request = spec.buildRequests(bidRequests, bidderRequest2); + const payload = JSON.parse(request.data); + + expect(payload.keywords).to.be.an('array').that.includes('cst-nocookies'); + expect(payload.keywords).to.be.an('array').that.includes('cst-nocontext'); + expect(payload.keywords).to.be.an('array').that.includes('cst-nodmp'); + expect(payload.keywords).to.be.an('array').that.includes('cst-nodata'); + expect(payload.keywords).to.be.an('array').that.includes('cst-noclicks'); + expect(payload.keywords).to.be.an('array').that.includes('cst-noresearch'); + + expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('nocookies'); + expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('nocontext'); + expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('nodmp'); + expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('nodata'); + expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('noclicks'); + expect(payload.placements[0].properties.restrictions).to.be.an('array').that.includes('noresearch'); + }); }); describe('interpretResponse validation', function () { it('response should have valid bidderCode', function () { diff --git a/test/spec/modules/instreamTracking_spec.js b/test/spec/modules/instreamTracking_spec.js new file mode 100644 index 00000000000..8c49da76ab6 --- /dev/null +++ b/test/spec/modules/instreamTracking_spec.js @@ -0,0 +1,221 @@ +import { assert } from 'chai'; +import { trackInstreamDeliveredImpressions } from 'modules/instreamTracking.js'; +import { config } from 'src/config.js'; +import * as events from 'src/events.js'; +import * as utils from 'src/utils.js'; +import * as sinon from 'sinon'; +import { INSTREAM, OUTSTREAM } from 'src/video.js'; + +const BIDDER_CODE = 'sampleBidder'; +const VIDEO_CACHE_KEY = '4cf395af-8fee-4960-af0e-88d44e399f14'; + +let sandbox; + +function enableInstreamTracking(regex) { + let configStub = sandbox.stub(config, 'getConfig'); + configStub.withArgs('instreamTracking').returns(Object.assign( + { + enabled: true, + maxWindow: 10, + pollingFreq: 0 + }, + regex && {urlPattern: regex}, + )); +} + +function mockPerformanceApi({adServerCallSent, videoPresent}) { + let performanceStub = sandbox.stub(window.performance, 'getEntriesByType'); + let entries = [{ + name: 'https://domain.com/img.png', + initiatorType: 'img' + }, { + name: 'https://domain.com/script.js', + initiatorType: 'script' + }, { + name: 'https://domain.com/xhr', + initiatorType: 'xmlhttprequest' + }, { + name: 'https://domain.com/fetch', + initiatorType: 'fetch' + }]; + + if (adServerCallSent || videoPresent) { + entries.push({ + name: 'https://adserver.com/ads?custom_params=hb_uuid%3D' + VIDEO_CACHE_KEY + '%26pos%3D' + VIDEO_CACHE_KEY, + initiatorType: 'xmlhttprequest' + }); + } + + if (videoPresent) { + entries.push({ + name: 'https://prebid-vast-cache.com/cache?key=' + VIDEO_CACHE_KEY, + initiatorType: 'xmlhttprequest' + }); + } + + performanceStub.withArgs('resource').returns(entries); +} + +function mockBidResponse(adUnit, requestId) { + const bid = { + 'adUnitCod': adUnit.code, + 'bidderCode': adUnit.bids[0].bidder, + 'width': adUnit.sizes[0][0], + 'height': adUnit.sizes[0][1], + 'statusMessage': 'Bid available', + 'adId': 'id', + 'requestId': requestId, + 'source': 'client', + 'no_bid': false, + 'cpm': '1.1495', + 'ttl': 180, + 'creativeId': 'id', + 'netRevenue': true, + 'currency': 'USD', + } + if (adUnit.mediaTypes.video) { + bid.videoCacheKey = VIDEO_CACHE_KEY; + } + return bid +} + +function mockBidRequest(adUnit, bidResponse) { + return { + 'bidderCode': bidResponse.bidderCode, + 'auctionId': '20882439e3238c', + 'bidderRequestId': 'bidderRequestId', + 'bids': [ + { + 'adUnitCode': adUnit.code, + 'mediaTypes': adUnit.mediaTypes, + 'bidder': bidResponse.bidderCode, + 'bidId': bidResponse.requestId, + 'sizes': adUnit.sizes, + 'params': adUnit.bids[0].params, + 'bidderRequestId': 'bidderRequestId', + 'auctionId': '20882439e3238c', + } + ], + 'auctionStart': 1505250713622, + 'timeout': 3000 + }; +} + +function getMockInput(mediaType) { + const bannerAdUnit = { + code: 'banner', + mediaTypes: {banner: {sizes: [[300, 250]]}}, + sizes: [[300, 250]], + bids: [{bidder: BIDDER_CODE, params: {placementId: 'id'}}] + }; + const outStreamAdUnit = { + code: 'video-' + OUTSTREAM, + mediaTypes: {video: {playerSize: [640, 480], context: OUTSTREAM}}, + sizes: [[640, 480]], + bids: [{bidder: BIDDER_CODE, params: {placementId: 'id'}}] + }; + const inStreamAdUnit = { + code: 'video-' + INSTREAM, + mediaTypes: {video: {playerSize: [640, 480], context: INSTREAM}}, + sizes: [[640, 480]], + bids: [{bidder: BIDDER_CODE, params: {placementId: 'id'}}] + }; + + let adUnit; + switch (mediaType) { + default: + case 'banner': + adUnit = bannerAdUnit; + break; + case OUTSTREAM: + adUnit = outStreamAdUnit; + break; + case INSTREAM: + adUnit = inStreamAdUnit; + break; + } + + const bidResponse = mockBidResponse(adUnit, utils.getUniqueIdentifierStr()); + const bidderRequest = mockBidRequest(adUnit, bidResponse); + return { + adUnits: [adUnit], + bidsReceived: [bidResponse], + bidderRequests: [bidderRequest], + }; +} + +describe('Instream Tracking', function () { + beforeEach(function () { + sandbox = sinon.sandbox.create(); + }); + + afterEach(function () { + sandbox.restore(); + }); + + describe('gaurd checks', function () { + it('skip if tracking not enable', function () { + sandbox.stub(config, 'getConfig').withArgs('instreamTracking').returns(undefined); + assert.isNotOk(trackInstreamDeliveredImpressions({ + adUnits: [], + bidsReceived: [], + bidderRequests: [] + }), 'should not start tracking when tracking is disabled'); + }); + + it('run only if instream bids are present', function () { + enableInstreamTracking(); + assert.isNotOk(trackInstreamDeliveredImpressions({adUnits: [], bidsReceived: [], bidderRequests: []})); + }); + + it('checks for instream bids', function (done) { + enableInstreamTracking(); + assert.isNotOk(trackInstreamDeliveredImpressions(getMockInput('banner')), 'should not start tracking when banner bids are present') + assert.isNotOk(trackInstreamDeliveredImpressions(getMockInput(OUTSTREAM)), 'should not start tracking when outstream bids are present') + mockPerformanceApi({}); + assert.isOk(trackInstreamDeliveredImpressions(getMockInput(INSTREAM)), 'should start tracking when instream bids are present') + setTimeout(done, 10); + }); + }); + + describe('instream bids check', function () { + let spyEventsOn; + + beforeEach(function () { + spyEventsOn = sandbox.spy(events, 'emit'); + }); + + it('BID WON event is not emitted when no video cache key entries are present', function (done) { + enableInstreamTracking(); + trackInstreamDeliveredImpressions(getMockInput(INSTREAM)); + mockPerformanceApi({}); + setTimeout(function () { + assert.isNotOk(spyEventsOn.calledWith('bidWon')) + done() + }, 10); + }); + + it('BID WON event is not emitted when ad server call is sent', function (done) { + enableInstreamTracking(); + mockPerformanceApi({adServerCallSent: true}); + setTimeout(function () { + assert.isNotOk(spyEventsOn.calledWith('bidWon')) + done() + }, 10); + }); + + it('BID WON event is emitted when video cache key is present', function (done) { + enableInstreamTracking(/cache/); + const bidWonSpy = sandbox.spy(); + events.on('bidWon', bidWonSpy); + mockPerformanceApi({adServerCallSent: true, videoPresent: true}); + + trackInstreamDeliveredImpressions(getMockInput(INSTREAM)); + setTimeout(function () { + assert.isOk(spyEventsOn.calledWith('bidWon')) + assert(bidWonSpy.args[0][0].videoCacheKey, VIDEO_CACHE_KEY, 'Video cache key in bid won should be equal to video cache call'); + done() + }, 10); + }); + }); +}); diff --git a/test/spec/modules/intentIqIdSystem_spec.js b/test/spec/modules/intentIqIdSystem_spec.js new file mode 100644 index 00000000000..2dccde18855 --- /dev/null +++ b/test/spec/modules/intentIqIdSystem_spec.js @@ -0,0 +1,143 @@ +import { expect } from 'chai'; +import {intentIqIdSubmodule} from 'modules/intentIqIdSystem.js'; +import * as utils from 'src/utils.js'; +import {server} from 'test/mocks/xhr.js'; + +const partner = 10; +const pai = '11'; +const pcid = '12'; +const defaultConfigParams = {partner: partner}; +const paiConfigParams = {partner: partner, pai: pai}; +const pcidConfigParams = {partner: partner, pcid: pcid}; +const allConfigParams = {partner: partner, pai: pai, pcid: pcid}; +const responseHeader = {'Content-Type': 'application/json'} + +describe('IntentIQ tests', function () { + let logErrorStub; + + beforeEach(function () { + logErrorStub = sinon.stub(utils, 'logError'); + }); + + afterEach(function () { + logErrorStub.restore(); + }); + + it('should log an error if no configParams were passed when getId', function () { + let submodule = intentIqIdSubmodule.getId(); + expect(logErrorStub.calledOnce).to.be.true; + expect(submodule).to.be.undefined; + }); + + it('should log an error if partner configParam was not passed when getId', function () { + let submodule = intentIqIdSubmodule.getId({}); + expect(logErrorStub.calledOnce).to.be.true; + expect(submodule).to.be.undefined; + }); + + it('should log an error if partner configParam was not a numeric value', function () { + let submodule = intentIqIdSubmodule.getId({partner: '10'}); + expect(logErrorStub.calledOnce).to.be.true; + expect(submodule).to.be.undefined; + }); + + it('should call the IntentIQ endpoint with only partner', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = intentIqIdSubmodule.getId(defaultConfigParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.intentiq.com/profiles_engine/ProfilesEngineServlet?at=39&mi=10&dpi=10&pt=17&dpn=1'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should call the IntentIQ endpoint with only partner, pai', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = intentIqIdSubmodule.getId(paiConfigParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.intentiq.com/profiles_engine/ProfilesEngineServlet?at=39&mi=10&dpi=10&pt=17&dpn=1&pai=11'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should call the IntentIQ endpoint with only partner, pcid', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = intentIqIdSubmodule.getId(pcidConfigParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.intentiq.com/profiles_engine/ProfilesEngineServlet?at=39&mi=10&dpi=10&pt=17&dpn=1&pcid=12'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should call the IntentIQ endpoint with partner, pcid, pai', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = intentIqIdSubmodule.getId(allConfigParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.intentiq.com/profiles_engine/ProfilesEngineServlet?at=39&mi=10&dpi=10&pt=17&dpn=1&pcid=12&pai=11'); + request.respond( + 200, + responseHeader, + JSON.stringify({}) + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should not throw Uncaught TypeError when IntentIQ endpoint returns empty response', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = intentIqIdSubmodule.getId(defaultConfigParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.intentiq.com/profiles_engine/ProfilesEngineServlet?at=39&mi=10&dpi=10&pt=17&dpn=1'); + request.respond( + 204, + responseHeader, + '' + ); + expect(callBackSpy.calledOnce).to.be.true; + expect(request.response).to.equal(''); + expect(logErrorStub.calledOnce).to.not.be.true; + }); + + it('should log an error and continue to callback if ajax request errors', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = intentIqIdSubmodule.getId(defaultConfigParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.intentiq.com/profiles_engine/ProfilesEngineServlet?at=39&mi=10&dpi=10&pt=17&dpn=1'); + request.respond( + 503, + responseHeader, + 'Unavailable' + ); + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should log an error and continue to callback if ajax request errors', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = intentIqIdSubmodule.getId(defaultConfigParams).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.be.eq('https://api.intentiq.com/profiles_engine/ProfilesEngineServlet?at=39&mi=10&dpi=10&pt=17&dpn=1'); + request.respond( + 503, + responseHeader, + 'Unavailable' + ); + expect(callBackSpy.calledOnce).to.be.true; + }); +}); diff --git a/test/spec/modules/invibesBidAdapter_spec.js b/test/spec/modules/invibesBidAdapter_spec.js index d21405a8b9d..442039504f8 100644 --- a/test/spec/modules/invibesBidAdapter_spec.js +++ b/test/spec/modules/invibesBidAdapter_spec.js @@ -1,5 +1,5 @@ -import { expect } from 'chai'; -import { spec, resetInvibes, stubDomainOptions } from 'modules/invibesBidAdapter.js'; +import {expect} from 'chai'; +import {spec, resetInvibes, stubDomainOptions, readGdprConsent} from 'modules/invibesBidAdapter.js'; describe('invibesBidAdapter:', function () { const BIDDER_CODE = 'invibes'; @@ -40,14 +40,15 @@ describe('invibesBidAdapter:', function () { } ]; - let StubbedPersistence = function(initialValue) { + let StubbedPersistence = function (initialValue) { var value = initialValue; return { load: function () { let str = value || ''; try { return JSON.parse(str); - } catch (e) { } + } catch (e) { + } }, save: function (obj) { value = JSON.stringify(obj); @@ -67,7 +68,7 @@ describe('invibesBidAdapter:', function () { describe('isBidRequestValid:', function () { context('valid bid request:', function () { - it('returns true when bidder params.placementId is set', function() { + it('returns true when bidder params.placementId is set', function () { const validBid = { bidder: BIDDER_CODE, params: { @@ -88,7 +89,7 @@ describe('invibesBidAdapter:', function () { expect(spec.isBidRequestValid(invalidBid)).to.be.false; }); - it('returns false when placementId is not set', function() { + it('returns false when placementId is not set', function () { const invalidBid = { bidder: BIDDER_CODE, params: { @@ -99,7 +100,7 @@ describe('invibesBidAdapter:', function () { expect(spec.isBidRequestValid(invalidBid)).to.be.false; }); - it('returns false when bid response was previously received', function() { + it('returns false when bid response was previously received', function () { const validBid = { bidder: BIDDER_CODE, params: { @@ -107,7 +108,7 @@ describe('invibesBidAdapter:', function () { } } - top.window.invibes.bidResponse = { prop: 'prop' }; + top.window.invibes.bidResponse = {prop: 'prop'}; expect(spec.isBidRequestValid(validBid)).to.be.false; }); }); @@ -126,7 +127,7 @@ describe('invibesBidAdapter:', function () { }); it('has location, html id, placement and width/height', function () { - const request = spec.buildRequests(bidRequests, { auctionStart: Date.now() }); + const request = spec.buildRequests(bidRequests, {auctionStart: Date.now()}); const parsedData = request.data; expect(parsedData.location).to.exist; expect(parsedData.videoAdHtmlId).to.exist; @@ -136,38 +137,46 @@ describe('invibesBidAdapter:', function () { }); it('has capped ids if local storage variable is correctly formatted', function () { + top.window.invibes.optIn = 1; + top.window.invibes.purposes = [true, false, false, false, false, false, false, false, false, false]; localStorage.ivvcap = '{"9731":[1,1768600800000]}'; - const request = spec.buildRequests(bidRequests, { auctionStart: Date.now() }); + const request = spec.buildRequests(bidRequests, {auctionStart: Date.now()}); expect(request.data.capCounts).to.equal('9731=1'); }); + it('does not have capped ids if local storage variable is correctly formatted but no opt in', function () { + localStorage.ivvcap = '{"9731":[1,1768600800000]}'; + const request = spec.buildRequests(bidRequests, {auctionStart: Date.now()}); + expect(request.data.capCounts).to.equal(''); + }); + it('does not have capped ids if local storage variable is incorrectly formatted', function () { localStorage.ivvcap = ':[1,1574334216992]}'; - const request = spec.buildRequests(bidRequests, { auctionStart: Date.now() }); + const request = spec.buildRequests(bidRequests, {auctionStart: Date.now()}); expect(request.data.capCounts).to.equal(''); }); it('does not have capped ids if local storage variable is expired', function () { localStorage.ivvcap = '{"9731":[1,1574330064104]}'; - const request = spec.buildRequests(bidRequests, { auctionStart: Date.now() }); + const request = spec.buildRequests(bidRequests, {auctionStart: Date.now()}); expect(request.data.capCounts).to.equal(''); }); it('sends query string params from localstorage 1', function () { - localStorage.ivbs = JSON.stringify({ bvci: 1 }); - const request = spec.buildRequests(bidRequests, { auctionStart: Date.now() }); + localStorage.ivbs = JSON.stringify({bvci: 1}); + const request = spec.buildRequests(bidRequests, {auctionStart: Date.now()}); expect(request.data.bvci).to.equal(1); }); it('sends query string params from localstorage 2', function () { - localStorage.ivbs = JSON.stringify({ invibbvlog: true }); - const request = spec.buildRequests(bidRequests, { auctionStart: Date.now() }); + localStorage.ivbs = JSON.stringify({invibbvlog: true}); + const request = spec.buildRequests(bidRequests, {auctionStart: Date.now()}); expect(request.data.invibbvlog).to.equal(true); }); it('does not send query string params from localstorage if unknwon', function () { - localStorage.ivbs = JSON.stringify({ someparam: true }); - const request = spec.buildRequests(bidRequests, { auctionStart: Date.now() }); + localStorage.ivbs = JSON.stringify({someparam: true}); + const request = spec.buildRequests(bidRequests, {auctionStart: Date.now()}); expect(request.data.someparam).to.be.undefined; }); @@ -177,78 +186,412 @@ describe('invibesBidAdapter:', function () { expect(JSON.parse(request.data.bidParamsJson).placementIds).to.contain(bidRequests[1].params.placementId); }); - it('uses cookies', function () { - global.document.cookie = 'ivNoCookie=1'; + it('sends undefined lid when no cookie', function () { let request = spec.buildRequests(bidRequests); expect(request.data.lId).to.be.undefined; }); - it('doesnt send the domain id if not graduated', function () { - global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":1522929537626,"hc":1}'; - let request = spec.buildRequests(bidRequests); - expect(request.data.lId).to.not.exist; + it('sends lid when comes on cookie', function () { + top.window.invibes.optIn = 1; + top.window.invibes.purposes = [true, false, false, false, false, false, false, false, false, false]; + global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":' + Date.now() + ',"hc":0}'; + let bidderRequest = {gdprConsent: {vendorData: {vendorConsents: {436: true}}}}; + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.lId).to.exist; }); - it('try to graduate but not enough count - doesnt send the domain id', function () { - global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":1521818537626,"hc":0}'; - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } }; + it('should send purpose 1', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendor: {consents: {436: true}}, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true, + 6: true, + 7: true, + 8: true, + 9: true, + 10: true + } + } + } + } + }; let request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.data.lId).to.not.exist; + expect(request.data.purposes.split(',')[0]).to.equal('true'); }); - it('try to graduate but not old enough - doesnt send the domain id', function () { - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } }; - global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":' + Date.now() + ',"hc":5}'; + it('should send purpose 2 & 7', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendor: {consents: {436: true}}, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true, + 6: true, + 7: true, + 8: true, + 9: true, + 10: true + } + } + } + } + }; let request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.data.lId).to.not.exist; + expect(request.data.purposes.split(',')[1] && request.data.purposes.split(',')[6]).to.equal('true'); }); - it('graduate and send the domain id', function () { - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } }; - stubDomainOptions(new StubbedPersistence('{"id":"dvdjkams6nkq","cr":1521818537626,"hc":7}')); + it('should send purpose 9', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendor: {consents: {436: true}}, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true, + 6: true, + 7: true, + 8: true, + 9: true, + 10: true + } + } + } + } + }; let request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.data.lId).to.exist; + expect(request.data.purposes.split(',')[9]).to.equal('true'); }); - it('send the domain id if already graduated', function () { - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } }; - stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi"}')); + it('should send oi = 0 when vendorData is null', function () { + let bidderRequest = { + gdprConsent: { + vendorData: null + } + }; let request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.data.lId).to.exist; - expect(top.window.invibes.dom.tempId).to.exist; + expect(request.data.oi).to.equal(0); + }); + + it('should send oi = 2 when consent was approved on tcf v2', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendor: {consents: {436: true}}, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true, + 6: true, + 7: true, + 8: true, + 9: true, + 10: true + } + } + } + } + }; + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.oi).to.equal(2); }); - it('send the domain id after replacing it with new format', function () { - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } }; - stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}')); + it('should send oi = 0 when vendor consents for invibes are false on tcf v2', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendor: {consents: {436: false}}, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true, + 6: true, + 7: true, + 8: true, + 9: true, + 10: true + } + } + } + } + }; let request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.data.lId).to.exist; - expect(top.window.invibes.dom.tempId).to.exist; + expect(request.data.oi).to.equal(0); + }); + + it('should send oi = 2 when purpose consents weren\'t approved on tcf v2', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendor: {consents: {436: true}}, + purpose: { + consents: { + 1: true, + 2: false, + 3: false, + 4: true, + 5: true, + 6: true, + 7: true, + 8: true, + 9: true, + 10: true + } + } + } + } + }; + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.oi).to.equal(2); + }); + + it('should send oi = 2 when purpose consents are less then 10 on tcf v2', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendor: {consents: {436: true}}, + purpose: { + consents: { + 1: true, + 2: false, + 3: false, + 4: true, + 5: true + } + } + } + } + }; + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.oi).to.equal(2); + }); + + it('should send oi = 4 when vendor consents are null on tcf v2', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendor: {consents: null}, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true, + 6: true, + 7: true, + 8: true, + 9: true, + 10: true + } + } + } + } + }; + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.oi).to.equal(4); }); - it('dont send the domain id if consent declined', function () { - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: false } } } }; - stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}')); + it('should send oi = 4 when vendor consents for invibes is null on tcf v2', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendor: {consents: {436: null}}, + purpose: { + consents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true, + 6: true, + 7: true, + 8: true, + 9: true, + 10: true + } + } + } + } + }; + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.oi).to.equal(4); + }); + + it('should send oi = 4 when vendor consents for invibes is null on tcf v1', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendorConsents: {436: null}, + purposeConsents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true + } + } + } + }; + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.oi).to.equal(4); + }); + + it('should send oi = 4 when vendor consents consents are null on tcf v1', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendorConsents: null, + purposeConsents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true + } + } + } + }; + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.oi).to.equal(4); + }); + + it('should send oi = 2 when gdpr doesn\'t apply or has global consent', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: false, + hasGlobalConsent: true, + } + } + }; + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.oi).to.equal(2); + }); + + it('should send oi = 2 when consent was approved on tcf v1', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendorConsents: {436: true}, + purposeConsents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true + } + } + } + }; let request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.data.lId).to.not.exist; - expect(top.window.invibes.dom.tempId).to.not.exist; + expect(request.data.oi).to.equal(2); }); - it('dont send the domain id if no consent', function () { - let bidderRequest = { }; - stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}')); + it('should send oi = 2 when purpose consents weren\'t approved on tcf v1', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendorConsents: {436: true}, + purposeConsents: { + 1: false, + 2: false, + 3: true, + 4: true, + 5: true + } + } + } + }; let request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.data.lId).to.not.exist; - expect(top.window.invibes.dom.tempId).to.not.exist; + expect(request.data.oi).to.equal(2); }); - it('try to init id but was already loaded on page - does not increment the id again', function () { - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } }; - global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":1521818537626,"hc":0}'; + it('should send oi = 2 when purpose consents are less then 5 on tcf v1', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendorConsents: {436: true}, + purposeConsents: { + 1: false, + 2: false, + 3: true + } + } + } + }; let request = spec.buildRequests(bidRequests, bidderRequest); - request = spec.buildRequests(bidRequests, bidderRequest); - expect(request.data.lId).to.not.exist; - expect(top.window.invibes.dom.tempId).to.exist; + expect(request.data.oi).to.equal(2); + }); + + it('should send oi = 0 when vendor consents for invibes are false on tcf v1', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendorConsents: {436: false}, + purposeConsents: { + 1: true, + 2: true, + 3: true, + 4: true, + 5: true + } + } + } + }; + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.oi).to.equal(0); }); }); @@ -285,59 +628,69 @@ describe('invibesBidAdapter:', function () { context('when the response is not valid', function () { it('handles response with no bids requested', function () { - let emptyResult = spec.interpretResponse({ body: response }); + let emptyResult = spec.interpretResponse({body: response}); expect(emptyResult).to.be.empty; }); it('handles empty response', function () { - let emptyResult = spec.interpretResponse(null, { bidRequests }); + let emptyResult = spec.interpretResponse(null, {bidRequests}); expect(emptyResult).to.be.empty; }); it('handles response with bidding is not configured', function () { - let emptyResult = spec.interpretResponse({ body: { Ads: [{ BidPrice: 1 }] } }, { bidRequests }); + let emptyResult = spec.interpretResponse({body: {Ads: [{BidPrice: 1}]}}, {bidRequests}); expect(emptyResult).to.be.empty; }); it('handles response with no ads are received', function () { - let emptyResult = spec.interpretResponse({ body: { BidModel: { PlacementId: '12345' }, AdReason: 'No ads' } }, { bidRequests }); + let emptyResult = spec.interpretResponse({ + body: { + BidModel: {PlacementId: '12345'}, + AdReason: 'No ads' + } + }, {bidRequests}); expect(emptyResult).to.be.empty; }); it('handles response with no ads are received - no ad reason', function () { - let emptyResult = spec.interpretResponse({ body: { BidModel: { PlacementId: '12345' } } }, { bidRequests }); + let emptyResult = spec.interpretResponse({body: {BidModel: {PlacementId: '12345'}}}, {bidRequests}); expect(emptyResult).to.be.empty; }); it('handles response when no placement Id matches', function () { - let emptyResult = spec.interpretResponse({ body: { BidModel: { PlacementId: '123456' }, Ads: [{ BidPrice: 1 }] } }, { bidRequests }); + let emptyResult = spec.interpretResponse({ + body: { + BidModel: {PlacementId: '123456'}, + Ads: [{BidPrice: 1}] + } + }, {bidRequests}); expect(emptyResult).to.be.empty; }); it('handles response when placement Id is not present', function () { - let emptyResult = spec.interpretResponse({ BidModel: { }, Ads: [{ BidPrice: 1 }] }, { bidRequests }); + let emptyResult = spec.interpretResponse({BidModel: {}, Ads: [{BidPrice: 1}]}, {bidRequests}); expect(emptyResult).to.be.empty; }); }); context('when the response is valid', function () { it('responds with a valid bid', function () { - top.window.invibes.setCookie('a', 'b', 370); - top.window.invibes.setCookie('c', 'd', 0); - let result = spec.interpretResponse({ body: response }, { bidRequests }); + // top.window.invibes.setCookie('a', 'b', 370); + // top.window.invibes.setCookie('c', 'd', 0); + let result = spec.interpretResponse({body: response}, {bidRequests}); expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); }); it('responds with a valid bid and uses logger', function () { localStorage.InvibesDEBUG = true; - let result = spec.interpretResponse({ body: response }, { bidRequests }); + let result = spec.interpretResponse({body: response}, {bidRequests}); expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); }); it('does not make multiple bids', function () { localStorage.InvibesDEBUG = false; - let result = spec.interpretResponse({ body: response }, { bidRequests }); - let secondResult = spec.interpretResponse({ body: response }, { bidRequests }); + let result = spec.interpretResponse({body: response}, {bidRequests}); + let secondResult = spec.interpretResponse({body: response}, {bidRequests}); expect(secondResult).to.be.empty; }); }); @@ -353,7 +706,17 @@ describe('invibesBidAdapter:', function () { it('returns an iframe with params if enabled', function () { top.window.invibes.optIn = 1; global.document.cookie = 'ivvbks=17639.0,1,2'; - let response = spec.getUserSyncs({ iframeEnabled: true }); + let response = spec.getUserSyncs({iframeEnabled: true}); + expect(response.type).to.equal('iframe'); + expect(response.url).to.include(SYNC_ENDPOINT); + expect(response.url).to.include('optIn'); + expect(response.url).to.include('ivvbks'); + }); + + it('returns an iframe with params including if enabled', function () { + top.window.invibes.optIn = 1; + global.document.cookie = 'ivvbks=17639.0,1,2;ivbsdid={"id":"dvdjkams6nkq","cr":' + Date.now() + ',"hc":0}'; + let response = spec.getUserSyncs({iframeEnabled: true}); expect(response.type).to.equal('iframe'); expect(response.url).to.include(SYNC_ENDPOINT); expect(response.url).to.include('optIn'); @@ -362,7 +725,7 @@ describe('invibesBidAdapter:', function () { }); it('returns undefined if iframe not enabled ', function () { - let response = spec.getUserSyncs({ iframeEnabled: false }); + let response = spec.getUserSyncs({iframeEnabled: false}); expect(response).to.equal(undefined); }); }); diff --git a/test/spec/modules/ironsourceBidAdapter_spec.js b/test/spec/modules/ironsourceBidAdapter_spec.js new file mode 100644 index 00000000000..cfdc51e0235 --- /dev/null +++ b/test/spec/modules/ironsourceBidAdapter_spec.js @@ -0,0 +1,339 @@ +import { expect } from 'chai'; +import { spec } from 'modules/ironsourceBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import { config } from 'src/config.js'; +import { VIDEO } from '../../../src/mediaTypes.js'; + +const ENDPOINT = 'https://hb.yellowblue.io/hb'; +const TTL = 360; + +describe('ironsourceAdapter', function () { + const adapter = newBidder(spec); + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + const bid = { + 'bidder': spec.code, + 'adUnitCode': 'adunit-code', + 'sizes': [['640', '480']], + 'params': { + 'isOrg': 'jdye8weeyirk00000001' + } + }; + + it('should return true when required params are passed', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not found', function () { + const newBid = Object.assign({}, bid); + delete newBid.params; + newBid.params = { + 'isOrg': null + }; + expect(spec.isBidRequestValid(newBid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + const bidRequests = [ + { + 'bidder': spec.code, + 'adUnitCode': 'adunit-code', + 'sizes': [[640, 480]], + 'params': { + 'isOrg': 'jdye8weeyirk00000001' + }, + 'bidId': '299ffc8cca0b87', + 'bidderRequestId': '1144f487e563f9', + 'auctionId': 'bfc420c3-8577-4568-9766-a8a935fb620d', + } + ]; + + const bidderRequest = { + bidderCode: 'ironsource', + } + + it('sends bid request to ENDPOINT via GET', function () { + const requests = spec.buildRequests(bidRequests, bidderRequest); + for (const request of requests) { + expect(request.url).to.equal(ENDPOINT); + expect(request.method).to.equal('GET'); + } + }); + + it('should send the correct bid Id', function () { + const requests = spec.buildRequests(bidRequests, bidderRequest); + for (const request of requests) { + expect(request.data.bid_id).to.equal('299ffc8cca0b87'); + } + }); + + it('should send the correct width and height', function () { + const requests = spec.buildRequests(bidRequests, bidderRequest); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.have.property('width', 640); + expect(request.data).to.have.property('height', 480); + } + }); + + it('should respect syncEnabled option', function() { + config.setConfig({ + userSync: { + syncEnabled: false, + filterSettings: { + all: { + bidders: '*', + filter: 'include' + } + } + } + }); + const requests = spec.buildRequests(bidRequests, bidderRequest); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.not.have.property('cs_method'); + } + }); + + it('should respect "iframe" filter settings', function () { + config.setConfig({ + userSync: { + syncEnabled: true, + filterSettings: { + iframe: { + bidders: [spec.code], + filter: 'include' + } + } + } + }); + const requests = spec.buildRequests(bidRequests, bidderRequest); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.have.property('cs_method', 'iframe'); + } + }); + + it('should respect "all" filter settings', function () { + config.setConfig({ + userSync: { + syncEnabled: true, + filterSettings: { + all: { + bidders: [spec.code], + filter: 'include' + } + } + } + }); + const requests = spec.buildRequests(bidRequests, bidderRequest); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.have.property('cs_method', 'iframe'); + } + }); + + it('should send the pixel user sync param if userSync is enabled and no "iframe" or "all" configs are present', function () { + config.setConfig({ + userSync: { + syncEnabled: true + } + }); + const requests = spec.buildRequests(bidRequests, bidderRequest); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.have.property('cs_method', 'pixel'); + } + }); + + it('should respect total exclusion', function() { + config.setConfig({ + userSync: { + syncEnabled: true, + filterSettings: { + image: { + bidders: [spec.code], + filter: 'exclude' + }, + iframe: { + bidders: [spec.code], + filter: 'exclude' + } + } + } + }); + const requests = spec.buildRequests(bidRequests, bidderRequest); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.not.have.property('cs_method'); + } + }); + + it('should have us_privacy param if usPrivacy is available in the bidRequest', function () { + const bidderRequestWithUSP = Object.assign({uspConsent: '1YNN'}, bidderRequest); + const requests = spec.buildRequests(bidRequests, bidderRequestWithUSP); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.have.property('us_privacy', '1YNN'); + } + }); + + it('should have an empty us_privacy param if usPrivacy is missing in the bidRequest', function () { + const requests = spec.buildRequests(bidRequests, bidderRequest); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.not.have.property('us_privacy'); + } + }); + + it('should not send the gdpr param if gdprApplies is false in the bidRequest', function () { + const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: false}}, bidderRequest); + const requests = spec.buildRequests(bidRequests, bidderRequestWithGDPR); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.not.have.property('gdpr'); + expect(request.data).to.not.have.property('gdpr_consent'); + } + }); + + it('should send the gdpr param if gdprApplies is true in the bidRequest', function () { + const bidderRequestWithGDPR = Object.assign({gdprConsent: {gdprApplies: true, consentString: 'test-consent-string'}}, bidderRequest); + const requests = spec.buildRequests(bidRequests, bidderRequestWithGDPR); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.have.property('gdpr', true); + expect(request.data).to.have.property('gdpr_consent', 'test-consent-string'); + } + }); + + it('should have schain param if it is available in the bidRequest', () => { + const schain = { + ver: '1.0', + complete: 1, + nodes: [{ asi: 'indirectseller.com', sid: '00001', hp: 1 }], + }; + bidRequests[0].schain = schain; + const requests = spec.buildRequests(bidRequests, bidderRequest); + for (const request of requests) { + expect(request.data).to.be.an('object'); + expect(request.data).to.have.property('schain', '1.0,1!indirectseller.com,00001,,,,'); + } + }); + }); + + describe('interpretResponse', function () { + const response = { + cpm: 12.5, + vastXml: '', + width: 640, + height: 480, + requestId: '21e12606d47ba7', + netRevenue: true, + currency: 'USD' + }; + + it('should get correct bid response', function () { + let expectedResponse = [ + { + requestId: '21e12606d47ba7', + cpm: 12.5, + width: 640, + height: 480, + creativeId: '21e12606d47ba7', + currency: 'USD', + netRevenue: true, + ttl: TTL, + vastXml: '', + mediaType: VIDEO + } + ]; + const result = spec.interpretResponse({ body: [response] }); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + }); + }) + + describe('getUserSyncs', function() { + const imageSyncResponse = { + body: { + userSyncPixels: [ + 'https://image-sync-url.test/1', + 'https://image-sync-url.test/2', + 'https://image-sync-url.test/3' + ] + } + }; + + const iframeSyncResponse = { + body: { + userSyncURL: 'https://iframe-sync-url.test' + } + }; + + it('should register all img urls from the response', function() { + const syncs = spec.getUserSyncs({ pixelEnabled: true }, [imageSyncResponse]); + expect(syncs).to.deep.equal([ + { + type: 'image', + url: 'https://image-sync-url.test/1' + }, + { + type: 'image', + url: 'https://image-sync-url.test/2' + }, + { + type: 'image', + url: 'https://image-sync-url.test/3' + } + ]); + }); + + it('should register the iframe url from the response', function() { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, [iframeSyncResponse]); + expect(syncs).to.deep.equal([ + { + type: 'iframe', + url: 'https://iframe-sync-url.test' + } + ]); + }); + + it('should register both image and iframe urls from the responses', function() { + const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: true }, [iframeSyncResponse, imageSyncResponse]); + expect(syncs).to.deep.equal([ + { + type: 'iframe', + url: 'https://iframe-sync-url.test' + }, + { + type: 'image', + url: 'https://image-sync-url.test/1' + }, + { + type: 'image', + url: 'https://image-sync-url.test/2' + }, + { + type: 'image', + url: 'https://image-sync-url.test/3' + } + ]); + }); + + it('should handle an empty response', function() { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, []); + expect(syncs).to.deep.equal([]); + }); + + it('should handle when user syncs are disabled', function() { + const syncs = spec.getUserSyncs({ pixelEnabled: false }, [imageSyncResponse]); + expect(syncs).to.deep.equal([]); + }); + }) +}); diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 114a2226770..63b04077f4e 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -5,7 +5,7 @@ import { newBidder } from 'src/adapters/bidderFactory.js'; import { spec } from 'modules/ixBidAdapter.js'; describe('IndexexchangeAdapter', function () { - const IX_SECURE_ENDPOINT = 'https://as-sec.casalemedia.com/cygnus'; + const IX_SECURE_ENDPOINT = 'https://htlb.casalemedia.com/cygnus'; const VIDEO_ENDPOINT_VERSION = 8.1; const BANNER_ENDPOINT_VERSION = 7.2; @@ -110,6 +110,35 @@ describe('IndexexchangeAdapter', function () { ] }; + const DEFAULT_BANNER_BID_RESPONSE_WITHOUT_ADOMAIN = { + cur: 'USD', + id: '11a22b33c44d', + seatbid: [ + { + bid: [ + { + crid: '12345', + adid: '14851455', + impid: '1a2b3c4d', + cid: '3051266', + price: 100, + w: 300, + h: 250, + id: '1', + ext: { + dspid: 50, + pricelevel: '_100', + advbrandid: 303325, + advbrand: 'OECTA' + }, + adm: '' + } + ], + seat: '3970' + } + ] + }; + const DEFAULT_VIDEO_BID_RESPONSE = { cur: 'USD', id: '1aa2bb3cc4de', @@ -190,6 +219,22 @@ describe('IndexexchangeAdapter', function () { v: 8.1 }; + const DEFAULT_USERID_DATA = { + idl_env: '1234-5678-9012-3456', // Liveramp + }; + + const DEFAULT_USERID_PAYLOAD = [ + { + source: 'liveramp.com', + uids: [{ + id: DEFAULT_USERID_DATA.idl_env, + ext: { + rtiPartner: 'idl' + } + }] + } + ]; + describe('inherited functions', function () { it('should exists and is a function', function () { const adapter = newBidder(spec); @@ -365,13 +410,16 @@ describe('IndexexchangeAdapter', function () { request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; query = request.data; }); + afterEach(function () { delete window.headertag; }); + describe('buildRequestSingleRTI', function () { before(function () { testCopy = JSON.parse(JSON.stringify(DEFAULT_IDENTITY_RESPONSE)); }); + it('payload should have correct format and value (single identity partner)', function () { const payload = JSON.parse(query.r); @@ -400,6 +448,7 @@ describe('IndexexchangeAdapter', function () { } ); }); + it('payload should have correct format and value (single identity w/ multi ids)', function () { const payload = JSON.parse(query.r); @@ -443,6 +492,7 @@ describe('IndexexchangeAdapter', function () { } } }); + it('payload should have correct format and value (multiple identity partners)', function () { const payload = JSON.parse(query.r); @@ -519,6 +569,177 @@ describe('IndexexchangeAdapter', function () { }); }); + describe('buildRequestsUserId', function () { + let validIdentityResponse; + let validUserIdPayload; + + beforeEach(function () { + window.headertag = {}; + window.headertag.getIdentityInfo = function () { + return validIdentityResponse; + }; + }); + + afterEach(function () { + delete window.headertag; + }); + + it('IX adapter reads LiveRamp IDL envelope from Prebid and adds it to Video', function () { + const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); + cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA); + + const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; + const payload = JSON.parse(request.data.r); + + expect(payload.user.eids).to.have.lengthOf(1); + expect(payload.user.eids).to.deep.include(DEFAULT_USERID_PAYLOAD[0]); + }); + + it('We continue to send in IXL identity info and Prebid takes precedence over IXL', function () { + validIdentityResponse = { + AdserverOrgIp: { + responsePending: false, + data: { + source: 'adserver.org', + uids: [ + { + id: '1234-5678-9012-3456', + ext: { + rtiPartner: 'TDID' + } + }, + { + id: 'FALSE', + ext: { + rtiPartner: 'TDID_LOOKUP' + } + }, + { + id: '2020-06-24T14:43:48.860Z', + ext: { + rtiPartner: 'TDID_CREATED_AT' + } + } + ] + } + }, + MerkleIp: { + responsePending: false, + data: { + source: 'merkle.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + enc: 1 + } + }] + } + }, + LiveRampIp: { + source: 'liveramp.com', + uids: [ + { + id: '0000-1234-4567-8901', + ext: { + rtiPartner: 'idl' + } + } + ] + } + }; + + const cloneValidBid = utils.deepClone(DEFAULT_BANNER_VALID_BID); + cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA) + + const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; + const payload = JSON.parse(request.data.r); + + validUserIdPayload = utils.deepClone(DEFAULT_USERID_PAYLOAD); + validUserIdPayload.push({ + source: 'merkle.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + enc: 1 + } + }] + }) + validUserIdPayload.push({ + source: 'adserver.org', + uids: [ + { + id: '1234-5678-9012-3456', + ext: { + rtiPartner: 'TDID' + } + }, + { + id: 'FALSE', + ext: { + rtiPartner: 'TDID_LOOKUP' + } + }, + { + id: '2020-06-24T14:43:48.860Z', + ext: { + rtiPartner: 'TDID_CREATED_AT' + } + } + ] + }) + + expect(payload.user).to.exist; + expect(payload.user.eids).to.have.lengthOf(3); + expect(payload.user.eids).to.deep.include(validUserIdPayload[0]); + expect(payload.user.eids).to.deep.include(validUserIdPayload[1]); + expect(payload.user.eids).to.deep.include(validUserIdPayload[2]); + }); + + it('IXL and Prebid are mutually exclusive', function () { + validIdentityResponse = { + LiveIntentIp: { + responsePending: false, + data: { + source: 'liveintent.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + rtiPartner: 'LDID', + enc: 1 + } + }] + } + } + }; + + const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); + cloneValidBid[0].userId = utils.deepClone(DEFAULT_USERID_DATA); + + const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; + + validUserIdPayload = utils.deepClone(DEFAULT_USERID_PAYLOAD); + validUserIdPayload.push({ + source: 'liveintent.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + rtiPartner: 'LDID', + enc: 1 + } + }] + }); + + const payload = JSON.parse(request.data.r); + expect(payload.user.eids).to.have.lengthOf(2); + expect(payload.user.eids).to.deep.include(validUserIdPayload[0]); + expect(payload.user.eids).to.deep.include(validUserIdPayload[1]); + }); + }); + describe('buildRequests', function () { const request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; const requestUrl = request.url; @@ -561,7 +782,7 @@ describe('IndexexchangeAdapter', function () { expect(payload.source.ext.schain).to.deep.equal(SAMPLE_SCHAIN); expect(payload.imp).to.exist; expect(payload.imp).to.be.an('array'); - expect(payload.imp).to.have.lengthOf(1); + expect(payload.imp).to.have.lengthOf(2); }); it('payload should not include schain when not provided', function () { @@ -735,6 +956,7 @@ describe('IndexexchangeAdapter', function () { const request = spec.buildRequests([DEFAULT_BANNER_VALID_BID[0], DEFAULT_VIDEO_VALID_BID[0]]); const bannerImp = JSON.parse(request[0].data.r).imp[0]; + expect(JSON.parse(request[0].data.r).imp).to.have.lengthOf(2); expect(JSON.parse(request[0].data.v)).to.equal(BANNER_ENDPOINT_VERSION); expect(bannerImp.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); expect(bannerImp.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId); @@ -749,6 +971,80 @@ describe('IndexexchangeAdapter', function () { expect(videoImp.video.w).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.size[0]); expect(videoImp.video.h).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.size[1]); }); + + it('request should contain the extra banner ad sizes that IX is not configured for using the first site id in the ad unit', function () { + const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); + bid.sizes.push([336, 280], [970, 90]); + bid.mediaTypes.banner.sizes.push([336, 280], [970, 90]); + const bid2 = utils.deepClone(bid); + bid2.params.siteId = '124'; + bid2.params.size = [300, 600]; + bid2.params.bidId = '2b3c4d5e'; + + const request = spec.buildRequests([bid, bid2], DEFAULT_OPTION)[0]; + const impressions = JSON.parse(request.data.r).imp; + + expect(impressions).to.be.an('array'); + expect(impressions).to.have.lengthOf(4); + + expect(impressions[0].ext.siteID).to.equal(DEFAULT_BANNER_VALID_BID[0].params.siteId.toString()) + expect(impressions[1].ext.siteID).to.equal(bid2.params.siteId) + expect(impressions[2].ext.siteID).to.equal(DEFAULT_BANNER_VALID_BID[0].params.siteId.toString()) + expect(impressions[3].ext.siteID).to.equal(DEFAULT_BANNER_VALID_BID[0].params.siteId.toString()) + + expect(impressions[0].banner.w).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[0]); + expect(impressions[0].banner.h).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[1]); + expect(impressions[1].banner.w).to.equal(bid2.params.size[0]); + expect(impressions[1].banner.h).to.equal(bid2.params.size[1]); + expect(impressions[2].banner.w).to.equal(bid.mediaTypes.banner.sizes[2][0]); + expect(impressions[2].banner.h).to.equal(bid.mediaTypes.banner.sizes[2][1]); + expect(impressions[3].banner.w).to.equal(bid.mediaTypes.banner.sizes[3][0]); + expect(impressions[3].banner.h).to.equal(bid.mediaTypes.banner.sizes[3][1]); + }); + + it('request should contain the extra banner ad sizes and their corresponding site ids when there is multiple ad units', function () { + const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); + bid.params.siteId = '124'; + bid.adUnitCode = 'div-gpt-ad-156456451554-1' + bid.transactionId = '152e36d1-1241-4242-t35e-y1dv34d12315'; + bid.bidId = '2f6g5s5e'; + bid.params.size = [336, 280] + bid.sizes = [[336, 280], [970, 90]] + bid.mediaTypes.banner.sizes = [[336, 280], [970, 90]] + + const request = spec.buildRequests([DEFAULT_BANNER_VALID_BID[0], bid], DEFAULT_OPTION)[0]; + + const impressions = JSON.parse(request.data.r).imp; + expect(impressions).to.be.an('array'); + expect(impressions).to.have.lengthOf(4); + + expect(impressions[0].ext.siteID).to.equal(DEFAULT_BANNER_VALID_BID[0].params.siteId.toString()) + expect(impressions[1].ext.siteID).to.equal(bid.params.siteId) + expect(impressions[2].ext.siteID).to.equal(DEFAULT_BANNER_VALID_BID[0].params.siteId.toString()) + expect(impressions[3].ext.siteID).to.equal(bid.params.siteId) + + expect(impressions[0].banner.w).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[0]); + expect(impressions[0].banner.h).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[1]); + expect(impressions[1].banner.w).to.equal(bid.params.size[0]); + expect(impressions[1].banner.h).to.equal(bid.params.size[1]); + expect(impressions[2].banner.w).to.equal(DEFAULT_BANNER_VALID_BID[0].mediaTypes.banner.sizes[1][0]); + expect(impressions[2].banner.h).to.equal(DEFAULT_BANNER_VALID_BID[0].mediaTypes.banner.sizes[1][1]); + expect(impressions[3].banner.w).to.equal(bid.mediaTypes.banner.sizes[1][0]); + expect(impressions[3].banner.h).to.equal(bid.mediaTypes.banner.sizes[1][1]); + + expect(impressions[0].ext.sid).to.equal(`${DEFAULT_BANNER_VALID_BID[0].params.size[0].toString()}x${DEFAULT_BANNER_VALID_BID[0].params.size[1].toString()}`); + expect(impressions[1].ext.sid).to.equal(`${bid.params.size[0].toString()}x${bid.params.size[1].toString()}`); + expect(impressions[2].ext.sid).to.equal(`${DEFAULT_BANNER_VALID_BID[0].mediaTypes.banner.sizes[1][0].toString()}x${DEFAULT_BANNER_VALID_BID[0].mediaTypes.banner.sizes[1][1].toString()}`); + expect(impressions[3].ext.sid).to.equal(`${bid.mediaTypes.banner.sizes[1][0].toString()}x${bid.mediaTypes.banner.sizes[1][1].toString()}`); + }); + + it('request should not contain the extra video ad sizes that IX is not configured for', function () { + const request = spec.buildRequests(DEFAULT_VIDEO_VALID_BID, DEFAULT_OPTION); + const impressions = JSON.parse(request[0].data.r).imp; + + expect(impressions).to.be.an('array'); + expect(impressions).to.have.lengthOf(1); + }); }); describe('buildRequestVideo', function () { @@ -835,7 +1131,8 @@ describe('IndexexchangeAdapter', function () { meta: { networkId: 50, brandId: 303325, - brandName: 'OECTA' + brandName: 'OECTA', + advertiserDomains: ['www.abc.com'] } } ]; @@ -843,6 +1140,31 @@ describe('IndexexchangeAdapter', function () { expect(result[0]).to.deep.equal(expectedParse[0]); }); + it('should get correct bid response for banner ad with missing adomain', function () { + const expectedParse = [ + { + requestId: '1a2b3c4d', + cpm: 1, + creativeId: '12345', + width: 300, + height: 250, + mediaType: 'banner', + ad: '', + currency: 'USD', + ttl: 300, + netRevenue: true, + dealId: undefined, + meta: { + networkId: 50, + brandId: 303325, + brandName: 'OECTA' + } + } + ]; + const result = spec.interpretResponse({ body: DEFAULT_BANNER_BID_RESPONSE_WITHOUT_ADOMAIN }, { data: DEFAULT_BIDDER_REQUEST_DATA }); + expect(result[0]).to.deep.equal(expectedParse[0]); + }); + it('should set creativeId to default value if not provided', function () { const bidResponse = utils.deepClone(DEFAULT_BANNER_BID_RESPONSE); delete bidResponse.seatbid[0].bid[0].crid; @@ -862,7 +1184,8 @@ describe('IndexexchangeAdapter', function () { meta: { networkId: 50, brandId: 303325, - brandName: 'OECTA' + brandName: 'OECTA', + advertiserDomains: ['www.abc.com'] } } ]; @@ -888,7 +1211,8 @@ describe('IndexexchangeAdapter', function () { meta: { networkId: 50, brandId: 303325, - brandName: 'OECTA' + brandName: 'OECTA', + advertiserDomains: ['www.abc.com'] } } ]; @@ -915,7 +1239,8 @@ describe('IndexexchangeAdapter', function () { meta: { networkId: 50, brandId: 303325, - brandName: 'OECTA' + brandName: 'OECTA', + advertiserDomains: ['www.abc.com'] } } ]; @@ -940,7 +1265,8 @@ describe('IndexexchangeAdapter', function () { meta: { networkId: 51, brandId: 303326, - brandName: 'OECTB' + brandName: 'OECTB', + advertiserDomains: ['www.abcd.com'] } } ]; diff --git a/test/spec/modules/jixieBidAdapter_spec.js b/test/spec/modules/jixieBidAdapter_spec.js new file mode 100644 index 00000000000..842f9e0ed30 --- /dev/null +++ b/test/spec/modules/jixieBidAdapter_spec.js @@ -0,0 +1,597 @@ +import { expect } from 'chai'; +import { spec, internal as jixieaux, storage } from 'modules/jixieBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import { config } from 'src/config.js'; + +describe('jixie Adapter', function () { + const pageurl_ = 'https://testdomain.com/testpage.html'; + const domain_ = 'https://testdomain.com'; + const device_ = 'desktop'; + const timeout_ = 1000; + const currency_ = 'USD'; + + /** + * Basic + */ + const adapter = newBidder(spec); + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + /** + * isBidRequestValid + */ + describe('isBidRequestValid', function () { + let bid = { + 'bidder': 'jixie', + 'params': { + 'unit': 'prebidsampleunit' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params obj does not exist', function () { + let bid0 = Object.assign({}, bid); + delete bid0.params; + expect(spec.isBidRequestValid(bid0)).to.equal(false); + }); + + it('should return false when params obj does not contain unit property', function () { + let bid1 = Object.assign({}, bid); + bid1.params = { rubbish: '' }; + expect(spec.isBidRequestValid(bid1)).to.equal(false); + }); + });// describe + + /** + * buildRequests + */ + describe('buildRequests', function () { + const adUnitCode0_ = 'adunit-code-0'; + const adUnitCode1_ = 'adunit-code-1'; + const adUnitCode2_ = 'adunit-code-2'; + + const bidId0_ = '22a9eb5004cf082'; + const bidId1_ = '230fceb12fd754f'; + const bidId2_ = '24dbe5c4fb80ed8'; + + const bidderRequestId_ = '2131ce076eeaa1b'; + const auctionId_ = '26d68819-d6ce-4a2c-a4d3-f1a97b159d66'; + + const clientIdTest1_ = '1aba6a40-f711-11e9-868c-53a2ae972xxx'; + const sessionIdTest1_ = '1594782644-1aba6a40-f711-11e9-868c-53a2ae972xxx'; + + // to serve as the object that prebid will call jixie buildRequest with: (param2) + const bidderRequest_ = { + refererInfo: {referer: pageurl_}, + auctionId: auctionId_, + timeout: timeout_ + }; + // to serve as the object that prebid will call jixie buildRequest with: (param1) + let bidRequests_ = [ + { + 'bidder': 'jixie', + 'params': { + 'unit': 'prebidsampleunit' + }, + 'sizes': [[300, 250], [300, 600]], + 'adUnitCode': adUnitCode0_, + 'bidId': bidId0_, + 'bidderRequestId': bidderRequestId_, + 'auctionId': auctionId_ + }, + { + 'bidder': 'jixie', + 'params': { + 'unit': 'prebidsampleunit' + }, + 'sizes': [[300, 250]], + 'mediaTypes': { + 'video': { + 'playerSize': [640, 360] + }, + 'banner': { + 'sizes': [[300, 250]] + } + }, + 'adUnitCode': adUnitCode1_, + 'bidId': bidId1_, + 'bidderRequestId': bidderRequestId_, + 'auctionId': auctionId_ + }, + { + 'bidder': 'jixie', + 'params': { + 'unit': 'prebidsampleunit' + }, + 'sizes': [[300, 250], [300, 600]], + 'mediaTypes': { + 'video': { + 'playerSize': [640, 360] + }, + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, + 'adUnitCode': adUnitCode2_, + 'bidId': bidId2_, + 'bidderRequestId': bidderRequestId_, + 'auctionId': auctionId_ + } + ]; + + // To serve as a reference to check against the bids array portion of the blob that the call to + // buildRequest returns + const refBids_ = [ + { + 'bidId': bidId0_, + 'adUnitCode': adUnitCode0_, + 'sizes': [[300, 250], [300, 600]], + 'params': { + 'unit': 'prebidsampleunit' + } + }, + { + 'bidId': bidId1_, + 'adUnitCode': adUnitCode1_, + 'mediaTypes': { + 'video': { + 'playerSize': [640, 360] + }, + 'banner': { + 'sizes': [[300, 250]] + } + }, + 'sizes': [[300, 250]], + 'params': { + 'unit': 'prebidsampleunit' + } + }, + { + 'bidId': bidId2_, + 'adUnitCode': adUnitCode2_, + 'mediaTypes': { + 'video': { + 'playerSize': [640, 360] + }, + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, + 'sizes': [[300, 250], [300, 600]], + 'params': { + 'unit': 'prebidsampleunit' + } + } + ]; + + it('should attach valid params to the adserver endpoint (1)', function () { + // this one we do not intercept the cookie stuff so really don't know + // what will be in there. so we do not check here (using expect) + // The next next below we check + const request = spec.buildRequests(bidRequests_, bidderRequest_); + it('sends bid request to ENDPOINT via POST', function () { + expect(request.method).to.equal('POST') + }) + expect(request.data).to.be.an('string'); + const payload = JSON.parse(request.data); + expect(payload).to.have.property('auctionid', auctionId_); + expect(payload).to.have.property('timeout', timeout_); + expect(payload).to.have.property('currency', currency_); + expect(payload).to.have.property('bids').that.deep.equals(refBids_); + });// it + + it('should attach valid params to the adserver endpoint (2)', function () { + // similar to above test case but here we force some clientid sessionid values + // and domain, pageurl + // get the interceptors ready: + let getCookieStub = sinon.stub(storage, 'getCookie'); + let getLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); + getCookieStub + .withArgs('_jx') + .returns(clientIdTest1_); + getCookieStub + .withArgs('_jxs') + .returns(sessionIdTest1_); + getLocalStorageStub + .withArgs('_jx') + .returns(clientIdTest1_); + getLocalStorageStub + .withArgs('_jxs') + .returns(sessionIdTest1_ + ); + let miscDimsStub = sinon.stub(jixieaux, 'getMiscDims'); + miscDimsStub + .returns({ device: device_, pageurl: pageurl_, domain: domain_ }); + + // actual api call: + const request = spec.buildRequests(bidRequests_, bidderRequest_); + it('sends bid request to ENDPOINT via POST', function () { + expect(request.method).to.equal('POST') + }) + expect(request.data).to.be.an('string'); + const payload = JSON.parse(request.data); + expect(payload).to.have.property('auctionid', auctionId_); + expect(payload).to.have.property('client_id_c', clientIdTest1_); + expect(payload).to.have.property('client_id_ls', clientIdTest1_); + expect(payload).to.have.property('session_id_c', sessionIdTest1_); + expect(payload).to.have.property('session_id_ls', sessionIdTest1_); + expect(payload).to.have.property('device', device_); + expect(payload).to.have.property('domain', domain_); + expect(payload).to.have.property('pageurl', pageurl_); + expect(payload).to.have.property('timeout', timeout_); + expect(payload).to.have.property('currency', currency_); + expect(payload).to.have.property('bids').that.deep.equals(refBids_); + + // unwire interceptors + getCookieStub.restore(); + getLocalStorageStub.restore(); + miscDimsStub.restore(); + });// it + });// describe + + /** + * interpretResponse: + */ + const JX_OTHER_OUTSTREAM_RENDERER_URL = 'https://scripts.jixie.io/dummyscript.js'; + const JX_OUTSTREAM_RENDERER_URL = 'https://scripts.jixie.io/jxhboutstream.js'; + + const mockVastXml_ = `JXADSERVERAlway%20Live%20Prebid%20CreativeHybrid in-stream00:00:10`; + const responseBody_ = { + 'bids': [ + // video (vast tag url) returned here + { + 'trackingUrlBase': 'https://tr.jixie.io/sync/ad?', + 'jxBidId': '62847e4c696edcb-028d5dee-2c83-44e3-bed1-b75002475cdf', + 'requestId': '62847e4c696edcb', + 'cpm': 2.19, + 'width': 640, + 'height': 360, + 'ttl': 300, + 'adUnitCode': 'demoslot3-div', + 'netRevenue': true, + 'currency': 'USD', + 'creativeId': 'jixie522', + 'meta': { + 'networkId': 123, + 'networkName': 'network123', + 'agencyId': 123, + 'agencyName': 'agency123', + 'advertiserId': 123, + 'advertiserName': 'advertiser123', + 'brandId': 123, + 'brandName': 'brand123', + 'primaryCatId': 1, + 'secondaryCatIds': [ + 2, + 3, + 4 + ], + 'mediaType': 'VIDEO' + }, + 'vastUrl': 'https://ad.jixie.io/v1/video?creativeid=522' + }, + // display ad returned here: + { + 'trackingUrlBase': 'https://tr.jixie.io/sync/ad?', + 'jxBidId': '600c9ae6fda1acb-028d5dee-2c83-44e3-bed1-b75002475cdf', + 'requestId': '600c9ae6fda1acb', + 'cpm': 1.999, + 'width': 300, + 'height': 250, + 'ttl': 300, + 'adUnitCode': 'demoslot1-div', + 'netRevenue': true, + 'currency': 'USD', + 'creativeId': 'jixie520', + 'meta': { + 'networkId': 123, + 'networkName': 'network123', + 'agencyId': 123, + 'agencyName': 'agency123', + 'advertiserId': 123, + 'advertiserName': 'advertiser123', + 'advertiserDomains': [ + 'advdom1', + 'advdom2', + 'advdom3' + ], + 'brandId': 123, + 'brandName': 'brand123', + 'primaryCatId': 1, + 'secondaryCatIds': [ + 2, + 3, + 4 + ], + 'mediaType': 'BANNER' + }, + 'ad': '
' + }, + // outstream, jx non-default renderer specified: + { + 'trackingUrlBase': 'https://tr.jixie.io/sync/ad?', + 'jxBidId': '99bc539c81b00ce-028d5dee-2c83-44e3-bed1-b75002475cdf', + 'requestId': '99bc539c81b00ce', + 'cpm': 2.99, + 'width': 640, + 'height': 360, + 'ttl': 300, + 'netRevenue': true, + 'currency': 'USD', + 'creativeId': 'jixie521', + 'adUnitCode': 'demoslot4-div', + 'osplayer': 'jixie', + 'osparams': { + 'script': JX_OTHER_OUTSTREAM_RENDERER_URL + }, + 'vastXml': mockVastXml_ + }, + // outstream, jx default renderer: + { + 'trackingUrlBase': 'https://tr.jixie.io/sync/ad?', + 'jxBidId': '61bc539c81b00ce-028d5dee-2c83-44e3-bed1-b75002475cdf', + 'requestId': '61bc539c81b00ce', + 'cpm': 1.99, + 'width': 640, + 'height': 360, + 'ttl': 300, + 'netRevenue': true, + 'currency': 'USD', + 'creativeId': 'jixie521', + 'meta': { + 'networkId': 123, + 'networkName': 'network123', + 'agencyId': 123, + 'agencyName': 'agency123', + 'advertiserId': 123, + 'advertiserName': 'advertiser123', + 'brandId': 123, + 'brandName': 'brand123', + 'primaryCatId': 1, + 'secondaryCatIds': [ + 2, + 3, + 4 + ], + 'mediaType': 'VIDEO' + }, + 'adUnitCode': 'demoslot2-div', + 'osplayer': 'jixie', + 'osparams': {}, + 'vastXml': mockVastXml_ + } + ], + 'setids': { + 'client_id': '43aacc10-f643-11ea-8a10-c5fe2d394e7e', + 'session_id': '1600057934-43aacc10-f643-11ea-8a10-c5fe2d394e7e' + }, + }; + const requestObj_ = + { + 'method': 'POST', + 'url': 'http://localhost:8080/v2/hbpost', + 'data': '{"auctionid":"028d5dee-2c83-44e3-bed1-b75002475cdf","timeout":1000,"currency":"USD","timestamp":1600057934665,"device":"desktop","domain":"mock.com","pageurl":"https://mock.com/tests/jxprebidtest_pbjs.html","bids":[{"bidId":"600c9ae6fda1acb","adUnitCode":"demoslot1-div","mediaTypes":{"banner":{"sizes":[[300,250],[300,600],[728,90]]}},"params":{"unit":"prebidsampleunit"}},{"bidId":"61bc539c81b00ce","adUnitCode":"demoslot2-div","mediaTypes":{"video":{"playerSize":[[640,360]],"context":"outstream"}},"params":{"unit":"prebidsampleunit"}},{"bidId":"99bc539c81b00ce","adUnitCode":"demoslot4-div","mediaTypes":{"video":{"playerSize":[[640,360]],"context":"outstream"}},"params":{"unit":"prebidsampleunit"}},{"bidId":"62847e4c696edcb","adUnitCode":"demoslot3-div","mediaTypes":{"video":{"playerSize":[[640,360]],"context":"instream"}},"params":{"unit":"prebidsampleunit"}},{"bidId":"6360235ab01d2cd","adUnitCode":"woo-div","mediaTypes":{"video":{"context":"outstream","playerSize":[[640,360]]}},"params":{"unit":"80b76fc951e161d7c019d21b6639e408"}},{"bidId":"64d9724c7a5e512","adUnitCode":"test-div","mediaTypes":{"video":{"context":"outstream","playerSize":[[300,250]]}},"params":{"unit":"80b76fc951e161d7c019d21b6639e408"}},{"bidId":"65bea7e80fed44b","adUnitCode":"test-div","mediaTypes":{"banner":{"sizes":[[300,250],[300,600],[728,90]]}},"params":{"unit":"7854f723e932b951b6c51fc80b23a410"}},{"bidId":"6642054c4ba1b7f","adUnitCode":"div-banner-native-1","mediaTypes":{"banner":{"sizes":[[640,360]]},"video":{"context":"outstream","sizes":[[640,361]],"playerSize":[[640,360]]},"native":{"type":"image"}},"params":{"unit":"632e7695f0910ce0fa74c19859060a04"}},{"bidId":"675ecf4b44db228","adUnitCode":"div-banner-native-2","mediaTypes":{"banner":{"sizes":[[300,250]]},"native":{"title":{"required":true},"image":{"required":true},"sponsoredBy":{"required":true}}},"params":{"unit":"1000008-b1Q2UMQfZx"}},{"bidId":"68f2dbf5dc23f94","adUnitCode":"div-Top-MediumRectangle","mediaTypes":{"banner":{"sizes":[[300,250],[300,100],[320,50]]}},"params":{"unit":"1000008-b1Q2UMQfZx"}},{"bidId":"6991cf107bb7f1a","adUnitCode":"div-Middle-MediumRectangle","mediaTypes":{"banner":{"sizes":[[300,250],[300,100],[320,50]]}},"params":{"unit":"1000008-b1Q2UMQfZx"}},{"bidId":"706be1b011eac83","adUnitCode":"div-Inside-MediumRectangle","mediaTypes":{"banner":{"sizes":[[300,600],[300,250],[300,100],[320,480]]}},"params":{"unit":"1000008-b1Q2UMQfZx"}}],"client_id_c":"ebd0dea0-f5c8-11ea-a2c7-a5b37aa7fe95","client_id_ls":"ebd0dea0-f5c8-11ea-a2c7-a5b37aa7fe95","session_id_c":"","session_id_ls":"1600005388-ebd0dea0-f5c8-11ea-a2c7-a5b37aa7fe95"}', + 'currency': 'USD' + }; + + describe('interpretResponse', function () { + it('handles nobid responses', function () { + expect(spec.interpretResponse({body: {}}, {validBidRequests: []}).length).to.equal(0) + expect(spec.interpretResponse({body: []}, {validBidRequests: []}).length).to.equal(0) + }); + + it('should get correct bid response', function () { + let setCookieSpy = sinon.spy(storage, 'setCookie'); + let setLocalStorageSpy = sinon.spy(storage, 'setDataInLocalStorage'); + const result = spec.interpretResponse({body: responseBody_}, requestObj_) + expect(setLocalStorageSpy.calledWith('_jx', '43aacc10-f643-11ea-8a10-c5fe2d394e7e')).to.equal(true); + expect(setLocalStorageSpy.calledWith('_jxs', '1600057934-43aacc10-f643-11ea-8a10-c5fe2d394e7e')).to.equal(true); + expect(setCookieSpy.calledWith('_jxs', '1600057934-43aacc10-f643-11ea-8a10-c5fe2d394e7e')).to.equal(true); + expect(setCookieSpy.calledWith('_jx', '43aacc10-f643-11ea-8a10-c5fe2d394e7e')).to.equal(true); + + // video ad with vastUrl returned by adserver + expect(result[0].requestId).to.equal('62847e4c696edcb') + expect(result[0].cpm).to.equal(2.19) + expect(result[0].width).to.equal(640) + expect(result[0].height).to.equal(360) + expect(result[0].creativeId).to.equal('jixie522') + expect(result[0].currency).to.equal('USD') + expect(result[0].netRevenue).to.equal(true) + expect(result[0].ttl).to.equal(300) + expect(result[0].vastUrl).to.include('https://ad.jixie.io/v1/video?creativeid=') + expect(result[0].trackingUrlBase).to.include('sync') + + // display ad + expect(result[1].requestId).to.equal('600c9ae6fda1acb') + expect(result[1].cpm).to.equal(1.999) + expect(result[1].width).to.equal(300) + expect(result[1].height).to.equal(250) + expect(result[1].creativeId).to.equal('jixie520') + expect(result[1].currency).to.equal('USD') + expect(result[1].netRevenue).to.equal(true) + expect(result[1].ttl).to.equal(300) + expect(result[1].ad).to.include('jxoutstream') + expect(result[1].trackingUrlBase).to.include('sync') + + // should pick up about using alternative outstream renderer + expect(result[2].requestId).to.equal('99bc539c81b00ce') + expect(result[2].cpm).to.equal(2.99) + expect(result[2].width).to.equal(640) + expect(result[2].height).to.equal(360) + expect(result[2].creativeId).to.equal('jixie521') + expect(result[2].currency).to.equal('USD') + expect(result[2].netRevenue).to.equal(true) + expect(result[2].ttl).to.equal(300) + expect(result[2].vastXml).to.include('') + expect(result[2].trackingUrlBase).to.include('sync'); + expect(result[2].renderer.id).to.equal('demoslot4-div') + expect(result[2].renderer.url).to.equal(JX_OTHER_OUTSTREAM_RENDERER_URL); + + // should know to use default outstream renderer + expect(result[3].requestId).to.equal('61bc539c81b00ce') + expect(result[3].cpm).to.equal(1.99) + expect(result[3].width).to.equal(640) + expect(result[3].height).to.equal(360) + expect(result[3].creativeId).to.equal('jixie521') + expect(result[3].currency).to.equal('USD') + expect(result[3].netRevenue).to.equal(true) + expect(result[3].ttl).to.equal(300) + expect(result[3].vastXml).to.include('') + expect(result[3].trackingUrlBase).to.include('sync'); + expect(result[3].renderer.id).to.equal('demoslot2-div') + expect(result[3].renderer.url).to.equal(JX_OUTSTREAM_RENDERER_URL) + + setLocalStorageSpy.restore(); + setCookieSpy.restore(); + });// it + });// describe + + /** + * onBidWon + */ + describe('onBidWon', function() { + let ajaxStub; + let miscDimsStub; + beforeEach(function() { + miscDimsStub = sinon.stub(jixieaux, 'getMiscDims'); + ajaxStub = sinon.stub(jixieaux, 'ajax'); + + miscDimsStub + .returns({ device: device_, pageurl: pageurl_, domain: domain_ }); + }) + + afterEach(function() { + miscDimsStub.restore(); + ajaxStub.restore(); + }) + + let TRACKINGURL_ = 'https://abc.com/sync?action=bidwon'; + + it('Should fire if the adserver trackingUrl flag says so', function() { + spec.onBidWon({ trackingUrl: TRACKINGURL_ }) + expect(jixieaux.ajax.calledWith(TRACKINGURL_)).to.equal(true); + }) + + it('Should not fire if the adserver response indicates no firing', function() { + let called = false; + ajaxStub.callsFake(function fakeFn() { + called = true; + }); + spec.onBidWon({ notrack: 1 }) + expect(called).to.equal(false); + }); + + // A reference to check again: + const QPARAMS_ = { + action: 'hbbidwon', + device: device_, + pageurl: encodeURIComponent(pageurl_), + domain: encodeURIComponent(domain_), + cid: 121, + cpid: 99, + jxbidid: '62847e4c696edcb-028d5dee-2c83-44e3-bed1-b75002475cdf', + auctionid: '028d5dee-2c83-44e3-bed1-b75002475cdf', + cpm: 1.11, + requestid: '62847e4c696edcb' + }; + + it('check it is sending the correct ajax url and qparameters', function() { + spec.onBidWon({ + trackingUrlBase: 'https://mytracker.com/sync?', + cid: 121, + cpid: 99, + jxBidId: '62847e4c696edcb-028d5dee-2c83-44e3-bed1-b75002475cdf', + auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', + cpm: 1.11, + requestId: '62847e4c696edcb' + }) + expect(jixieaux.ajax.calledWith('https://mytracker.com/sync?', null, QPARAMS_)).to.equal(true); + }); + }); // describe + + /** + * onTimeout + */ + describe('onTimeout', function() { + let ajaxStub; + let miscDimsStub; + beforeEach(function() { + ajaxStub = sinon.stub(jixieaux, 'ajax'); + miscDimsStub = sinon.stub(jixieaux, 'getMiscDims'); + miscDimsStub + .returns({ device: device_, pageurl: pageurl_, domain: domain_ }); + }) + + afterEach(function() { + miscDimsStub.restore(); + ajaxStub.restore(); + }) + + // reference to check against: + const QPARAMS_ = { + action: 'hbtimeout', + device: device_, + pageurl: encodeURIComponent(pageurl_), + domain: encodeURIComponent(domain_), + auctionid: '028d5dee-2c83-44e3-bed1-b75002475cdf', + timeout: 1000, + count: 2 + }; + + it('check it is sending the correct ajax url and qparameters', function() { + spec.onTimeout([ + {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000}, + {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000} + ]) + expect(jixieaux.ajax.calledWith(spec.EVENTS_URL, null, QPARAMS_)).to.equal(true); + }) + + it('if turned off via config then dont do onTimeout sending of event', function() { + let getConfigStub = sinon.stub(config, 'getConfig'); + getConfigStub.callsFake(function fakeFn(prop) { + if (prop == 'jixie') { + return { onTimeout: 'off' }; + } + return null; + }); + let called = false; + ajaxStub.callsFake(function fakeFn() { + called = true; + }); + spec.onTimeout([ + {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000}, + {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000} + ]) + expect(called).to.equal(false); + getConfigStub.restore(); + }) + + const otherUrl_ = 'https://other.azurewebsites.net/sync/evt?'; + it('if config specifies a different endpoint then should send there instead', function() { + let getConfigStub = sinon.stub(config, 'getConfig'); + getConfigStub.callsFake(function fakeFn(prop) { + if (prop == 'jixie') { + return { onTimeoutUrl: otherUrl_ }; + } + return null; + }); + spec.onTimeout([ + {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000}, + {auctionId: '028d5dee-2c83-44e3-bed1-b75002475cdf', timeout: 1000} + ]) + expect(jixieaux.ajax.calledWith(otherUrl_, null, QPARAMS_)).to.equal(true); + getConfigStub.restore(); + }) + });// describe +}); diff --git a/test/spec/modules/justpremiumBidAdapter_spec.js b/test/spec/modules/justpremiumBidAdapter_spec.js index c162b785aed..7cc154254ff 100644 --- a/test/spec/modules/justpremiumBidAdapter_spec.js +++ b/test/spec/modules/justpremiumBidAdapter_spec.js @@ -21,7 +21,9 @@ describe('justpremium adapter', function () { }, userId: { tdid: '1111111', - id5id: '2222222', + id5id: { + uid: '2222222' + }, digitrustid: { data: { id: '3333333' @@ -84,7 +86,7 @@ describe('justpremium adapter', function () { expect(jpxRequest.version.jp_adapter).to.equal('1.7') expect(jpxRequest.pubcid).to.equal('0000000') expect(jpxRequest.uids.tdid).to.equal('1111111') - expect(jpxRequest.uids.id5id).to.equal('2222222') + expect(jpxRequest.uids.id5id.uid).to.equal('2222222') expect(jpxRequest.uids.digitrustid.data.id).to.equal('3333333') expect(jpxRequest.us_privacy).to.equal('1YYN') }) diff --git a/test/spec/modules/jwplayerRtdProvider_spec.js b/test/spec/modules/jwplayerRtdProvider_spec.js new file mode 100644 index 00000000000..b5bacdc3694 --- /dev/null +++ b/test/spec/modules/jwplayerRtdProvider_spec.js @@ -0,0 +1,399 @@ +import { fetchTargetingForMediaId, getTargetingForBid, + fetchTargetingInformation, jwplayerSubmodule } from 'modules/jwplayerRtdProvider.js'; +import { server } from 'test/mocks/xhr.js'; + +describe('jwplayerRtdProvider', function() { + const testIdForSuccess = 'test_id_for_success'; + const testIdForFailure = 'test_id_for_failure'; + const validSegments = ['test_seg_1', 'test_seg_2']; + const responseHeader = {'Content-Type': 'application/json'}; + + describe('Fetch targeting for mediaID tests', function () { + let request; + + describe('Fetch succeeds', function () { + beforeEach(function () { + fetchTargetingForMediaId(testIdForSuccess); + request = server.requests[0]; + }); + + afterEach(function () { + server.respond(); + }); + + it('should reach out to media endpoint', function () { + expect(request.url).to.be.eq(`https://cdn.jwplayer.com/v2/media/${testIdForSuccess}`); + }); + + it('should write to cache when successful', function () { + request.respond( + 200, + responseHeader, + JSON.stringify({ + playlist: [ + { + file: 'test.mp4', + jwpseg: validSegments + } + ] + }) + ); + + const targetingInfo = getTargetingForBid({ + jwTargeting: { + mediaID: testIdForSuccess + } + }); + + const validTargeting = { + segments: validSegments, + mediaID: testIdForSuccess + }; + + expect(targetingInfo).to.deep.equal(validTargeting); + }); + }); + + describe('Fetch fails', function () { + beforeEach(function () { + fetchTargetingForMediaId(testIdForFailure); + request = server.requests[0] + }); + + it('should not write to cache when response is malformed', function() { + request.respond('{]'); + const targetingInfo = getTargetingForBid({ + jwTargeting: { + mediaID: testIdForFailure + } + }); + expect(targetingInfo).to.be.null; + }); + + it('should not write to cache when playlist is absent', function() { + request.respond({}); + const targetingInfo = getTargetingForBid({ + jwTargeting: { + mediaID: testIdForFailure + } + }); + expect(targetingInfo).to.be.null; + }); + + it('should not write to cache when segments are absent', function() { + request.respond( + 200, + responseHeader, + JSON.stringify({ + playlist: [ + { + file: 'test.mp4' + } + ] + }) + ); + const targetingInfo = getTargetingForBid({ + jwTargeting: { + mediaID: testIdForFailure + } + }); + expect(targetingInfo).to.be.null; + }); + + it('should not write to cache when request errors', function() { + request.error(); + const targetingInfo = getTargetingForBid({ + jwTargeting: { + mediaID: testIdForFailure + } + }); + expect(targetingInfo).to.be.null; + }); + }); + }); + + describe('Get targeting for bid', function() { + const mediaIdWithSegment = 'media_ID_1'; + const mediaIdNoSegment = 'media_ID_2'; + const mediaIdForCurrentItem = 'media_ID_current'; + const mediaIdNotCached = 'media_test_ID'; + + const validPlayerID = 'player_test_ID_valid'; + const invalidPlayerID = 'player_test_ID_invalid'; + + it('returns null when targeting block is missing', function () { + const targeting = getTargetingForBid({}); + expect(targeting).to.be.null; + }); + + it('returns null when jwplayer.js is absent from page', function () { + const targeting = getTargetingForBid({ + jwTargeting: { + playerID: invalidPlayerID, + mediaID: mediaIdNotCached + } + }); + expect(targeting).to.be.null; + }); + + describe('When jwplayer.js is on page', function () { + const playlistItemWithSegmentMock = { + mediaid: mediaIdWithSegment, + jwpseg: validSegments + }; + + const targetingForMediaWithSegment = { + segments: validSegments, + mediaID: mediaIdWithSegment + }; + + const playlistItemNoSegmentMock = { + mediaid: mediaIdNoSegment + }; + + const currentItemSegments = ['test_seg_3', 'test_seg_4']; + const currentPlaylistItemMock = { + mediaid: mediaIdForCurrentItem, + jwpseg: currentItemSegments + }; + const targetingForCurrentItem = { + segments: currentItemSegments, + mediaID: mediaIdForCurrentItem + }; + + const playerInstanceMock = { + getPlaylist: function () { + return [playlistItemWithSegmentMock, playlistItemNoSegmentMock]; + }, + + getPlaylistItem: function () { + return currentPlaylistItemMock; + } + }; + + const jwplayerMock = function(playerID) { + if (playerID === validPlayerID) { + return playerInstanceMock; + } else { + return {}; + } + }; + + beforeEach(function () { + window.jwplayer = jwplayerMock; + }); + + it('returns null when player ID does not match player on page', function () { + const targeting = getTargetingForBid({ + jwTargeting: { + playerID: invalidPlayerID, + mediaID: mediaIdNotCached + } + }); + expect(targeting).to.be.null; + }); + + it('returns segments when media ID matches a playlist item with segments', function () { + const targeting = getTargetingForBid({ + jwTargeting: { + playerID: validPlayerID, + mediaID: mediaIdWithSegment + } + }); + expect(targeting).to.deep.equal(targetingForMediaWithSegment); + }); + + it('caches segments media ID matches a playist item with segments', function () { + getTargetingForBid({ + jwTargeting: { + playerID: validPlayerID, + mediaID: mediaIdWithSegment + } + }); + + window.jwplayer = null; + const targeting2 = getTargetingForBid({ + jwTargeting: { + playerID: invalidPlayerID, + mediaID: mediaIdWithSegment + } + }); + expect(targeting2).to.deep.equal(targetingForMediaWithSegment); + }); + + it('returns segments of current item when media ID is missing', function () { + const targeting = getTargetingForBid({ + jwTargeting: { + playerID: validPlayerID + } + }); + expect(targeting).to.deep.equal(targetingForCurrentItem); + }); + + it('caches segments from the current item', function () { + getTargetingForBid({ + jwTargeting: { + playerID: validPlayerID + } + }); + + window.jwplayer = null; + const targeting2 = getTargetingForBid({ + jwTargeting: { + playerID: invalidPlayerID, + mediaID: mediaIdForCurrentItem + } + }); + expect(targeting2).to.deep.equal(targetingForCurrentItem); + }); + + it('returns undefined segments when segments are absent', function () { + const targeting = getTargetingForBid({ + jwTargeting: { + playerID: validPlayerID, + mediaID: mediaIdNoSegment + } + }); + expect(targeting).to.deep.equal({ + mediaID: mediaIdNoSegment, + segments: undefined + }); + }); + }); + }); + + describe('jwplayerSubmodule', function () { + it('successfully instantiates', function () { + expect(jwplayerSubmodule.init()).to.equal(true); + }); + + describe('getData', function () { + const validMediaIDs = ['media_ID_1', 'media_ID_2', 'media_ID_3']; + let bidRequestSpy; + let fakeServer; + let clock; + + beforeEach(function () { + bidRequestSpy = sinon.spy(); + + fakeServer = sinon.createFakeServer(); + fakeServer.respondImmediately = false; + fakeServer.autoRespond = false; + + clock = sinon.useFakeTimers(); + }); + + afterEach(function () { + clock.restore(); + fakeServer.respond(); + }); + + it('executes callback immediately when no requests are pending', function () { + fetchTargetingInformation({ + mediaIDs: [] + }); + jwplayerSubmodule.getData([], bidRequestSpy); + expect(bidRequestSpy.calledOnce).to.be.true; + }); + + it('executes callback after requests complete', function() { + fetchTargetingInformation({ + mediaIDs: validMediaIDs + }); + jwplayerSubmodule.getData([], bidRequestSpy); + expect(bidRequestSpy.notCalled).to.be.true; + + const req1 = fakeServer.requests[0]; + const req2 = fakeServer.requests[1]; + const req3 = fakeServer.requests[2]; + + req1.respond(); + expect(bidRequestSpy.notCalled).to.be.true; + + req2.respond(); + expect(bidRequestSpy.notCalled).to.be.true; + + req3.respond(); + expect(bidRequestSpy.calledOnce).to.be.true; + }); + + it('executes callback after timeout', function () { + fetchTargetingInformation({ + mediaIDs: validMediaIDs + }); + jwplayerSubmodule.getData([], bidRequestSpy); + expect(bidRequestSpy.notCalled).to.be.true; + clock.tick(150); + expect(bidRequestSpy.calledOnce).to.be.true; + }); + + it('executes callback only once if requests succeed after timeout', function () { + fetchTargetingInformation({ + mediaIDs: validMediaIDs + }); + jwplayerSubmodule.getData([], bidRequestSpy); + expect(bidRequestSpy.notCalled).to.be.true; + clock.tick(150); + expect(bidRequestSpy.calledOnce).to.be.true; + + fakeServer.respond(); + expect(bidRequestSpy.calledOnce).to.be.true; + }); + + it('returns data in proper structure', function () { + const adUnitCode = 'test_ad_unit'; + const adUnitWithMediaId = { + code: adUnitCode, + jwTargeting: { + mediaID: testIdForSuccess + } + }; + const adUnitEmpty = { + code: 'test_ad_unit_empty' + }; + const expectedData = {}; + const expectedContentId = 'jw_' + testIdForSuccess; + expectedData[adUnitCode] = { + jwTargeting: { + segments: validSegments, + content: { + id: expectedContentId + } + } + }; + jwplayerSubmodule.getData([adUnitWithMediaId, adUnitEmpty], bidRequestSpy); + expect(bidRequestSpy.calledOnceWithExactly(expectedData)).to.be.true; + }); + + it('returns an empty object when media id is invalid', function () { + const adUnitCode = 'test_ad_unit'; + const adUnitWithMediaId = { + code: adUnitCode, + jwTargeting: { + mediaID: testIdForFailure + } + }; + const adUnitEmpty = { + code: 'test_ad_unit_empty' + }; + + jwplayerSubmodule.getData([adUnitWithMediaId, adUnitEmpty], bidRequestSpy); + expect(bidRequestSpy.calledOnceWithExactly({})).to.be.true; + }); + + it('returns an empty object when jwTargeting block is absent', function () { + const adUnitCode = 'test_ad_unit'; + const adUnitWithMediaId = { + code: adUnitCode, + mediaID: testIdForSuccess + }; + const adUnitEmpty = { + code: 'test_ad_unit_empty' + }; + + jwplayerSubmodule.getData([adUnitWithMediaId, adUnitEmpty], bidRequestSpy); + expect(bidRequestSpy.calledOnceWithExactly({})).to.be.true; + }); + }); + }); +}); diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index be73e140839..9dbcca8e331 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -505,7 +505,8 @@ describe('kargo adapter tests', function () { netRevenue: true, currency: 'USD', meta: { - clickUrl: 'https://foobar.com' + clickUrl: 'https://foobar.com', + advertiserDomains: ['https://foobar.com'] } }, { requestId: '3', diff --git a/test/spec/modules/konduitWrapper_spec.js b/test/spec/modules/konduitWrapper_spec.js index d70cb7a6c60..c88287c7066 100644 --- a/test/spec/modules/konduitWrapper_spec.js +++ b/test/spec/modules/konduitWrapper_spec.js @@ -10,7 +10,11 @@ describe('The Konduit vast wrapper module', function () { config.setConfig({ konduit: { konduitId } }); }); - describe('processBids function', () => { + describe('processBids function (send one bid)', () => { + beforeEach(function() { + config.setConfig({ enableSendAllBids: false }); + }); + it(`should make a correct processBids request and add kCpm and konduitCacheKey to the passed bids and to the adserverTargeting object`, function () { const bid = createBid(10, 'video1', 15, '10.00_15s', '123', '395'); @@ -35,7 +39,7 @@ describe('The Konduit vast wrapper module', function () { expect(bid.adserverTargeting).to.be.an('object'); expect(bid.adserverTargeting.k_cpm).to.equal(bid.pbCg || bid.pbAg); - expect(bid.adserverTargeting.konduit_cache_key).to.equal('test_cache_key'); + expect(bid.adserverTargeting.k_cache_key).to.equal('test_cache_key'); expect(bid.adserverTargeting.konduit_id).to.equal(konduitId); }); @@ -60,7 +64,7 @@ describe('The Konduit vast wrapper module', function () { expect(bid.kCpm).to.equal(bid.cpm); expect(bid.adserverTargeting.k_cpm).to.equal(bid.pbCg || bid.pbAg); - expect(bid.adserverTargeting.konduit_cache_key).to.be.undefined; + expect(bid.adserverTargeting.k_cache_key).to.be.undefined; expect(bid.adserverTargeting.konduit_id).to.be.undefined; expect(callback.firstCall.args[0]).to.be.an('error'); @@ -111,12 +115,122 @@ describe('The Konduit vast wrapper module', function () { const callback = sinon.spy(); processBids({ bid: null, + bids: [], + callback + }); + + expect(callback.calledOnce).to.be.true; + expect(callback.firstCall.args[0]).to.be.an('error'); + expect(callback.firstCall.args[0].message).to.equal(errorMessages.NO_BIDS); + }); + }); + describe('processBids function (send all bids)', () => { + beforeEach(function() { + config.setConfig({ enableSendAllBids: true }); + }); + + it(`should make a correct processBids request and add kCpm and konduitCacheKey + to the passed bids and to the adserverTargeting object`, function () { + const bid = createBid(10, 'video1', 15, '10.00_15s', '123', '395'); + + server.respondWith(JSON.stringify({ + kCpmData: { [`${bid.bidderCode}:${bid.creativeId}`]: bid.cpm }, + cacheData: { [`${bid.bidderCode}:${bid.creativeId}`]: 'test_cache_key' }, + })); + + processBids({ adUnitCode: 'video1', bids: [bid] }); + server.respond(); + + expect(server.requests.length).to.equal(1); + + const requestBody = JSON.parse(server.requests[0].requestBody); + + expect(requestBody.clientId).to.equal(konduitId); + + expect(bid.konduitCacheKey).to.equal('test_cache_key'); + expect(bid.kCpm).to.equal(bid.cpm); + + expect(bid.adserverTargeting).to.be.an('object'); + + expect(bid.adserverTargeting.k_cpm).to.equal(bid.pbCg || bid.pbAg); + expect(bid.adserverTargeting[`k_cpm_${bid.bidderCode}`]).to.equal(bid.pbCg || bid.pbAg); + expect(bid.adserverTargeting.k_cache_key).to.equal('test_cache_key'); + expect(bid.adserverTargeting[`k_cache_key_${bid.bidderCode}`]).to.equal('test_cache_key'); + expect(bid.adserverTargeting.konduit_id).to.equal(konduitId); + }); + + it(`should call callback with error object in arguments if cacheData is empty in the response`, function () { + const bid = createBid(10, 'video1', 15, '10.00_15s', '123', '395'); + + server.respondWith(JSON.stringify({ + kCpmData: { [`${bid.bidderCode}:${bid.creativeId}`]: bid.cpm }, + cacheData: {}, + })); + const callback = sinon.spy(); + processBids({ adUnitCode: 'video1', bids: [bid], callback }); + server.respond(); + + expect(server.requests.length).to.equal(1); + + const requestBody = JSON.parse(server.requests[0].requestBody); + + expect(requestBody.clientId).to.equal(konduitId); + + expect(bid.konduitCacheKey).to.be.undefined; + expect(bid.kCpm).to.equal(bid.cpm); + + expect(bid.adserverTargeting.k_cpm).to.equal(bid.pbCg || bid.pbAg); + expect(bid.adserverTargeting[`k_cpm_${bid.bidderCode}`]).to.equal(bid.pbCg || bid.pbAg); + expect(bid.adserverTargeting.k_cache_key).to.be.undefined; + expect(bid.adserverTargeting[`k_cache_key_${bid.bidderCode}`]).to.be.undefined; + expect(bid.adserverTargeting.konduit_id).to.be.undefined; + + expect(callback.firstCall.args[0]).to.be.an('error'); + }); + + it('should call callback if processBids request is sent successfully', function () { + const bid = createBid(10, 'video1', 15, '10.00_15s', '123', '395'); + server.respondWith(JSON.stringify({ key: 'test' })); + const callback = sinon.spy(); + processBids({ adUnitCode: 'video1', bid: [bid], callback }); + server.respond(); + + expect(callback.calledOnce).to.be.true; + }); + + it('should call callback with error object in arguments if processBids request is failed', function () { + const bid = createBid(10, 'video1', 15, '10.00_15s', '123', '395'); + const callback = sinon.spy(); + processBids({ adUnitCode: 'video1', bid: [bid], callback }); + server.respond(); + + expect(callback.calledOnce).to.be.true; + expect(callback.firstCall.args[0]).to.be.an('error'); + }); + + it('should call callback with error object in arguments if no konduitId in configs', function () { + config.setConfig({ konduit: { konduitId: null } }); + + const bid = createBid(10, 'video1', 15, '10.00_15s', '123', '395'); + const callback = sinon.spy(); + processBids({ adUnitCode: 'video1', bid: [bid], callback }); + + expect(callback.calledOnce).to.be.true; + expect(callback.firstCall.args[0]).to.be.an('error'); + expect(callback.firstCall.args[0].message).to.equal(errorMessages.NO_KONDUIT_ID); + }); + + it('should call callback with error object in arguments if no bids found', function () { + const callback = sinon.spy(); + processBids({ + bid: null, + bids: [], callback }); expect(callback.calledOnce).to.be.true; expect(callback.firstCall.args[0]).to.be.an('error'); - expect(callback.firstCall.args[0].message).to.equal(errorMessages.NO_BID); + expect(callback.firstCall.args[0].message).to.equal(errorMessages.NO_BIDS); }); }); }); @@ -152,7 +266,7 @@ function createBid(cpm, adUnitCode, durationBucket, priceIndustryDuration, uuid, 'bidder': 'appnexus', 'timeToRespond': 61, 'pbLg': '5.00', - 'pbMg': '5.00', + 'pbMg': `${cpm}.00`, 'pbHg': '5.00', 'pbAg': `${cpm}.00`, 'pbDg': '5.00', @@ -170,7 +284,7 @@ function createBid(cpm, adUnitCode, durationBucket, priceIndustryDuration, uuid, }, 'customCacheKey': `${priceIndustryDuration}_${uuid}`, 'meta': { - 'iabSubCatId': 'iab-1', + 'primaryCatId': 'iab-1', 'adServerCatId': label }, 'videoCacheKey': '4cf395af-8fee-4960-af0e-88d44e399f14' diff --git a/test/spec/modules/liveIntentIdSystem_spec.js b/test/spec/modules/liveIntentIdSystem_spec.js index 85e0d30b348..b19d38d5859 100644 --- a/test/spec/modules/liveIntentIdSystem_spec.js +++ b/test/spec/modules/liveIntentIdSystem_spec.js @@ -33,21 +33,6 @@ describe('LiveIntentId', function () { resetLiveIntentIdSubmodule(); }); - it('should log an error if no configParams were passed when getId', function () { - liveIntentIdSubmodule.getId(); - expect(logErrorStub.calledOnce).to.be.true; - }); - - it('should log an error if publisherId configParam was not passed when getId', function () { - liveIntentIdSubmodule.getId({}); - expect(logErrorStub.calledOnce).to.be.true; - }); - - it('should log an error if publisherId configParam was not passed when decode', function () { - liveIntentIdSubmodule.decode({}, {}); - expect(logErrorStub.calledOnce).to.be.true; - }); - it('should initialize LiveConnect with a us privacy string when getId, and include it in all requests', function () { consentDataStub.returns('1YNY'); let callBackSpy = sinon.spy(); diff --git a/test/spec/modules/livewrappedAnalyticsAdapter_spec.js b/test/spec/modules/livewrappedAnalyticsAdapter_spec.js index 4e05d1a31ff..c723f589fa0 100644 --- a/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +++ b/test/spec/modules/livewrappedAnalyticsAdapter_spec.js @@ -120,6 +120,7 @@ const MOCK = { const ANALYTICS_MESSAGE = { publisherId: 'CC411485-42BC-4F92-8389-42C503EE38D7', + gdpr: [{}], bidAdUnits: [ { adUnit: 'panorama_d_1', @@ -134,17 +135,20 @@ const ANALYTICS_MESSAGE = { { adUnit: 'panorama_d_1', bidder: 'livewrapped', - timeStamp: 1519149562216 + timeStamp: 1519149562216, + gdpr: 0 }, { adUnit: 'box_d_1', bidder: 'livewrapped', - timeStamp: 1519149562216 + timeStamp: 1519149562216, + gdpr: 0 }, { adUnit: 'box_d_2', bidder: 'livewrapped', - timeStamp: 1519149562216 + timeStamp: 1519149562216, + gdpr: 0 } ], responses: [ @@ -321,6 +325,48 @@ describe('Livewrapped analytics adapter', function () { expect(message.rcv).to.equal(true); }); + + it('should forward GDPR data', function () { + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, { + 'bidder': 'livewrapped', + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa', + 'bidderRequestId': '1be65d7958826a', + 'bids': [ + { + 'bidder': 'livewrapped', + 'adUnitCode': 'panorama_d_1', + 'bidId': '2ecff0db240757', + }, + { + 'bidder': 'livewrapped', + 'adUnitCode': 'box_d_1', + 'bidId': '3ecff0db240757', + } + ], + 'start': 1519149562216, + 'gdprConsent': { + 'gdprApplies': true, + 'consentString': 'consentstring' + } + }, + ); + events.emit(BID_TIMEOUT, MOCK.BID_TIMEOUT); + events.emit(AUCTION_END, MOCK.AUCTION_END); + + clock.tick(BID_WON_TIMEOUT + 1000); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + + expect(message.gdpr.length).to.equal(1); + expect(message.gdpr[0].gdprApplies).to.equal(true); + expect(message.gdpr[0].gdprConsent).to.equal('consentstring'); + expect(message.requests.length).to.equal(2); + expect(message.requests[0].gdpr).to.equal(0); + expect(message.requests[1].gdpr).to.equal(0); + }); }); describe('when given other endpoint', function () { diff --git a/test/spec/modules/livewrappedBidAdapter_spec.js b/test/spec/modules/livewrappedBidAdapter_spec.js index 800ca744d9c..2d5ba3f48df 100644 --- a/test/spec/modules/livewrappedBidAdapter_spec.js +++ b/test/spec/modules/livewrappedBidAdapter_spec.js @@ -2,7 +2,7 @@ import {expect} from 'chai'; import {spec, storage} from 'modules/livewrappedBidAdapter.js'; import {config} from 'src/config.js'; import * as utils from 'src/utils.js'; -import { BANNER, NATIVE } from 'src/mediaTypes.js'; +import { BANNER, NATIVE, VIDEO } from 'src/mediaTypes.js'; describe('Livewrapped adapter tests', function () { let sandbox, @@ -102,7 +102,7 @@ describe('Livewrapped adapter tests', function () { userId: 'user id', url: 'https://www.domain.com', seats: {'dsp': ['seat 1']}, - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -139,7 +139,7 @@ describe('Livewrapped adapter tests', function () { userId: 'user id', url: 'https://www.domain.com', seats: {'dsp': ['seat 1']}, - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -177,7 +177,7 @@ describe('Livewrapped adapter tests', function () { userId: 'user id', url: 'https://www.domain.com', seats: {'dsp': ['seat 1']}, - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -208,7 +208,7 @@ describe('Livewrapped adapter tests', function () { auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', publisherId: '26947112-2289-405D-88C1-A7340C57E63E', url: 'https://www.domain.com', - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -238,7 +238,7 @@ describe('Livewrapped adapter tests', function () { let expectedQuery = { auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', url: 'https://www.domain.com', - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -270,7 +270,7 @@ describe('Livewrapped adapter tests', function () { auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', publisherId: '26947112-2289-405D-88C1-A7340C57E63E', url: 'https://www.domain.com', - version: '1.3', + version: '1.4', width: 100, height: 100, deviceId: 'deviceid', @@ -303,7 +303,7 @@ describe('Livewrapped adapter tests', function () { auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', publisherId: '26947112-2289-405D-88C1-A7340C57E63E', url: 'https://www.domain.com', - version: '1.3', + version: '1.4', width: 100, height: 100, tid: 'tracking id', @@ -335,7 +335,7 @@ describe('Livewrapped adapter tests', function () { auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', publisherId: '26947112-2289-405D-88C1-A7340C57E63E', url: 'https://www.domain.com', - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -366,7 +366,7 @@ describe('Livewrapped adapter tests', function () { auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', publisherId: '26947112-2289-405D-88C1-A7340C57E63E', url: 'https://www.domain.com', - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -397,7 +397,7 @@ describe('Livewrapped adapter tests', function () { auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', publisherId: '26947112-2289-405D-88C1-A7340C57E63E', url: 'https://www.domain.com', - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -428,7 +428,7 @@ describe('Livewrapped adapter tests', function () { auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', publisherId: '26947112-2289-405D-88C1-A7340C57E63E', url: 'https://www.domain.com', - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -445,6 +445,37 @@ describe('Livewrapped adapter tests', function () { expect(data).to.deep.equal(expectedQuery); }); + it('should make a well-formed single request object with video only parameters', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + let testbidRequest = clone(bidderRequest); + delete testbidRequest.bids[0].params.userId; + delete testbidRequest.bids[0].params.seats; + delete testbidRequest.bids[0].params.adUnitId; + testbidRequest.bids[0].mediaTypes = {'video': {'videodata': 'content parsed serverside only'}}; + let result = spec.buildRequests(testbidRequest.bids, testbidRequest); + let data = JSON.parse(result.data); + + let expectedQuery = { + auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', + publisherId: '26947112-2289-405D-88C1-A7340C57E63E', + url: 'https://www.domain.com', + version: '1.4', + width: 100, + height: 100, + cookieSupport: true, + adRequests: [{ + callerAdUnitId: 'panorama_d_1', + bidId: '2ffb201a808da7', + transactionId: '3D1C8CF7-D288-4D7F-8ADD-97C553056C3D', + formats: [{width: 980, height: 240}, {width: 980, height: 120}], + video: {'videodata': 'content parsed serverside only'} + }] + }; + + expect(data).to.deep.equal(expectedQuery); + }); + it('should use app objects', function() { sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); @@ -474,7 +505,7 @@ describe('Livewrapped adapter tests', function () { userId: 'user id', url: 'https://appdomain.com', seats: {'dsp': ['seat 1']}, - version: '1.3', + version: '1.4', width: 300, height: 200, ifa: 'ifa', @@ -507,7 +538,7 @@ describe('Livewrapped adapter tests', function () { auctionId: 'F7557995-65F5-4682-8782-7D5D34D82A8C', publisherId: '26947112-2289-405D-88C1-A7340C57E63E', url: 'https://www.domain.com', - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -541,7 +572,7 @@ describe('Livewrapped adapter tests', function () { userId: 'user id', url: 'https://www.domain.com', seats: {'dsp': ['seat 1']}, - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -577,7 +608,7 @@ describe('Livewrapped adapter tests', function () { userId: 'user id', url: 'https://www.domain.com', seats: {'dsp': ['seat 1']}, - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -608,7 +639,7 @@ describe('Livewrapped adapter tests', function () { userId: 'user id', url: 'https://www.domain.com', seats: {'dsp': ['seat 1']}, - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: false, @@ -638,7 +669,7 @@ describe('Livewrapped adapter tests', function () { userId: 'user id', url: 'https://www.domain.com', seats: {'dsp': ['seat 1']}, - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: false, @@ -701,7 +732,7 @@ describe('Livewrapped adapter tests', function () { userId: 'pubcid 123', url: 'https://www.domain.com', seats: {'dsp': ['seat 1']}, - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -733,7 +764,7 @@ describe('Livewrapped adapter tests', function () { userId: 'user id', url: 'https://www.domain.com', seats: {'dsp': ['seat 1']}, - version: '1.3', + version: '1.4', width: 100, height: 100, cookieSupport: true, @@ -756,7 +787,7 @@ describe('Livewrapped adapter tests', function () { let testbidRequest = clone(bidderRequest); delete testbidRequest.bids[0].params.userId; testbidRequest.bids[0].userId = {}; - testbidRequest.bids[0].userId.id5id = 'id5-user-id'; + testbidRequest.bids[0].userId.id5id = { uid: 'id5-user-id' }; let result = spec.buildRequests(testbidRequest.bids, testbidRequest); let data = JSON.parse(result.data); @@ -788,6 +819,31 @@ describe('Livewrapped adapter tests', function () { }]); }); + it('should send schain object if available', function() { + sandbox.stub(utils, 'isSafariBrowser').callsFake(() => false); + sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); + let testbidRequest = clone(bidderRequest); + let schain = { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'directseller.com', + 'sid': '00001', + 'rid': 'BidRequest1', + 'hp': 1 + } + ] + }; + + testbidRequest.bids[0].schain = schain; + + let result = spec.buildRequests(testbidRequest.bids, testbidRequest); + let data = JSON.parse(result.data); + + expect(data.schain).to.deep.equal(schain); + }); + describe('interpretResponse', function () { it('should handle single success response', function() { let lwResponse = { @@ -870,6 +926,48 @@ describe('Livewrapped adapter tests', function () { expect(bids).to.deep.equal(expectedResponse); }) + it('should handle single video success response', function() { + let lwResponse = { + ads: [ + { + id: '28e5ddf4-3c01-11e8-86a7-0a44794250d4', + callerId: 'site_outsider_0', + tag: 'VAST XML', + video: {}, + width: 300, + height: 250, + cpmBid: 2.565917, + bidId: '32e50fad901ae89', + auctionId: '13e674db-d4d8-4e19-9d28-ff38177db8bf', + creativeId: '52cbd598-2715-4c43-a06f-229fc170f945:427077', + ttl: 120, + meta: undefined + } + ], + currency: 'USD' + }; + + let expectedResponse = [{ + requestId: '32e50fad901ae89', + bidderCode: 'livewrapped', + cpm: 2.565917, + width: 300, + height: 250, + ad: 'VAST XML', + ttl: 120, + creativeId: '52cbd598-2715-4c43-a06f-229fc170f945:427077', + netRevenue: true, + currency: 'USD', + meta: undefined, + vastXml: 'VAST XML', + mediaType: VIDEO + }]; + + let bids = spec.interpretResponse({body: lwResponse}); + + expect(bids).to.deep.equal(expectedResponse); + }) + it('should handle multiple success response', function() { let lwResponse = { ads: [ diff --git a/test/spec/modules/logicadBidAdapter_spec.js b/test/spec/modules/logicadBidAdapter_spec.js index eddcaecac7b..c4c06630a2b 100644 --- a/test/spec/modules/logicadBidAdapter_spec.js +++ b/test/spec/modules/logicadBidAdapter_spec.js @@ -21,6 +21,32 @@ describe('LogicadAdapter', function () { } } }]; + const nativeBidRequests = [{ + bidder: 'logicad', + bidId: '51ef8751f9aead', + params: { + tid: 'bgjD1', + page: 'https://www.logicad.com/' + }, + adUnitCode: 'div-gpt-ad-1460505748561-1', + transactionId: 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + sizes: [[1, 1]], + bidderRequestId: '418b37f85e772c', + auctionId: '18fd8b8b0bd757', + mediaTypes: { + native: { + title: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + } + } + } + }]; const bidderRequest = { refererInfo: { referer: 'fakeReferer', @@ -52,6 +78,40 @@ describe('LogicadAdapter', function () { } } }; + const nativeServerResponse = { + body: { + seatbid: + [{ + bid: { + requestId: '51ef8751f9aead', + cpm: 101.0234, + width: 1, + height: 1, + creativeId: '2019', + currency: 'JPY', + netRevenue: true, + ttl: 60, + native: { + clickUrl: 'https://www.logicad.com', + image: { + url: 'https://cd.ladsp.com/img.png', + width: '1200', + height: '628' + }, + impressionTrackers: [ + 'https://example.com' + ], + sponsoredBy: 'Logicad', + title: 'Native Creative', + } + } + }], + userSync: { + type: 'image', + url: 'https://cr-p31.ladsp.jp/cookiesender/31' + } + } + }; describe('isBidRequestValid', function () { it('should return true if the tid parameter is present', function () { @@ -69,6 +129,10 @@ describe('LogicadAdapter', function () { delete bidRequest[0].params; expect(spec.isBidRequestValid(bidRequest)).to.be.false; }); + + it('should return true if the tid parameter is present for native request', function () { + expect(spec.isBidRequestValid(nativeBidRequests[0])).to.be.true; + }); }); describe('buildRequests', function () { @@ -101,6 +165,27 @@ describe('LogicadAdapter', function () { expect(interpretedResponse[0].netRevenue).to.equal(serverResponse.body.seatbid[0].bid.netRevenue); expect(interpretedResponse[0].ad).to.equal(serverResponse.body.seatbid[0].bid.ad); expect(interpretedResponse[0].ttl).to.equal(serverResponse.body.seatbid[0].bid.ttl); + + // native + const nativeRequest = spec.buildRequests(nativeBidRequests, bidderRequest)[0]; + const interpretedResponseForNative = spec.interpretResponse(nativeServerResponse, nativeRequest); + + expect(interpretedResponseForNative).to.have.lengthOf(1); + + expect(interpretedResponseForNative[0].requestId).to.equal(nativeServerResponse.body.seatbid[0].bid.requestId); + expect(interpretedResponseForNative[0].cpm).to.equal(nativeServerResponse.body.seatbid[0].bid.cpm); + expect(interpretedResponseForNative[0].width).to.equal(nativeServerResponse.body.seatbid[0].bid.width); + expect(interpretedResponseForNative[0].height).to.equal(nativeServerResponse.body.seatbid[0].bid.height); + expect(interpretedResponseForNative[0].creativeId).to.equal(nativeServerResponse.body.seatbid[0].bid.creativeId); + expect(interpretedResponseForNative[0].currency).to.equal(nativeServerResponse.body.seatbid[0].bid.currency); + expect(interpretedResponseForNative[0].netRevenue).to.equal(nativeServerResponse.body.seatbid[0].bid.netRevenue); + expect(interpretedResponseForNative[0].ttl).to.equal(nativeServerResponse.body.seatbid[0].bid.ttl); + expect(interpretedResponseForNative[0].native.clickUrl).to.equal(nativeServerResponse.body.seatbid[0].bid.native.clickUrl); + expect(interpretedResponseForNative[0].native.image.url).to.equal(nativeServerResponse.body.seatbid[0].bid.native.image.url); + expect(interpretedResponseForNative[0].native.image.width).to.equal(nativeServerResponse.body.seatbid[0].bid.native.image.width); + expect(interpretedResponseForNative[0].native.impressionTrackers).to.equal(nativeServerResponse.body.seatbid[0].bid.native.impressionTrackers); + expect(interpretedResponseForNative[0].native.sponsoredBy).to.equal(nativeServerResponse.body.seatbid[0].bid.native.sponsoredBy); + expect(interpretedResponseForNative[0].native.title).to.equal(nativeServerResponse.body.seatbid[0].bid.native.title); }); }); diff --git a/test/spec/modules/lotamePanoramaIdSystem_spec.js b/test/spec/modules/lotamePanoramaIdSystem_spec.js new file mode 100644 index 00000000000..c6d3383374a --- /dev/null +++ b/test/spec/modules/lotamePanoramaIdSystem_spec.js @@ -0,0 +1,449 @@ +import { + lotamePanoramaIdSubmodule, + storage, +} from 'modules/lotamePanoramaIdSystem.js'; +import * as utils from 'src/utils.js'; +import { server } from 'test/mocks/xhr.js'; + +const responseHeader = { 'Content-Type': 'application/json' }; + +describe('LotameId', function() { + let logErrorStub; + let getCookieStub; + let setCookieStub; + let getLocalStorageStub; + let setLocalStorageStub; + let removeFromLocalStorageStub; + let timeStampStub; + + const nowTimestamp = new Date().getTime(); + + beforeEach(function () { + logErrorStub = sinon.stub(utils, 'logError'); + getCookieStub = sinon.stub(storage, 'getCookie'); + setCookieStub = sinon.stub(storage, 'setCookie'); + getLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); + setLocalStorageStub = sinon.stub(storage, 'setDataInLocalStorage'); + removeFromLocalStorageStub = sinon.stub( + storage, + 'removeDataFromLocalStorage' + ); + timeStampStub = sinon.stub(utils, 'timestamp').returns(nowTimestamp); + }); + + afterEach(function () { + logErrorStub.restore(); + getCookieStub.restore(); + setCookieStub.restore(); + getLocalStorageStub.restore(); + setLocalStorageStub.restore(); + removeFromLocalStorageStub.restore(); + timeStampStub.restore(); + }); + + describe('caching initial data received from the remote server', function () { + let request; + let callBackSpy = sinon.spy(); + + beforeEach(function() { + let submoduleCallback = lotamePanoramaIdSubmodule.getId({}).callback; + submoduleCallback(callBackSpy); + + request = server.requests[0]; + + request.respond( + 200, + responseHeader, + JSON.stringify({ + profile_id: '4ec137245858469eb94a4e248f238694', + expiry_ts: 10, + core_id: + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87a', + }) + ); + }); + + it('should call the remote server when getId is called', function () { + expect(request.url).to.be.eq('https://id.crwdcntrl.net/id'); + + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should save the first party id', function () { + sinon.assert.calledWith( + setLocalStorageStub, + '_cc_id', + '4ec137245858469eb94a4e248f238694' + ); + sinon.assert.calledWith( + setCookieStub, + '_cc_id', + '4ec137245858469eb94a4e248f238694' + ); + }); + + it('should save the expiry', function () { + sinon.assert.calledWith( + setLocalStorageStub, + 'panoramaId_expiry', 10); + + sinon.assert.calledWith( + setCookieStub, + 'panoramaId_expiry', 10 + ); + }); + + it('should save the id', function () { + sinon.assert.calledWith( + setLocalStorageStub, + 'panoramaId', + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87a' + ); + + sinon.assert.calledWith( + setCookieStub, + 'panoramaId', + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87a' + ); + }); + }); + + describe('No stored values', function() { + describe('and receives the profile id but no panorama id', function() { + let request; + let callBackSpy = sinon.spy(); + + beforeEach(function() { + let submoduleCallback = lotamePanoramaIdSubmodule.getId({}).callback; + submoduleCallback(callBackSpy); + request = server.requests[0]; + + request.respond( + 200, + responseHeader, + JSON.stringify({ + profile_id: '4ec137245858469eb94a4e248f238694', + expiry_ts: 3800000, + }) + ); + }); + + it('should save the profile id', function() { + sinon.assert.calledWith( + setLocalStorageStub, + '_cc_id', + '4ec137245858469eb94a4e248f238694' + ); + sinon.assert.calledWith( + setCookieStub, + '_cc_id', + '4ec137245858469eb94a4e248f238694' + ); + }); + + it('should save the panorama id expiry', function () { + sinon.assert.calledWith( + setLocalStorageStub, + 'panoramaId_expiry', + 3800000 + ); + + sinon.assert.calledWith(setCookieStub, 'panoramaId_expiry', 3800000); + }); + + it('should NOT save the panorama id', function () { + sinon.assert.neverCalledWith( + setLocalStorageStub, + 'panoramaId', + sinon.match.any + ); + + sinon.assert.calledWith( + removeFromLocalStorageStub, + 'panoramaId' + ); + + sinon.assert.calledWith( + setCookieStub, + 'panoramaId', + '', + 'Thu, 01 Jan 1970 00:00:00 GMT', + 'Lax' + ); + }); + }); + + describe('and receives both the profile id and the panorama id', function () { + let request; + let callBackSpy = sinon.spy(); + + beforeEach(function () { + let submoduleCallback = lotamePanoramaIdSubmodule.getId({}).callback; + submoduleCallback(callBackSpy); + request = server.requests[0]; + + request.respond( + 200, + responseHeader, + JSON.stringify({ + profile_id: '4ec137245858469eb94a4e248f238694', + core_id: + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87b', + expiry_ts: 3600000, + }) + ); + }); + it('should save the profile id', function () { + sinon.assert.calledWith( + setLocalStorageStub, + '_cc_id', + '4ec137245858469eb94a4e248f238694' + ); + sinon.assert.calledWith( + setCookieStub, + '_cc_id', + '4ec137245858469eb94a4e248f238694' + ); + }); + + it('should save the panorama id expiry', function () { + sinon.assert.calledWith( + setLocalStorageStub, + 'panoramaId_expiry', + 3600000 + ); + + sinon.assert.calledWith(setCookieStub, 'panoramaId_expiry', 3600000); + }); + + it('should save the panorama id', function () { + sinon.assert.calledWith( + setLocalStorageStub, + 'panoramaId', + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87b' + ); + + sinon.assert.calledWith( + setCookieStub, + 'panoramaId', + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87b' + ); + }); + }); + }); + + describe('With a panorama id found', function() { + describe('and it is too early to try again', function () { + let submoduleCallback; + + beforeEach(function () { + getCookieStub + .withArgs('panoramaId_expiry') + .returns(String(Date.now() + 100000)); + getCookieStub + .withArgs('panoramaId') + .returns( + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87c' + ); + + submoduleCallback = lotamePanoramaIdSubmodule.getId({}); + }); + + it('should not call the remote server when getId is called', function () { + expect(submoduleCallback).to.be.eql({ + id: 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87c', + }); + }); + }); + + describe('and can try again', function () { + let request; + let callBackSpy = sinon.spy(); + + beforeEach(function () { + getCookieStub.withArgs('panoramaId_expiry').returns('1000'); + getCookieStub + .withArgs('panoramaId') + .returns( + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87d' + ); + + let submoduleCallback = lotamePanoramaIdSubmodule.getId({}).callback; + submoduleCallback(callBackSpy); + + request = server.requests[0]; + + request.respond( + 200, + responseHeader, + JSON.stringify({ + profile_id: '4ec137245858469eb94a4e248f238694', + core_id: + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87d', + expiry_ts: 3600000 + }) + ); + }); + + it('should call the remote server when getId is called', function () { + expect(callBackSpy.calledOnce).to.be.true; + }); + }); + + describe('receives an optout request', function () { + let request; + let callBackSpy = sinon.spy(); + + beforeEach(function () { + getCookieStub.withArgs('panoramaId_expiry').returns('1000'); + getCookieStub + .withArgs('panoramaId') + .returns( + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87d' + ); + + let submoduleCallback = lotamePanoramaIdSubmodule.getId({}).callback; + submoduleCallback(callBackSpy); + + request = server.requests[0]; + + request.respond( + 200, + responseHeader, + JSON.stringify({ + expiry_ts: Date.now() + (30 * 24 * 60 * 60 * 1000), + }) + ); + }); + + it('should call the remote server when getId is called', function () { + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should clear the panorama id', function () { + sinon.assert.calledWith( + removeFromLocalStorageStub, + 'panoramaId' + ); + + sinon.assert.calledWith( + setCookieStub, + 'panoramaId', + '', + 'Thu, 01 Jan 1970 00:00:00 GMT', + 'Lax' + ); + }); + + it('should clear the profile id', function () { + sinon.assert.calledWith(removeFromLocalStorageStub, '_cc_id'); + + sinon.assert.calledWith( + setCookieStub, + '_cc_id', + '', + 'Thu, 01 Jan 1970 00:00:00 GMT', + 'Lax' + ); + }); + }); + }); + + describe('With no panorama id found', function() { + beforeEach(function() { + getCookieStub.withArgs('panoramaId').returns(null); + getLocalStorageStub.withArgs('panoramaId').returns(null); + }) + describe('and it is too early to try again', function () { + let submoduleCallback; + + beforeEach(function () { + getCookieStub + .withArgs('panoramaId_expiry') + .returns(String(Date.now() + 100000)); + + submoduleCallback = lotamePanoramaIdSubmodule.getId({}); + }); + + it('should not call the remote server when getId is called', function () { + expect(submoduleCallback).to.be.eql({ + id: null + }); + }); + }); + + describe('and can try again', function () { + let request; + let callBackSpy = sinon.spy(); + + beforeEach(function () { + getLocalStorageStub + .withArgs('panoramaId_expiry') + .returns('1000'); + + let submoduleCallback = lotamePanoramaIdSubmodule.getId({}).callback; + submoduleCallback(callBackSpy); + + request = server.requests[0]; + + request.respond( + 200, + responseHeader, + JSON.stringify({ + profile_id: '4ec137245858469eb94a4e248f238694', + core_id: + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87e', + expiry_ts: 3600000 + }) + ); + }); + + it('should call the remote server when getId is called', function () { + expect(callBackSpy.calledOnce).to.be.true; + }); + }); + }); + + describe('when gdpr applies', function () { + let request; + let callBackSpy = sinon.spy(); + + beforeEach(function () { + let submoduleCallback = lotamePanoramaIdSubmodule.getId({}, { + gdprApplies: true, + consentString: 'consentGiven' + }).callback; + submoduleCallback(callBackSpy); + + request = server.requests[0]; + + request.respond( + 200, + responseHeader, + JSON.stringify({ + profile_id: '4ec137245858469eb94a4e248f238694', + core_id: + 'ca22992567e3cd4d116a5899b88a55d0d857a23610db939ae6ac13ba2335d87f', + expiry_ts: 3600000, + }) + ); + }); + + it('should call the remote server when getId is called', function () { + expect(callBackSpy.calledOnce).to.be.true; + }); + + it('should pass the gdpr consent string back', function() { + expect(request.url).to.be.eq( + 'https://id.crwdcntrl.net/id?gdpr_applies=true&gdpr_consent=consentGiven' + ); + }); + }); + + it('should retrieve the id when decode is called', function() { + var id = lotamePanoramaIdSubmodule.decode('1234'); + expect(id).to.be.eql({ + 'lotamePanoramaId': '1234' + }); + }); +}); diff --git a/test/spec/modules/lunamediaBidAdapter_spec.js b/test/spec/modules/lunamediaBidAdapter_spec.js index fc8648bf8a0..c0809071419 100755 --- a/test/spec/modules/lunamediaBidAdapter_spec.js +++ b/test/spec/modules/lunamediaBidAdapter_spec.js @@ -7,9 +7,9 @@ describe('lunamediaBidAdapter', function () { let bidRequestsVid; beforeEach(function () { - bidRequests = [{'bidder': 'lunamedia', 'params': {'pubid': '0cf8d6d643e13d86a5b6374148a4afac', 'floor': 0.5, 'placement': 1234}, 'crumbs': {'pubcid': '979fde13-c71e-4ac2-98b7-28c90f99b449'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]]}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'transactionId': 'f72931e6-2b0e-4e37-a2bc-1ea912141f81', 'sizes': [[300, 250]], 'bidId': '2aa73f571eaf29', 'bidderRequestId': '1bac84515a7af3', 'auctionId': '5dbc60fa-1aa1-41ce-9092-e6bbd4d478f7', 'src': 'client', 'bidRequestsCount': 1, 'pageurl': 'http://google.com'}]; + bidRequests = [{'bidder': 'lunamedia', 'params': {'pubid': '0cf8d6d643e13d86a5b6374148a4afac', 'floor': 0.5, 'placement': 1234, size: '320x250'}, 'crumbs': {'pubcid': '979fde13-c71e-4ac2-98b7-28c90f99b449'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]]}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'transactionId': 'f72931e6-2b0e-4e37-a2bc-1ea912141f81', 'sizes': [[300, 250]], 'bidId': '2aa73f571eaf29', 'bidderRequestId': '1bac84515a7af3', 'auctionId': '5dbc60fa-1aa1-41ce-9092-e6bbd4d478f7', 'src': 'client', 'bidRequestsCount': 1, 'pageurl': 'http://google.com'}]; - bidRequestsVid = [{'bidder': 'lunamedia', 'params': {'pubid': '8537f00948fc37cc03c5f0f88e198a76', 'floor': 1.0, 'placement': 1234, 'video': {'id': 123, 'skip': 1, 'mimes': ['video/mp4', 'application/javascript'], 'playbackmethod': [2, 6], 'maxduration': 30}}, 'crumbs': {'pubcid': '979fde13-c71e-4ac2-98b7-28c90f99b449'}, 'mediaTypes': {'video': {'playerSize': [[320, 480]], 'context': 'instream'}}, 'adUnitCode': 'video1', 'transactionId': '8b060952-93f7-4863-af44-bb8796b97c42', 'sizes': [], 'bidId': '25c6ab92aa0e81', 'bidderRequestId': '1d420b73a013fc', 'auctionId': '9a69741c-34fb-474c-83e1-cfa003aaee17', 'src': 'client', 'bidRequestsCount': 1, 'pageurl': 'http://google.com'}]; + bidRequestsVid = [{'bidder': 'lunamedia', 'params': {'pubid': '8537f00948fc37cc03c5f0f88e198a76', 'floor': 1.0, 'placement': 1234, size: '320x480', 'video': {'id': 123, 'skip': 1, 'mimes': ['video/mp4', 'application/javascript'], 'playbackmethod': [2, 6], 'maxduration': 30}}, 'crumbs': {'pubcid': '979fde13-c71e-4ac2-98b7-28c90f99b449'}, 'mediaTypes': {'video': {'playerSize': [[320, 480]], 'context': 'instream'}}, 'adUnitCode': 'video1', 'transactionId': '8b060952-93f7-4863-af44-bb8796b97c42', 'sizes': [], 'bidId': '25c6ab92aa0e81', 'bidderRequestId': '1d420b73a013fc', 'auctionId': '9a69741c-34fb-474c-83e1-cfa003aaee17', 'src': 'client', 'bidRequestsCount': 1, 'pageurl': 'http://google.com'}]; }); describe('spec.isBidRequestValid', function () { diff --git a/test/spec/modules/luponmediaBidAdapter_spec.js b/test/spec/modules/luponmediaBidAdapter_spec.js index 39c915e38b8..8aeecc87c98 100644 --- a/test/spec/modules/luponmediaBidAdapter_spec.js +++ b/test/spec/modules/luponmediaBidAdapter_spec.js @@ -364,4 +364,49 @@ describe('luponmediaBidAdapter', function () { expect(checkSchain).to.equal(false); }); }); + + describe('onBidWon', function () { + const bidWonEvent = { + 'bidderCode': 'luponmedia', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '105bbf8c54453ff', + 'requestId': '934b8752185955', + 'mediaType': 'banner', + 'source': 'client', + 'cpm': 0.364, + 'creativeId': '443801010', + 'currency': 'USD', + 'netRevenue': false, + 'ttl': 300, + 'referrer': '', + 'ad': '', + 'auctionId': '926a8ea3-3dd4-4bf2-95ab-c85c2ce7e99b', + 'responseTimestamp': 1598527728026, + 'requestTimestamp': 1598527727629, + 'bidder': 'luponmedia', + 'adUnitCode': 'div-gpt-ad-1533155193780-5', + 'timeToRespond': 397, + 'size': '300x250', + 'status': 'rendered' + }; + + let ajaxStub; + + beforeEach(() => { + ajaxStub = sinon.stub(spec, 'sendWinningsToServer') + }) + + afterEach(() => { + ajaxStub.restore() + }) + + it('calls luponmedia\'s callback endpoint', () => { + const result = spec.onBidWon(bidWonEvent); + expect(result).to.equal(undefined); + expect(ajaxStub.calledOnce).to.equal(true); + expect(ajaxStub.firstCall.args[0]).to.deep.equal(JSON.stringify(bidWonEvent)); + }); + }); }); diff --git a/test/spec/modules/malltvBidAdapter_spec.js b/test/spec/modules/malltvBidAdapter_spec.js new file mode 100644 index 00000000000..e1e9ad867e7 --- /dev/null +++ b/test/spec/modules/malltvBidAdapter_spec.js @@ -0,0 +1,146 @@ +import { expect } from 'chai'; +import { spec } from 'modules/malltvBidAdapter'; + +describe('malltvAdapterTest', () => { + describe('bidRequestValidity', () => { + it('bidRequest with propertyId and placementId', () => { + expect(spec.isBidRequestValid({ + bidder: 'malltv', + params: { + propertyId: '{propertyId}', + placementId: '{placementId}' + } + })).to.equal(true); + }); + + it('bidRequest without propertyId', () => { + expect(spec.isBidRequestValid({ + bidder: 'malltv', + params: { + placementId: '{placementId}' + } + })).to.equal(false); + }); + + it('bidRequest without placementId', () => { + expect(spec.isBidRequestValid({ + bidder: 'malltv', + params: { + propertyId: '{propertyId}', + } + })).to.equal(false); + }); + + it('bidRequest without propertyId or placementId', () => { + expect(spec.isBidRequestValid({ + bidder: 'malltv', + params: { + propertyId: '{propertyId}', + } + })).to.equal(false); + }); + }); + + describe('bidRequest', () => { + const bidRequests = [{ + 'bidder': 'malltv', + 'params': { + 'propertyId': '{propertyId}', + 'placementId': '{placementId}' + }, + 'adUnitCode': 'hb-leaderboard', + 'transactionId': 'b6b889bb-776c-48fd-bc7b-d11a1cf0425e', + 'sizes': [[300, 250]], + 'bidId': '10bdc36fe0b48c8', + 'bidderRequestId': '70deaff71c281d', + 'auctionId': 'f9012acc-b6b7-4748-9098-97252914f9dc' + }]; + + it('bidRequest HTTP method', () => { + const requests = spec.buildRequests(bidRequests); + requests.forEach(function (requestItem) { + expect(requestItem.method).to.equal('POST'); + }); + }); + + it('bidRequest url', () => { + const endpointUrl = 'https://central.mall.tv/bid'; + const requests = spec.buildRequests(bidRequests); + requests.forEach(function (requestItem) { + expect(requestItem.url).to.match(new RegExp(`${endpointUrl}`)); + }); + }); + + it('bidRequest data', () => { + const requests = spec.buildRequests(bidRequests); + requests.forEach(function (requestItem) { + expect(requestItem.data).to.exist; + }); + }); + + it('bidRequest sizes', () => { + const requests = spec.buildRequests(bidRequests); + requests.forEach(function (requestItem) { + expect(requestItem.data.placements).to.exist; + expect(requestItem.data.placements.length).to.equal(1); + expect(requestItem.data.placements[0].sizes).to.equal('300x250'); + }); + }); + }); + + describe('interpretResponse', () => { + const bidRequest = { + 'method': 'POST', + 'url': 'https://central.mall.tv/bid', + 'data': { + 'sizes': '300x250', + 'adUnitId': 'rectangle', + 'placementId': '{placementId}', + 'propertyId': '{propertyId}', + 'pageViewGuid': '{pageViewGuid}', + 'url': 'http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true', + 'requestid': '26ee8fe87940da7', + 'bidid': '2962dbedc4768bf' + } + }; + + const bidResponse = { + body: [{ + 'CPM': 1, + 'Width': 300, + 'Height': 250, + 'Referrer': 'http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true', + 'Ad': '
Test ad
', + 'CreativeId': '123abc', + 'NetRevenue': false, + 'Currency': 'EUR', + 'TTL': 360 + }], + headers: {} + }; + + it('all keys present', () => { + const result = spec.interpretResponse(bidResponse, bidRequest); + + let keys = [ + 'requestId', + 'cpm', + 'width', + 'height', + 'creativeId', + 'currency', + 'netRevenue', + 'ttl', + 'referrer', + 'ad', + 'vastUrl', + 'mediaType' + ]; + + let resultKeys = Object.keys(result[0]); + resultKeys.forEach(function (key) { + expect(keys.indexOf(key) !== -1).to.equal(true); + }); + }) + }); +}); diff --git a/test/spec/modules/mantisBidAdapter_spec.js b/test/spec/modules/mantisBidAdapter_spec.js index 1dad60f5d98..d9ab3c69a24 100644 --- a/test/spec/modules/mantisBidAdapter_spec.js +++ b/test/spec/modules/mantisBidAdapter_spec.js @@ -1,9 +1,21 @@ import {expect} from 'chai'; import {spec} from 'modules/mantisBidAdapter.js'; import {newBidder} from 'src/adapters/bidderFactory.js'; +import {sfPostMessage, iframePostMessage} from 'modules/mantisBidAdapter'; describe('MantisAdapter', function () { const adapter = newBidder(spec); + let sandbox; + let clock; + + beforeEach(function() { + sandbox = sinon.sandbox.create(); + clock = sandbox.useFakeTimers(); + }); + + afterEach(function() { + sandbox.restore(); + }); describe('isBidRequestValid', function () { let bid = { @@ -31,6 +43,68 @@ describe('MantisAdapter', function () { }); }); + describe('viewability', function() { + it('iframe (viewed)', () => { + let viewed = false; + + sandbox.stub(document, 'getElementsByTagName').withArgs('iframe').returns([ + { + name: 'mantis', + getBoundingClientRect: () => ({ + top: 10, + bottom: 260, + left: 10, + right: 190, + width: 300, + height: 250 + }) + } + ]); + + iframePostMessage({innerHeight: 500, innerWidth: 500}, 'mantis', () => viewed = true); + + sandbox.clock.runAll(); + + expect(viewed).to.equal(true); + }); + + it('safeframe (viewed)', () => { + let viewed = false; + + sfPostMessage({ + ext: { + register: (width, height, callback) => { + expect(width).to.equal(100); + expect(height).to.equal(200); + + callback(); + }, + inViewPercentage: () => 60 + } + }, 100, 200, () => viewed = true); + + expect(viewed).to.equal(true); + }); + + it('safeframe (unviewed)', () => { + let viewed = false; + + sfPostMessage({ + ext: { + register: (width, height, callback) => { + expect(width).to.equal(100); + expect(height).to.equal(200); + + callback(); + }, + inViewPercentage: () => 30 + } + }, 100, 200, () => viewed = true); + + expect(viewed).to.equal(false); + }); + }); + describe('buildRequests', function () { let bidRequests = [ { @@ -47,6 +121,24 @@ describe('MantisAdapter', function () { } ]; + it('gdpr consent not required', function () { + const request = spec.buildRequests(bidRequests, {gdprConsent: {gdprApplies: false}}); + + expect(request.url).not.to.include('consent=false'); + }); + + it('gdpr consent required', function () { + const request = spec.buildRequests(bidRequests, {gdprConsent: {gdprApplies: true}}); + + expect(request.url).to.include('consent=false'); + }); + + it('usp consent', function () { + const request = spec.buildRequests(bidRequests, {uspConsent: 'foobar'}); + + expect(request.url).to.include('usp=foobar'); + }); + it('domain override', function () { window.mantis_domain = 'https://foo'; const request = spec.buildRequests(bidRequests); diff --git a/test/spec/modules/marsmediaBidAdapter_spec.js b/test/spec/modules/marsmediaBidAdapter_spec.js index e02870d9890..b4c2fe68f34 100644 --- a/test/spec/modules/marsmediaBidAdapter_spec.js +++ b/test/spec/modules/marsmediaBidAdapter_spec.js @@ -624,4 +624,38 @@ describe('marsmedia adapter tests', function () { expect(utils.triggerPixel.called).to.equal(true); }); }); + + describe('on Timeout', function () { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + it('exists and is a function', () => { + expect(spec.onTimeout).to.exist.and.to.be.a('function'); + }); + it('should return nothing', function () { + var response = spec.onTimeout({}); + expect(response).to.be.an('undefined') + expect(utils.triggerPixel.called).to.equal(true); + }); + }); + + describe('on Set Targeting', function () { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + it('exists and is a function', () => { + expect(spec.onSetTargeting).to.exist.and.to.be.a('function'); + }); + it('should return nothing', function () { + var response = spec.onSetTargeting({}); + expect(response).to.be.an('undefined') + expect(utils.triggerPixel.called).to.equal(true); + }); + }); }); diff --git a/test/spec/modules/mediaforceBidAdapter_spec.js b/test/spec/modules/mediaforceBidAdapter_spec.js index 09d997e9349..ee478acbc83 100644 --- a/test/spec/modules/mediaforceBidAdapter_spec.js +++ b/test/spec/modules/mediaforceBidAdapter_spec.js @@ -1,6 +1,7 @@ import {assert} from 'chai'; import {spec} from 'modules/mediaforceBidAdapter.js'; import * as utils from '../../../src/utils.js'; +import {BANNER, NATIVE} from '../../../src/mediaTypes.js'; describe('mediaforce bid adapter', function () { let sandbox; @@ -19,7 +20,7 @@ describe('mediaforce bid adapter', function () { } const language = getLanguage(); - const baseUrl = 'https://rtb.mfadsrvr.com' + const baseUrl = 'https://rtb.mfadsrvr.com'; describe('isBidRequestValid()', function () { const defaultBid = { @@ -56,17 +57,6 @@ describe('mediaforce bid adapter', function () { bid.params = {publisher_id: 2, placement_id: '123'}; assert.equal(spec.isBidRequestValid(bid), true); }); - - it('should return false when mediaTypes == native passed (native is not supported yet)', function () { - let bid = utils.deepClone(defaultBid); - bid.mediaTypes = { - native: { - sizes: [[300, 250]] - } - }; - bid.params = {publisher_id: 2, placement_id: '123'}; - assert.equal(spec.isBidRequestValid(bid), true); - }); }); describe('buildRequests()', function () { @@ -76,9 +66,35 @@ describe('mediaforce bid adapter', function () { publisher_id: 'pub123', placement_id: '202', }, + nativeParams: { + title: { + required: true, + len: 800 + }, + image: { + required: true, + sizes: [300, 250], + }, + sponsoredBy: { + required: true + } + }, mediaTypes: { banner: { sizes: [[300, 250]] + }, + native: { + title: { + required: true, + len: 800 + }, + image: { + required: true, + sizes: [300, 250], + }, + sponsoredBy: { + required: true + } } }, transactionId: 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b', @@ -95,7 +111,7 @@ describe('mediaforce bid adapter', function () { const requestUrl = `${baseUrl}/header_bid`; const dnt = utils.getDNT() ? 1 : 0; - const secure = 1 + const secure = 1; it('should return undefined if no validBidRequests passed', function () { assert.equal(spec.buildRequests([]), undefined); @@ -135,13 +151,26 @@ describe('mediaforce bid adapter', function () { secure: secure, bidfloor: bid.params.bidfloor, banner: {w: 300, h: 250}, + native: { + ver: '1.2', + request: { + assets: [ + {id: 1, title: {len: 800}, required: 1}, + {id: 3, img: {w: 300, h: 250, type: 3}, required: 1}, + {id: 5, data: {type: 1}, required: 1} + ], + context: 1, + plcmttype: 1, + ver: '1.2' + } + }, }], }); assert.deepEqual(request, { method: 'POST', url: requestUrl, - data: '{"id":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b","site":{"page":"https%3A%2F%2Fwww.prebid.org","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + language + '"},"imp":[{"tagid":"202","secure":1,"bidfloor":0.5,"banner":{"w":300,"h":250}}]}', + data: '{"id":"d45dd707-a418-42ec-b8a7-b70a6c6fab0b","site":{"page":"https%3A%2F%2Fwww.prebid.org","ref":"https%3A%2F%2Fwww.prebid.org","id":"pub123","publisher":{"id":"pub123"}},"device":{"ua":"' + navigator.userAgent + '","js":1,"dnt":' + dnt + ',"language":"' + language + '"},"imp":[{"tagid":"202","secure":1,"bidfloor":0.5,"banner":{"w":300,"h":250},"native":{"ver":"1.2","request":{"assets":[{"required":1,"id":1,"title":{"len":800}},{"required":1,"id":3,"img":{"type":3,"w":300,"h":250}},{"required":1,"id":5,"data":{"type":1}}],"context":1,"plcmttype":1,"ver":"1.2"}}}]}', }); }); @@ -173,6 +202,7 @@ describe('mediaforce bid adapter', function () { cid: '2_ssl', h: 100, cat: ['IAB1-1'], + dealid: '3901521', crid: '2_ssl', impid: '2b3c9d103723a7', adid: '2_ssl', @@ -193,11 +223,13 @@ describe('mediaforce bid adapter', function () { assert.deepEqual(bids, ([{ ad: bid.adm, cpm: bid.price, + dealId: bid.dealid, creativeId: bid.adid, currency: response.body.cur, height: bid.h, netRevenue: true, burl: bid.burl, + mediaType: BANNER, requestId: bid.impid, ttl: 300, width: bid.w, @@ -205,6 +237,174 @@ describe('mediaforce bid adapter', function () { }); }); + describe('interpretResponse() native as object', function () { + it('successfull response', function () { + let titleText = 'Colorado Drivers With No DUI\'s Getting A Pay Day on Friday'; + let imgData = { + url: `${baseUrl}/image`, + w: 1200, + h: 627 + }; + let nativeLink = `${baseUrl}/click/`; + let nativeTracker = `${baseUrl}/imp-image`; + let sponsoredByValue = 'Comparisons.org'; + let bodyValue = 'Drivers With No Tickets In 3 Years Should Do This On June'; + let bid = { + price: 3, + id: '65599d0a-42d2-446a-9d39-6086c1433ffe', + burl: `${baseUrl}/burl/\${AUCTION_PRICE}`, + cid: '2_ssl', + cat: ['IAB1-1'], + crid: '2_ssl', + impid: '2b3c9d103723a7', + adid: '2_ssl', + ext: { + advertiser_name: 'MediaForce', + native: { + link: {url: nativeLink}, + assets: [{ + id: 1, + title: {text: titleText}, + required: 1 + }, { + id: 3, + img: imgData + }, { + id: 5, + data: {value: sponsoredByValue} + }, { + id: 4, + data: {value: bodyValue} + }], + imptrackers: [nativeTracker], + ver: '1' + }, + language: 'en', + agency_name: 'MediaForce DSP' + } + }; + + let response = { + body: { + seatbid: [{ + bid: [bid] + }], + cur: 'USD', + id: '620190c2-7eef-42fa-91e2-f5c7fbc2bdd3' + } + }; + + let bids = spec.interpretResponse(response); + assert.deepEqual(bids, ([{ + native: { + clickUrl: nativeLink, + clickTrackers: [], + impressionTrackers: [nativeTracker], + javascriptTrackers: [], + title: titleText, + image: { + url: imgData.url, + width: imgData.w, + height: imgData.h + }, + sponsoredBy: sponsoredByValue, + body: bodyValue + }, + cpm: bid.price, + creativeId: bid.adid, + currency: response.body.cur, + netRevenue: true, + burl: bid.burl, + mediaType: NATIVE, + requestId: bid.impid, + ttl: 300, + }])); + }); + }); + + describe('interpretResponse() native as string', function () { + it('successfull response', function () { + let titleText = 'Colorado Drivers With No DUI\'s Getting A Pay Day on Friday'; + let imgData = { + url: `${baseUrl}/image`, + w: 1200, + h: 627 + }; + let nativeLink = `${baseUrl}/click/`; + let nativeTracker = `${baseUrl}/imp-image`; + let sponsoredByValue = 'Comparisons.org'; + let bodyValue = 'Drivers With No Tickets In 3 Years Should Do This On June'; + let adm = JSON.stringify({ + native: { + link: {url: nativeLink}, + assets: [{ + id: 1, + title: {text: titleText}, + required: 1 + }, { + id: 3, + img: imgData + }, { + id: 5, + data: {value: sponsoredByValue} + }, { + id: 4, + data: {value: bodyValue} + }], + imptrackers: [nativeTracker], + ver: '1' + } + }); + let bid = { + price: 3, + id: '65599d0a-42d2-446a-9d39-6086c1433ffe', + burl: `${baseUrl}/burl/\${AUCTION_PRICE}`, + cid: '2_ssl', + cat: ['IAB1-1'], + crid: '2_ssl', + impid: '2b3c9d103723a7', + adid: '2_ssl', + adm: adm + }; + + let response = { + body: { + seatbid: [{ + bid: [bid] + }], + cur: 'USD', + id: '620190c2-7eef-42fa-91e2-f5c7fbc2bdd3' + } + }; + + let bids = spec.interpretResponse(response); + assert.deepEqual(bids, ([{ + native: { + clickUrl: nativeLink, + clickTrackers: [], + impressionTrackers: [nativeTracker], + javascriptTrackers: [], + title: titleText, + image: { + url: imgData.url, + width: imgData.w, + height: imgData.h + }, + sponsoredBy: sponsoredByValue, + body: bodyValue + }, + cpm: bid.price, + creativeId: bid.adid, + currency: response.body.cur, + netRevenue: true, + burl: bid.burl, + mediaType: NATIVE, + requestId: bid.impid, + ttl: 300, + }])); + }); + }); + describe('onBidWon()', function () { beforeEach(function() { sinon.stub(utils, 'triggerPixel'); diff --git a/test/spec/modules/mediagoBidAdapter_spec.js b/test/spec/modules/mediagoBidAdapter_spec.js new file mode 100644 index 00000000000..25cfc72672b --- /dev/null +++ b/test/spec/modules/mediagoBidAdapter_spec.js @@ -0,0 +1,101 @@ +import { + expect +} from 'chai'; +import { + spec +} from 'modules/mediagoBidAdapter.js'; + +describe('mediago:BidAdapterTests', function() { + let bidRequestData = { + 'bidderCode': 'mediago', + 'auctionId': '7fae02a9-0195-472f-ba94-708d3bc2c0d9', + 'bidderRequestId': '4fec04e87ad785', + 'bids': [{ + 'bidder': 'mediago', + 'params': { + 'token': '85a6b01e41ac36d49744fad726e3655d' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ] + ] + } + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': '5e24a2ce-db03-4565-a8a3-75dbddca9377', + 'sizes': [ + [ + 300, + 250 + ] + ], + 'bidId': '54d73f19c9d47a', + 'bidderRequestId': '4fec04e87ad785', + 'auctionId': '7fae02a9-0195-472f-ba94-708d3bc2c0d9', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + }] + }; + let request = []; + + it('mediago:validate_pub_params', function() { + expect( + spec.isBidRequestValid({ + bidder: 'mediago', + params: { + token: ['85a6b01e41ac36d49744fad726e3655d'] + } + }) + ).to.equal(true); + }); + + it('mediago:validate_generated_params', function() { + request = spec.buildRequests(bidRequestData.bids, bidRequestData); + // console.log(request); + let req_data = JSON.parse(request.data); + expect(req_data.imp).to.have.lengthOf(1); + }); + + it('mediago:validate_response_params', function() { + let serverResponse = { + body: { + 'id': '7244645c-a81a-4760-8fd6-9d908d2c4a44', + 'seatbid': [{ + 'bid': [{ + 'id': 'aa86796a857ebedda9a2d7128a87dab1', + 'impid': '1', + 'price': 0.05, + 'nurl': 'http://d21uzv52i0cqie.cloudfront.net/api/winnotice?tn=341443089c0cb829164455a42d216ee3\u0026winloss=1\u0026id=aa86796a857ebedda9a2d7128a87dab1\u0026seat_id=${AUCTION_SEAT_ID}\u0026currency=${AUCTION_CURRENCY}\u0026bid_id=${AUCTION_BID_ID}\u0026ad_id=${AUCTION_AD_ID}\u0026loss=${AUCTION_LOSS}\u0026imp_id=1\u0026price=${AUCTION_PRICE}\u0026test=0\u0026time=1597714943\u0026adp=Dtnz0O4U8sdAU-XGGijCAgMbjDIeMGyCLXeSg1laXxM\u0026dsp_id=22\u0026url=-BFDu2NYtc4PYTplFW_2JcnDSRVLOOfaERbwJABjFyG6NUB4ywA3dUaXt5zPlyCUpBCOxjH9gk4E6yWTshzuSfQSx7g_TxvcXYUgh7YtY9NQZxx14InmNCTsezqID5UztV7llz8SXWHQ-ZsutH1nJIZzl1jH3i2uCPi91shqIZLN1bLJ5guAr5O4WyxVeOqIKyD_GiVcY9Olm51iI_3wgwFyDEN_dIDv-ObgNxpbPD0L11-62bjhGw3__7RuEo6XLdox-g46Fcqk6i0zayfsPM4QeMAhWJ4lsg-xswSI0YAfzyoOIeTWB78mdpt_GmN5PKZZPqyO7VkbwHEasn-mTyYTddbz5v2fzEkRO0AQZtAZx96PANGrNvcOHnRVmCdkzN96b5Ur1_8ipdyzHOFRtJ-z_KmKaxig6himvMCePozZvrvihiGhigP4RGiFT7ytVYKHyUGAV2PF5SwtgnB0uGCltd7o1CLhZyZEQNgE7LSESyGztZ5kM9N_VZV9gPZVhvlJDfYFNRW9i6D2pZxV0Gd63rA9gpeUJ3mhbkj-B27VRKrNTBSrwIAU7P0RPD5_opl3G8nPD1Ce2vKuQK8qynHWQblfeA61nDok-fRezSKbzwepqi8oxXadFrCmN7KxP_mPqA794xYzIw5-mS64NA', + 'burl': 'http://d21uzv52i0cqie.cloudfront.net/api/winnotice?tn=341443089c0cb829164455a42d216ee3\u0026winloss=2\u0026id=aa86796a857ebedda9a2d7128a87dab1\u0026seat_id=${AUCTION_SEAT_ID}\u0026currency=${AUCTION_CURRENCY}\u0026bid_id=${AUCTION_BID_ID}\u0026ad_id=${AUCTION_AD_ID}\u0026loss=${AUCTION_LOSS}\u0026imp_id=1\u0026price=${AUCTION_PRICE}\u0026test=0\u0026time=1597714943\u0026adp=Dtnz0O4U8sdAU-XGGijCAgMbjDIeMGyCLXeSg1laXxM\u0026dsp_id=22\u0026url=dXerAvyp4zYQzsQ56eGB4JtiA4yFaYlTqcHffccrvCg', + 'lurl': 'http://d21uzv52i0cqie.cloudfront.net/api/winnotice?tn=341443089c0cb829164455a42d216ee3\u0026winloss=0\u0026id=aa86796a857ebedda9a2d7128a87dab1\u0026seat_id=${AUCTION_SEAT_ID}\u0026currency=${AUCTION_CURRENCY}\u0026bid_id=${AUCTION_BID_ID}\u0026ad_id=${AUCTION_AD_ID}\u0026loss=${AUCTION_LOSS}\u0026imp_id=1\u0026price=${AUCTION_PRICE}\u0026test=0\u0026time=1597714943\u0026adp=Dtnz0O4U8sdAU-XGGijCAgMbjDIeMGyCLXeSg1laXxM\u0026dsp_id=22\u0026url=ptSxg_vR7-fdx-WAkkUADJb__BntE5a6-RSeYdUewvk', + 'adm': '\u003clink rel=\"stylesheet\" href=\"//cdn.mediago.io/js/style/style_banner_300*250.css\"\u003e\u003cdiv id=\"mgcontainer-583ce3286b442001205b2fb9a5488efc\" class=\"mediago-placement imgTopTitleBottom\" style=\"position:relative;width:298px;height:248px;overflow:hidden\"\u003e\u003ca href=\"http://trace.mediago.io/api/bidder/track?tn=341443089c0cb829164455a42d216ee3\u0026price=PRMC8pCHtH55ipgXubUs8jlsKTBxWRSEweH8Mee_aUQ\u0026evt=102\u0026rid=aa86796a857ebedda9a2d7128a87dab1\u0026campaignid=1003540\u0026impid=25-300x175-1\u0026offerid=1107782\u0026test=0\u0026time=1597714943\u0026cp=GJA03gjm-ugPTmN7prOpvhfu1aA04IgpTcW4oRX22Lg\u0026clickid=25_aa86796a857ebedda9a2d7128a87dab1_25-300x175-1\u0026acid=164\u0026trackingid=583ce3286b442001205b2fb9a5488efc\u0026uid=6dda6c6b70eb4e2d9ab3469d921f2c74\u0026jt=2\u0026url=PQFFci337KgCVkx7KTgRItClLaWH0lgTcIlgBRTpfKngVJES4uKLfxXz9mjLcDWIbWQcEVVk_gfTcIaK8oKO2YyVG5lc3hjZeZr0VaIDHbWggPJaqtfDK9T0HZIKvrpe\" target=\"_blank\"\u003e\u003cimg alt=\"Robert Vowed To Keep Silent, But Decided To Put The People First And Speak\" src=\"https://d2cli4kgl5uxre.cloudfront.net/ML/b5e361889beef5eaf69987384b7a56e8__300x175.png\" style=\"height:70%;width:100%;border-width:0;border:none;\"\u003e\u003ch3 class=\"title\" style=\"font-size:16px;\"\u003eRobert Vowed To Keep Silent, But Decided To Put The People First And Speak\u003c/h3\u003e\u003c/a\u003e\u003cspan class=\"source\"\u003e\u003ca class=\"sourcename\" href=\"//www.mediago.io\" target=\"_blank\"\u003e\u003cspan\u003eAd\u003c/span\u003e \u003c/a\u003e\u003ca class=\"srcnameadslabelurl\" href=\"//www.mediago.io/privacy\" target=\"_blank\"\u003e\u003cspan\u003eViral Net News\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e\u003c/div\u003e\u003cscript\u003e!function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){\"undefined\"!=typeof Symbol\u0026\u0026Symbol.toStringTag\u0026\u0026Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},n.t=function(e,t){if(1\u0026t\u0026\u0026(e=n(e)),8\u0026t)return e;if(4\u0026t\u0026\u0026\"object\"==typeof e\u0026\u0026e\u0026\u0026e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,\"default\",{enumerable:!0,value:e}),2\u0026t\u0026\u0026\"string\"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e\u0026\u0026e.__esModule?function(){return e.default}:function(){return e};return n.d(t,\"a\",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p=\"\",n(n.s=24)}({24:function(e,t,n){\"use strict\";function o(e){var t=new Image;t.src=e,t.style=\"display:none;visibility:hidden\",t.width=0,t.height=0,document.body.appendChild(t)}o(\"http://d21uzv52i0cqie.cloudfront.net/api/bidder/track?tn=341443089c0cb829164455a42d216ee3\u0026price=PRMC8pCHtH55ipgXubUs8jlsKTBxWRSEweH8Mee_aUQ\u0026evt=101\u0026rid=aa86796a857ebedda9a2d7128a87dab1\u0026campaignid=1003540\u0026impid=25-300x175-1\u0026offerid=1107782\u0026test=0\u0026time=1597714943\u0026cp=GJA03gjm-ugPTmN7prOpvhfu1aA04IgpTcW4oRX22Lg\u0026acid=164\u0026trackingid=583ce3286b442001205b2fb9a5488efc\u0026uid=6dda6c6b70eb4e2d9ab3469d921f2c74\");var r=document.getElementById(\"mgcontainer-583ce3286b442001205b2fb9a5488efc\"),i=!1;!function e(){setTimeout((function(){var t,n;!i\u0026\u0026(t=r,n=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight,(t.getBoundingClientRect()\u0026\u0026t.getBoundingClientRect().top)\u003c=n-.75*(t.offsetHeight||t.clientHeight))?(i=!0,o(\"http://d21uzv52i0cqie.cloudfront.net/api/bidder/track?tn=341443089c0cb829164455a42d216ee3\u0026price=PRMC8pCHtH55ipgXubUs8jlsKTBxWRSEweH8Mee_aUQ\u0026evt=104\u0026rid=aa86796a857ebedda9a2d7128a87dab1\u0026campaignid=1003540\u0026impid=25-300x175-1\u0026offerid=1107782\u0026test=0\u0026time=1597714943\u0026cp=GJA03gjm-ugPTmN7prOpvhfu1aA04IgpTcW4oRX22Lg\u0026acid=164\u0026trackingid=583ce3286b442001205b2fb9a5488efc\u0026uid=6dda6c6b70eb4e2d9ab3469d921f2c74\u0026sid=16__11__13\u0026format=\u0026crid=b5e361889beef5eaf69987384b7a56e8\")):e()}),500)}()}});\u003c/script\u003e\u003cscript type=\"text/javascript\" src=\"http://d21uzv52i0cqie.cloudfront.net/api/track?tn=341443089c0cb829164455a42d216ee3\u0026price=${AUCTION_PRICE}\u0026evt=5\u0026rid=aa86796a857ebedda9a2d7128a87dab1\u0026impid=1\u0026offerid=\u0026tagid=\u0026test=0\u0026time=1597714943\u0026adp=5zrCZ2rC-WLafYkNpeTnzA72tDqVZUlOA3Js6_eJjYU\u0026dsp_id=22\u0026cp=${cp}\u0026url=\u0026type=script\"\u003e\u003c/script\u003e\u003cscript\u003edocument.addEventListener\u0026\u0026document.addEventListener(\"click\",function(){var a=document.createElement(\"script\");a.src=\"http://d21uzv52i0cqie.cloudfront.net/api/track?tn=341443089c0cb829164455a42d216ee3\u0026price=${AUCTION_PRICE}\u0026evt=6\u0026rid=aa86796a857ebedda9a2d7128a87dab1\u0026impid=1\u0026offerid=\u0026tagid=\u0026test=0\u0026time=1597714943\u0026adp=5zrCZ2rC-WLafYkNpeTnzA72tDqVZUlOA3Js6_eJjYU\u0026dsp_id=22\u0026cp=${cp}\u0026url=\u0026clickid=25_aa86796a857ebedda9a2d7128a87dab1_1\";document.body.appendChild(a)});\u003c/script\u003e', + 'cid': '1003540', + 'crid': 'b5e361889beef5eaf69987384b7a56e8', + 'w': 300, + 'h': 250 + }] + }], + 'cur': 'USD' + } + }; + + let bids = spec.interpretResponse(serverResponse); + // console.log({ + // bids + // }); + expect(bids).to.have.lengthOf(1); + + let bid = bids[0]; + + expect(bid.creativeId).to.equal('b5e361889beef5eaf69987384b7a56e8'); + expect(bid.width).to.equal(300); + expect(bid.height).to.equal(250); + expect(bid.currency).to.equal('USD'); + }); +}); diff --git a/test/spec/modules/medianetAnalyticsAdapter_spec.js b/test/spec/modules/medianetAnalyticsAdapter_spec.js index dcec1050652..41a6338225e 100644 --- a/test/spec/modules/medianetAnalyticsAdapter_spec.js +++ b/test/spec/modules/medianetAnalyticsAdapter_spec.js @@ -9,18 +9,32 @@ const { } = CONSTANTS; const MOCK = { - AUCTION_INIT: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'timestamp': 1584563605739}, + Ad_Units: [{'code': 'div-gpt-ad-1460505748561-0', 'mediaTypes': {'banner': {'sizes': [[300, 250]]}}, 'bids': [], 'ext': {'prop1': 'value1'}}], + MULTI_FORMAT_TWIN_AD_UNITS: [{'code': 'div-gpt-ad-1460505748561-0', 'mediaTypes': {'banner': {'sizes': [[300, 250]]}, 'native': {'image': {'required': true, 'sizes': [150, 50]}}}, 'bids': [], 'ext': {'prop1': 'value1'}}, {'code': 'div-gpt-ad-1460505748561-0', 'mediaTypes': {'video': {'playerSize': [640, 480], 'context': 'instream'}}, 'bids': [], 'ext': {'prop1': 'value1'}}], + AUCTION_INIT: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'timestamp': 1584563605739, 'timeout': 6000}, + AUCTION_INIT_WITH_FLOOR: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'timestamp': 1584563605739, 'timeout': 6000, 'bidderRequests': [{'bids': [{ 'floorData': {'enforcements': {'enforceJS': true}} }]}]}, BID_REQUESTED: {'bidderCode': 'medianet', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'bids': [{'bidder': 'medianet', 'params': {'cid': 'TEST_CID', 'crid': '451466393'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]], 'ext': ['asdads']}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'sizes': [[300, 250]], 'bidId': '28248b0e6aece2', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'}], 'auctionStart': 1584563605739, 'timeout': 6000, 'uspConsent': '1YY', 'start': 1584563605743}, - BID_RESPONSE: {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}, + MULTI_FORMAT_BID_REQUESTED: {'bidderCode': 'medianet', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'bids': [{'bidder': 'medianet', 'params': {'cid': 'TEST_CID', 'crid': '451466393'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]]}, 'video': {'playerSize': [640, 480], 'context': 'instream'}, 'native': {'image': {'required': true, 'sizes': [150, 50]}, 'title': {'required': true, 'len': 80}}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'sizes': [[300, 250]], 'bidId': '28248b0e6aece2', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'}], 'auctionStart': 1584563605739, 'timeout': 6000, 'uspConsent': '1YY', 'start': 1584563605743}, + BID_RESPONSE: {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.10, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}, AUCTION_END: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'auctionEnd': 1584563605739}, SET_TARGETING: {'div-gpt-ad-1460505748561-0': {'prebid_test': '1', 'hb_format': 'banner', 'hb_source': 'client', 'hb_size': '300x250', 'hb_pb': '2.00', 'hb_adid': '3e6e4bce5c8fb3', 'hb_bidder': 'medianet', 'hb_format_medianet': 'banner', 'hb_source_medianet': 'client', 'hb_size_medianet': '300x250', 'hb_pb_medianet': '2.00', 'hb_adid_medianet': '3e6e4bce5c8fb3', 'hb_bidder_medianet': 'medianet'}}, + NO_BID_SET_TARGETING: {'div-gpt-ad-1460505748561-0': {}}, BID_WON: {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'statusMessage': 'Bid available', 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}, NO_BID: {'bidder': 'medianet', 'params': {'cid': 'test123', 'crid': '451466393', 'site': {}}, 'mediaTypes': {'banner': {'sizes': [[300, 250]], 'ext': ['asdads']}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'transactionId': '303fa0c6-682f-4aea-8e4a-dc68f0d5c7d5', 'sizes': [[300, 250], [300, 600]], 'bidId': '28248b0e6aece2', 'bidderRequestId': '13fccf3809fe43', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'}, BID_TIMEOUT: [{'bidId': '28248b0e6aece2', 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'params': [{'cid': 'test123', 'crid': '451466393', 'site': {}}, {'cid': '8CUX0H51P', 'crid': '451466393', 'site': {}}], 'timeout': 6}] } +function performAuctionWithFloorConfig() { + events.emit(AUCTION_INIT, {...MOCK.AUCTION_INIT_WITH_FLOOR, adUnits: MOCK.Ad_Units}); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(BID_WON, MOCK.BID_WON); +} + function performStandardAuctionWithWinner() { - events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(AUCTION_INIT, {...MOCK.AUCTION_INIT, adUnits: MOCK.Ad_Units}); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(BID_RESPONSE, MOCK.BID_RESPONSE); events.emit(AUCTION_END, MOCK.AUCTION_END); @@ -28,20 +42,28 @@ function performStandardAuctionWithWinner() { events.emit(BID_WON, MOCK.BID_WON); } +function performMultiFormatAuctionWithNoBid() { + events.emit(AUCTION_INIT, {...MOCK.AUCTION_INIT, adUnits: MOCK.MULTI_FORMAT_TWIN_AD_UNITS}); + events.emit(BID_REQUESTED, MOCK.MULTI_FORMAT_BID_REQUESTED); + events.emit(NO_BID, MOCK.NO_BID); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(SET_TARGETING, MOCK.NO_BID_SET_TARGETING); +} + function performStandardAuctionWithNoBid() { - events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(AUCTION_INIT, {...MOCK.AUCTION_INIT, adUnits: MOCK.Ad_Units}); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(NO_BID, MOCK.NO_BID); events.emit(AUCTION_END, MOCK.AUCTION_END); - events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(SET_TARGETING, MOCK.NO_BID_SET_TARGETING); } function performStandardAuctionWithTimeout() { - events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(AUCTION_INIT, {...MOCK.AUCTION_INIT, adUnits: MOCK.Ad_Units}); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(BID_TIMEOUT, MOCK.BID_TIMEOUT); events.emit(AUCTION_END, MOCK.AUCTION_END); - events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(SET_TARGETING, MOCK.NO_BID_SET_TARGETING); } function getQueryData(url) { @@ -104,8 +126,10 @@ describe('Media.net Analytics Adapter', function() { cid: 'test123' } }); + medianetAnalytics.clearlogsQueue(); }); afterEach(function () { + medianetAnalytics.clearlogsQueue(); medianetAnalytics.disableAnalytics(); }); @@ -115,6 +139,16 @@ describe('Media.net Analytics Adapter', function() { expect(medianetAnalytics.getlogsQueue().length).to.equal(0); }); + it('should have all applicable sizes in request', function() { + medianetAnalytics.clearlogsQueue(); + performMultiFormatAuctionWithNoBid(); + const noBidLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log))[0]; + medianetAnalytics.clearlogsQueue(); + expect(noBidLog.mtype).to.have.ordered.members([encodeURIComponent('banner|native|video'), encodeURIComponent('banner|video|native')]); + expect(noBidLog.szs).to.have.ordered.members([encodeURIComponent('300x250|1x1|640x480'), encodeURIComponent('300x250|1x1|640x480')]); + expect(noBidLog.vplcmtt).to.equal('instream'); + }); + it('should have winner log in standard auction', function() { medianetAnalytics.clearlogsQueue(); performStandardAuctionWithWinner(); @@ -137,12 +171,30 @@ describe('Media.net Analytics Adapter', function() { src: 'client', size: '300x250', mtype: 'banner', + gdpr: '0', cid: 'test123', lper: '1', ogbdp: '1.1495', flt: '1', supcrid: 'div-gpt-ad-1460505748561-0', - mpvid: '123' + mpvid: '123', + bidflr: '1.1' + }); + }); + + it('should have correct bid floor data in winner log', function() { + medianetAnalytics.clearlogsQueue(); + performAuctionWithFloorConfig(); + let winnerLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter((log) => log.winner); + medianetAnalytics.clearlogsQueue(); + + expect(winnerLog[0]).to.include({ + winner: '1', + curr: 'USD', + ogbdp: '1.1495', + bidflr: '1.1', + flrrule: 'banner', + flrdata: encodeURIComponent('ln=||skp=||enfj=true||enfd=||sr=||fs=') }); }); @@ -158,7 +210,7 @@ describe('Media.net Analytics Adapter', function() { expect(noBidLog.status).to.have.ordered.members(['1', '2']); expect(noBidLog.src).to.have.ordered.members(['client', 'client']); expect(noBidLog.curr).to.have.ordered.members(['', '']); - expect(noBidLog.mtype).to.have.ordered.members(['', '']); + expect(noBidLog.mtype).to.have.ordered.members(['banner', 'banner']); expect(noBidLog.ogbdp).to.have.ordered.members(['', '']); expect(noBidLog.mpvid).to.have.ordered.members(['', '']); expect(noBidLog.crid).to.have.ordered.members(['', '451466393']); @@ -176,7 +228,7 @@ describe('Media.net Analytics Adapter', function() { expect(timeoutLog.status).to.have.ordered.members(['1', '3']); expect(timeoutLog.src).to.have.ordered.members(['client', 'client']); expect(timeoutLog.curr).to.have.ordered.members(['', '']); - expect(timeoutLog.mtype).to.have.ordered.members(['', '']); + expect(timeoutLog.mtype).to.have.ordered.members(['banner', 'banner']); expect(timeoutLog.ogbdp).to.have.ordered.members(['', '']); expect(timeoutLog.mpvid).to.have.ordered.members(['', '']); expect(timeoutLog.crid).to.have.ordered.members(['', '451466393']); diff --git a/test/spec/modules/medianetBidAdapter_spec.js b/test/spec/modules/medianetBidAdapter_spec.js index cf23bc62655..649929056fa 100644 --- a/test/spec/modules/medianetBidAdapter_spec.js +++ b/test/spec/modules/medianetBidAdapter_spec.js @@ -37,6 +37,11 @@ let VALID_BID_REQUEST = [{ }, 'adUnitCode': 'div-gpt-ad-1460505748561-123', 'transactionId': 'c52a5c62-3c2b-4b90-9ff8-ec1487754822', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 251]], + } + }, 'sizes': [[300, 251]], 'bidId': '3f97ca71b1e5c2', 'bidderRequestId': '1e9b1f07797c1c', @@ -81,6 +86,11 @@ let VALID_BID_REQUEST = [{ }, 'adUnitCode': 'div-gpt-ad-1460505748561-123', 'transactionId': 'c52a5c62-3c2b-4b90-9ff8-ec1487754822', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 251]], + } + }, 'sizes': [[300, 251]], 'bidId': '3f97ca71b1e5c2', 'bidderRequestId': '1e9b1f07797c1c', @@ -127,6 +137,11 @@ let VALID_BID_REQUEST = [{ }, 'adUnitCode': 'div-gpt-ad-1460505748561-123', 'transactionId': 'c52a5c62-3c2b-4b90-9ff8-ec1487754822', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 251]], + } + }, 'sizes': [[300, 251]], 'bidId': '3f97ca71b1e5c2', 'bidderRequestId': '1e9b1f07797c1c', @@ -731,6 +746,28 @@ let VALID_BID_REQUEST = [{ }], 'tmax': config.getConfig('bidderTimeout') }, + + VALID_VIDEO_BID_REQUEST = [{ + 'bidder': 'medianet', + 'params': { + 'cid': 'customer_id', + 'video': { + 'skipppable': true + } + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': '277b631f-92f5-4844-8b19-ea13c095d3f1', + 'mediaTypes': { + 'video': { + 'context': 'instream', + } + }, + 'bidId': '28f8f8130a583e', + 'bidderRequestId': '1e9b1f07797c1c', + 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'bidRequestsCount': 1 + }], + VALID_PAYLOAD_PAGE_META = (() => { let PAGE_META; try { @@ -1109,6 +1146,8 @@ describe('Media.net bid adapter', function () { describe('buildRequests', function () { beforeEach(function () { + $$PREBID_GLOBAL$$.medianetGlobals = {}; + let documentStub = sandbox.stub(document, 'getElementById'); let boundingRect = { top: 50, @@ -1154,6 +1193,11 @@ describe('Media.net bid adapter', function () { expect(JSON.parse(bidReq.data)).to.deep.equal(VALID_PAYLOAD_NATIVE); }); + it('should parse params for video request', function () { + let bidReq = spec.buildRequests(VALID_VIDEO_BID_REQUEST, VALID_AUCTIONDATA); + expect(JSON.stringify(bidReq.data)).to.include('instream'); + }); + it('should have valid crid present in bid request', function() { sandbox.stub(config, 'getConfig').callsFake((key) => { const config = { diff --git a/test/spec/modules/mediasquareBidAdapter_spec.js b/test/spec/modules/mediasquareBidAdapter_spec.js new file mode 100644 index 00000000000..5d930f2b6ac --- /dev/null +++ b/test/spec/modules/mediasquareBidAdapter_spec.js @@ -0,0 +1,131 @@ +import {expect} from 'chai'; +import {spec} from 'modules/mediasquareBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; +import {config} from 'src/config.js'; +import * as utils from 'src/utils.js'; +import { requestBidsHook } from 'modules/consentManagement.js'; + +describe('MediaSquare bid adapter tests', function () { + var DEFAULT_PARAMS = [{ + adUnitCode: 'banner-div', + bidId: 'aaaa1234', + auctionId: 'bbbb1234', + transactionId: 'cccc1234', + mediaTypes: { + banner: { + sizes: [ + [300, 250] + ] + } + }, + bidder: 'mediasquare', + params: { + owner: 'test', + code: 'publishername_atf_desktop_rg_pave' + }, + }]; + + var BID_RESPONSE = {'body': { + 'responses': [{ + 'transaction_id': 'cccc1234', + 'cpm': 22.256608, + 'width': 300, + 'height': 250, + 'creative_id': '158534630', + 'currency': 'USD', + 'net_revenue': true, + 'ttl': 300, + 'ad': '< --- creative code --- >', + 'bidder': 'msqClassic', + 'code': 'test/publishername_atf_desktop_rg_pave', + 'bid_id': 'aaaa1234', + }], + }}; + + const DEFAULT_OPTIONS = { + gdprConsent: { + gdprApplies: true, + consentString: 'BOzZdA0OzZdA0AGABBENDJ-AAAAvh7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__79__3z3_9pxP78k89r7337Mw_v-_v-b7JCPN_Y3v-8Kg', + vendorData: {} + }, + refererInfo: { + referer: 'https://www.prebid.org', + canonicalUrl: 'https://www.prebid.org/the/link/to/the/page' + }, + uspConsent: '111222333', + userId: { 'id5id': { uid: '1111' } }, + schain: { + 'ver': '1.0', + 'complete': 1, + 'nodes': [{ + 'asi': 'exchange1.com', + 'sid': '1234', + 'hp': 1, + 'rid': 'bid-request-1', + 'name': 'publisher', + 'domain': 'publisher.com' + }] + }, + }; + it('Verify build request', function () { + const request = spec.buildRequests(DEFAULT_PARAMS, DEFAULT_OPTIONS); + expect(request).to.have.property('url').and.to.equal('https://pbs-front.mediasquare.fr/msq_prebid'); + expect(request).to.have.property('method').and.to.equal('POST'); + const requestContent = JSON.parse(request.data); + expect(requestContent.codes[0]).to.have.property('owner').and.to.equal('test'); + expect(requestContent.codes[0]).to.have.property('code').and.to.equal('publishername_atf_desktop_rg_pave'); + expect(requestContent.codes[0]).to.have.property('adunit').and.to.equal('banner-div'); + expect(requestContent.codes[0]).to.have.property('bidId').and.to.equal('aaaa1234'); + expect(requestContent.codes[0]).to.have.property('auctionId').and.to.equal('bbbb1234'); + expect(requestContent.codes[0]).to.have.property('transactionId').and.to.equal('cccc1234'); + expect(requestContent.codes[0]).to.have.property('mediatypes').exist; + }); + + it('Verify parse response', function () { + const request = spec.buildRequests(DEFAULT_PARAMS, DEFAULT_OPTIONS); + const response = spec.interpretResponse(BID_RESPONSE, request); + expect(response).to.have.lengthOf(1); + const bid = response[0]; + expect(bid.cpm).to.equal(22.256608); + expect(bid.ad).to.equal('< --- creative code --- >'); + expect(bid.width).to.equal(300); + expect(bid.height).to.equal(250); + expect(bid.creativeId).to.equal('158534630'); + expect(bid.currency).to.equal('USD'); + expect(bid.netRevenue).to.equal(true); + expect(bid.ttl).to.equal(300); + expect(bid.requestId).to.equal('aaaa1234'); + expect(bid.mediasquare).to.exist; + expect(bid.mediasquare.bidder).to.equal('msqClassic'); + expect(bid.mediasquare.code).to.equal([DEFAULT_PARAMS[0].params.owner, DEFAULT_PARAMS[0].params.code].join('/')); + }); + + it('Verifies bidder code', function () { + expect(spec.code).to.equal('mediasquare'); + }); + + it('Verifies bidder aliases', function () { + expect(spec.aliases).to.have.lengthOf(1); + expect(spec.aliases[0]).to.equal('msq'); + }); + it('Verifies if bid request valid', function () { + expect(spec.isBidRequestValid(DEFAULT_PARAMS[0])).to.equal(true); + }); + it('Verifies bid won', function () { + const request = spec.buildRequests(DEFAULT_PARAMS, DEFAULT_OPTIONS); + const response = spec.interpretResponse(BID_RESPONSE, request); + const won = spec.onBidWon(response[0]); + expect(won).to.equal(true); + }); + it('Verifies user sync without cookie in bid response', function () { + var syncs = spec.getUserSyncs({}, [BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent, DEFAULT_OPTIONS.uspConsent); + expect(syncs).to.have.property('type').and.to.equal('iframe'); + }); + it('Verifies user sync with cookies in bid response', function () { + BID_RESPONSE.body.cookies = [{'type': 'image', 'url': 'http://www.cookie.sync.org/'}]; + var syncs = spec.getUserSyncs({}, [BID_RESPONSE], DEFAULT_OPTIONS.gdprConsent); + expect(syncs).to.have.lengthOf(1); + expect(syncs[0]).to.have.property('type').and.to.equal('image'); + expect(syncs[0]).to.have.property('url').and.to.equal('http://www.cookie.sync.org/'); + }); +}); diff --git a/test/spec/modules/nextrollBidAdapter_spec.js b/test/spec/modules/nextrollBidAdapter_spec.js index 85cd45be1d0..7722443e584 100644 --- a/test/spec/modules/nextrollBidAdapter_spec.js +++ b/test/spec/modules/nextrollBidAdapter_spec.js @@ -27,6 +27,44 @@ describe('nextrollBidAdapter', function() { let bidWithoutValidId = { id: '' }; let bidWithoutId = { params: { zoneId: 'zone1' } }; + describe('nativeBidRequest', () => { + it('validates native spec', () => { + let nativeAdUnit = [{ + bidder: 'nextroll', + adUnitCode: 'adunit-code', + bidId: 'bid_id', + mediaTypes: { + native: { + title: {required: true, len: 80}, + image: {required: true, sizes: [728, 90]}, + sponsoredBy: {required: false, len: 20}, + clickUrl: {required: true}, + body: {required: true, len: 25}, + icon: {required: true, sizes: [50, 50], aspect_ratios: [{ratio_height: 3, ratio_width: 4}]}, + someRandomAsset: {required: false, len: 100} // This should be ignored + } + }, + params: { + bidfloor: 1, + zoneId: 'zone1', + publisherId: 'publisher_id' + } + }]; + + let request = spec.buildRequests(nativeAdUnit) + let assets = request[0].data.imp.native.request.native.assets + + let excptedAssets = [ + {id: 1, required: 1, title: {len: 80}}, + {id: 2, required: 1, img: {w: 728, h: 90, wmin: 1, hmin: 1, type: 3}}, + {id: 3, required: 1, img: {w: 50, h: 50, wmin: 4, hmin: 3, type: 1}}, + {id: 5, required: 0, data: {len: 20, type: 1}}, + {id: 6, required: 1, data: {len: 25, type: 2}} + ] + expect(assets).to.be.deep.equal(excptedAssets) + }) + }) + describe('isBidRequestValid', function() { it('validates the bids correctly when the bid has an id', function() { expect(spec.isBidRequestValid(validBid)).to.be.true; @@ -86,6 +124,13 @@ describe('nextrollBidAdapter', function() { expect(bannerObject.format[0].w).to.be.equal(300); expect(bannerObject.format[0].h).to.be.equal(200); }); + + it('sets the CCPA consent string', function () { + const us_privacy = '1YYY'; + const request = spec.buildRequests([validBid], {'uspConsent': us_privacy})[0]; + + expect(request.data.regs.ext.us_privacy).to.be.equal(us_privacy); + }); }); describe('interpretResponse', function () { @@ -142,42 +187,82 @@ describe('nextrollBidAdapter', function() { }); }); - describe('hasCCPAConsent', function() { - function ccpaRequest(consentString) { - return { - bidderCode: 'bidderX', - auctionId: 'e3a336ad-2222-4a1c-bbbb-ecc7c5554a34', - uspConsent: consentString - }; - } + describe('interpret native response', () => { + let clickUrl = 'https://clickurl.com/with/some/path' + let titleText = 'Some title' + let imgW = 300 + let imgH = 250 + let imgUrl = 'https://clickurl.com/img.png' + let brandText = 'Some Brand' + let impUrl = 'https://clickurl.com/imptracker' - const noNoticeCases = ['1NYY', '1NNN', '1N--']; - noNoticeCases.forEach((ccpaString, index) => { - it(`No notice should indicate no consent (case ${index})`, function () { - const req = ccpaRequest(ccpaString); - expect(hasCCPAConsent(req)).to.be.false; - }); - }); + let responseBody = { + body: { + id: 'bidresponse_id', + seatbid: [{ + bid: [{ + price: 1.2, + crid: 'crid1', + adm: { + link: {url: clickUrl}, + assets: [ + {id: 1, title: {text: titleText}}, + {id: 2, img: {w: imgW, h: imgH, url: imgUrl}}, + {id: 5, data: {value: brandText}} + ], + imptrackers: [impUrl] + } + }] + }] + } + }; - const noConsentCases = ['1YYY', '1YYN', '1YY-']; - noConsentCases.forEach((ccpaString, index) => { - it(`Opt-Out should indicate no consent (case ${index})`, function () { - const req = ccpaRequest(ccpaString); - expect(hasCCPAConsent(req)).to.be.false; - }); - }); + it('Should interpret response', () => { + let response = spec.interpretResponse(utils.deepClone(responseBody)) + let expectedResponse = { + clickUrl: clickUrl, + impressionTrackers: [impUrl], + privacyLink: 'https://info.evidon.com/pub_info/573', + privacyIcon: 'https://c.betrad.com/pub/icon1.png', + title: titleText, + image: {url: imgUrl, width: imgW, height: imgH}, + sponsoredBy: brandText, + clickTrackers: [], + jstracker: [] + } - const consentCases = [undefined, '1YNY', '1YN-', '1Y--', '1---']; - consentCases.forEach((ccpaString, index) => { - it(`should indicate consent (case ${index})`, function() { - const req = ccpaRequest(ccpaString); - expect(hasCCPAConsent(req)).to.be.true; - }) - }); + expect(response[0].native).to.be.deep.equal(expectedResponse) + }) - it('builds a request with no credentials', function () { - const noConsent = ccpaRequest('1YYY'); - expect(spec.buildRequests([validBid], noConsent)[0].options.withCredentials).to.be.false; - }); - }); + it('Should interpret all assets', () => { + let allAssetsResponse = utils.deepClone(responseBody) + let iconUrl = imgUrl + '?icon=true', iconW = 10, iconH = 15 + let logoUrl = imgUrl + '?logo=true', logoW = 20, logoH = 25 + let bodyText = 'Some body text' + + allAssetsResponse.body.seatbid[0].bid[0].adm.assets.push(...[ + {id: 3, img: {w: iconW, h: iconH, url: iconUrl}}, + {id: 4, img: {w: logoW, h: logoH, url: logoUrl}}, + {id: 6, data: {value: bodyText}} + ]) + + let response = spec.interpretResponse(allAssetsResponse) + let expectedResponse = { + clickUrl: clickUrl, + impressionTrackers: [impUrl], + jstracker: [], + clickTrackers: [], + privacyLink: 'https://info.evidon.com/pub_info/573', + privacyIcon: 'https://c.betrad.com/pub/icon1.png', + title: titleText, + image: {url: imgUrl, width: imgW, height: imgH}, + icon: {url: iconUrl, width: iconW, height: iconH}, + logo: {url: logoUrl, width: logoW, height: logoH}, + body: bodyText, + sponsoredBy: brandText + } + + expect(response[0].native).to.be.deep.equal(expectedResponse) + }) + }) }); diff --git a/test/spec/modules/nobidBidAdapter_spec.js b/test/spec/modules/nobidBidAdapter_spec.js index afbc46f862f..346356e7d5b 100644 --- a/test/spec/modules/nobidBidAdapter_spec.js +++ b/test/spec/modules/nobidBidAdapter_spec.js @@ -110,6 +110,95 @@ describe('Nobid Adapter', function () { refererInfo: {referer: REFERER} } + it('should add source and version to the tag', function () { + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.sid).to.equal(SITE_ID); + expect(payload.l).to.exist.and.to.equal(encodeURIComponent(REFERER)); + expect(payload.a).to.exist; + expect(payload.t).to.exist; + expect(payload.tz).to.exist; + expect(payload.r).to.exist.and.to.equal('100x100'); + expect(payload.lang).to.exist; + expect(payload.ref).to.exist; + expect(payload.a[0].d).to.exist.and.to.equal('adunit-code'); + expect(payload.a[0].at).to.exist.and.to.equal('video'); + expect(payload.a[0].params.video).to.exist; + expect(payload.a[0].params.video.skippable).to.exist.and.to.equal(true); + expect(payload.a[0].params.video.playback_methods).to.exist.and.to.contain('auto_play_sound_off'); + expect(payload.a[0].params.video.position).to.exist.and.to.equal('atf'); + expect(payload.a[0].params.video.mimes).to.exist.and.to.contain('video/x-flv'); + expect(payload.a[0].params.video.minduration).to.exist.and.to.equal(1); + expect(payload.a[0].params.video.maxduration).to.exist.and.to.equal(30); + expect(payload.a[0].params.video.frameworks[0]).to.exist.and.to.equal(1); + expect(payload.a[0].params.video.frameworks[1]).to.exist.and.to.equal(2); + expect(payload.a[0].params.video.frameworks[2]).to.exist.and.to.equal(3); + expect(payload.a[0].params.video.frameworks[3]).to.exist.and.to.equal(4); + expect(payload.a[0].params.video.frameworks[4]).to.exist.and.to.equal(5); + expect(payload.a[0].params.video.frameworks[5]).to.exist.and.to.equal(6); + }); + }); + + describe('isVideoBidRequestValid', function () { + let bid = { + bidder: 'nobid', + params: { + siteId: 2, + video: { + skippable: true, + playback_methods: ['auto_play_sound_off'], + position: 'atf', + mimes: ['video/x-flv', 'video/mp4', 'video/x-ms-wmv', 'application/x-shockwave-flash', 'application/javascript'], + minduration: 1, + maxduration: 30, + frameworks: [1, 2, 3, 4, 5, 6] + } + }, + adUnitCode: 'adunit-code', + sizes: [[640, 480]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + mediaTypes: { + video: { + context: 'outstream' + } + } + }; + const SITE_ID = 2; + const REFERER = 'https://www.examplereferer.com'; + let bidRequests = [ + { + bidder: 'nobid', + params: { + siteId: SITE_ID, + video: { + skippable: true, + playback_methods: ['auto_play_sound_off'], + position: 'atf', + mimes: ['video/x-flv', 'video/mp4', 'video/x-ms-wmv', 'application/x-shockwave-flash', 'application/javascript'], + minduration: 1, + maxduration: 30, + frameworks: [1, 2, 3, 4, 5, 6] + } + }, + adUnitCode: 'adunit-code', + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'outstream' + } + } + } + ]; + + let bidderRequest = { + refererInfo: {referer: REFERER} + } + it('should add source and version to the tag', function () { const request = spec.buildRequests(bidRequests, bidderRequest); const payload = JSON.parse(request.data); @@ -175,6 +264,38 @@ describe('Nobid Adapter', function () { expect(payload.gdpr).to.exist; }); + it('sends bid request to ad size', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.a).to.exist; + expect(payload.a.length).to.exist.and.to.equal(1); + expect(payload.a[0].z[0][0]).to.equal(300); + expect(payload.a[0].z[0][1]).to.equal(250); + }); + + it('sends bid request to div id', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.a).to.exist; + expect(payload.a[0].d).to.equal('adunit-code'); + }); + + it('sends bid request to site id', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.a).to.exist; + expect(payload.a[0].sid).to.equal(2); + expect(payload.a[0].at).to.equal('banner'); + expect(payload.a[0].params.siteId).to.equal(2); + }); + + it('sends bid request to ad type', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.a).to.exist; + expect(payload.a[0].at).to.equal('banner'); + }); + it('sends bid request to ENDPOINT via POST', function () { const request = spec.buildRequests(bidRequests); expect(request.url).to.contain('ads.servenobid.com/adreq'); @@ -202,6 +323,43 @@ describe('Nobid Adapter', function () { expect(payload.gdpr.consentString).to.exist.and.to.equal(consentString); expect(payload.gdpr.consentRequired).to.exist.and.to.be.true; }); + + it('should add gdpr consent information to the request', function () { + let bidderRequest = { + 'bidderCode': 'nobid', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gdprConsent': { + gdprApplies: false + } + }; + bidderRequest.bids = bidRequests; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.gdpr).to.exist; + expect(payload.gdpr.consentString).to.not.exist; + expect(payload.gdpr.consentRequired).to.exist.and.to.be.false; + }); + + it('should add usp consent information to the request', function () { + let bidderRequest = { + 'bidderCode': 'nobid', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'uspConsent': '1Y-N' + }; + bidderRequest.bids = bidRequests; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.usp).to.exist; + expect(payload.usp).to.exist.and.to.equal('1Y-N'); + }); }); describe('buildRequestsRefreshCount', function () { diff --git a/test/spec/modules/oneVideoBidAdapter_spec.js b/test/spec/modules/oneVideoBidAdapter_spec.js index 45d59683942..ae29bcd48ec 100644 --- a/test/spec/modules/oneVideoBidAdapter_spec.js +++ b/test/spec/modules/oneVideoBidAdapter_spec.js @@ -1,7 +1,6 @@ import { expect } from 'chai'; import { spec } from 'modules/oneVideoBidAdapter.js'; import * as utils from 'src/utils.js'; -import {config} from 'src/config.js'; describe('OneVideoBidAdapter', function () { let bidRequest; @@ -47,6 +46,7 @@ describe('OneVideoBidAdapter', function () { sid: 134, rewarded: 1, placement: 1, + hp: 1, inventoryid: 123 }, site: { @@ -181,6 +181,21 @@ describe('OneVideoBidAdapter', function () { } expect(spec.isBidRequestValid(bidRequest)).to.equal(false); }) + + it('should return true for Multi-Format AdUnits, when the mediaTypes are both "banner" and "video" (Multi-Format Support)', function () { + bidRequest = { + mediaTypes: { + banner: { + sizes: [640, 480] + }, + video: { + context: 'outstream', + playerSize: [640, 480] + } + } + } + expect(spec.isBidRequestValid(bidRequest)).to.equal(false); + }) }); describe('spec.buildRequests', function () { @@ -202,7 +217,7 @@ describe('OneVideoBidAdapter', function () { const placement = bidRequest.params.video.placement; const rewarded = bidRequest.params.video.rewarded; const inventoryid = bidRequest.params.video.inventoryid; - const VERSION = '3.0.2'; + const VERSION = '3.0.4'; expect(data.imp[0].video.w).to.equal(width); expect(data.imp[0].video.h).to.equal(height); expect(data.imp[0].bidfloor).to.equal(bidRequest.params.bidfloor); @@ -222,6 +237,84 @@ describe('OneVideoBidAdapter', function () { expect(data.imp[0].video.w).to.equal(width); expect(data.imp[0].video.h).to.equal(height); }); + + it('should set pubId to HBExchange when bid.params.video.e2etest = true', function () { + bidRequest.params.video.e2etest = true; + const requests = spec.buildRequests([ bidRequest ], bidderRequest); + expect(requests[0].method).to.equal('POST'); + expect(requests[0].url).to.equal(spec.E2ETESTENDPOINT + 'HBExchange'); + }); + + it('should attach End 2 End test data', function () { + bidRequest.params.video.e2etest = true; + const requests = spec.buildRequests([ bidRequest ], bidderRequest); + const data = requests[0].data; + expect(data.imp[0].bidfloor).to.not.exist; + expect(data.imp[0].video.w).to.equal(300); + expect(data.imp[0].video.h).to.equal(250); + expect(data.imp[0].video.mimes).to.eql(['video/mp4', 'application/javascript']); + expect(data.imp[0].video.api).to.eql([2]); + expect(data.site.page).to.equal('https://verizonmedia.com'); + expect(data.site.ref).to.equal('https://verizonmedia.com'); + expect(data.tmax).to.equal(1000); + }); + + it('it should create new schain and send it if video.params.sid exists', function () { + const requests = spec.buildRequests([ bidRequest ], bidderRequest); + const data = requests[0].data; + const schain = data.source.ext.schain; + expect(schain.nodes.length).to.equal(1); + expect(schain.nodes[0].sid).to.equal(bidRequest.params.video.sid); + expect(schain.nodes[0].rid).to.equal(data.id); + }) + + it('should send Global or Bidder specific schain if sid is not passed in video.params.sid', function () { + bidRequest.params.video.sid = null; + const globalSchain = { + ver: '1.0', + complete: 1, + nodes: [{ + asi: 'some-platform.com', + sid: '111111', + rid: bidRequest.id, + hp: 1 + }] + }; + bidRequest.schain = globalSchain; + const requests = spec.buildRequests([ bidRequest ], bidderRequest); + const data = requests[0].data; + const schain = data.source.ext.schain; + expect(schain.nodes.length).to.equal(1); + expect(schain).to.equal(globalSchain); + }); + + it('should ignore Global or Bidder specific schain if video.params.sid exists and send new schain', function () { + const globalSchain = { + ver: '1.0', + complete: 1, + nodes: [{ + asi: 'some-platform.com', + sid: '111111', + rid: bidRequest.id, + hp: 1 + }] + }; + bidRequest.schain = globalSchain; + const requests = spec.buildRequests([ bidRequest ], bidderRequest); + const data = requests[0].data; + const schain = data.source.ext.schain; + expect(schain.nodes.length).to.equal(1); + expect(schain.complete).to.equal(1); + expect(schain.nodes[0].sid).to.equal(bidRequest.params.video.sid); + expect(schain.nodes[0].rid).to.equal(data.id); + }) + + it('should append hp to new schain created by sid if video.params.hp is passed', function () { + const requests = spec.buildRequests([ bidRequest ], bidderRequest); + const data = requests[0].data; + const schain = data.source.ext.schain; + expect(schain.nodes[0].hp).to.equal(bidRequest.params.video.hp); + }) }); describe('spec.interpretResponse', function () { @@ -344,14 +437,8 @@ describe('OneVideoBidAdapter', function () { expect(request[0].data.regs.ext.gdpr).to.equal(1); expect(request[0].data.regs.ext.us_privacy).to.equal(bidderRequest.uspConsent); }); - - it('should send schain object', function () { - const requests = spec.buildRequests([ bidRequest ], bidderRequest); - const data = requests[0].data; - expect(data.source.ext.schain.nodes[0].sid).to.equal(bidRequest.params.video.sid); - expect(data.source.ext.schain.nodes[0].rid).to.equal(data.id); - }); }); + describe('should send banner object', function () { it('should send banner object when display is 1 and context="instream" (DAP O&O)', function () { bidRequest = { @@ -506,14 +593,25 @@ describe('OneVideoBidAdapter', function () { it('should get correct user sync when iframeEnabled', function () { let pixel = spec.getUserSyncs({pixelEnabled: true}, {}, {gdprApplies: true, consentString: GDPR_CONSENT_STRING}) - expect(pixel[2].type).to.equal('image'); - expect(pixel[2].url).to.equal('https://sync-tm.everesttech.net/upi/pid/m7y5t93k?gdpr=1&gdpr_consent=' + GDPR_CONSENT_STRING + '&redir=https%3A%2F%2Fpixel.advertising.com%2Fups%2F55986%2Fsync%3Fuid%3D%24%7BUSER_ID%7D%26_origin%3D0&gdpr=1&gdpr_consent=' + encodeURI(GDPR_CONSENT_STRING)); + expect(pixel[1].type).to.equal('image'); + expect(pixel[1].url).to.equal('https://sync-tm.everesttech.net/upi/pid/m7y5t93k?gdpr=1&gdpr_consent=' + GDPR_CONSENT_STRING + '&redir=https%3A%2F%2Fpixel.advertising.com%2Fups%2F55986%2Fsync%3Fuid%3D%24%7BUSER_ID%7D%26_origin%3D0&gdpr=1&gdpr_consent=' + encodeURI(GDPR_CONSENT_STRING)); }); it('should default to gdprApplies=0 when consentData is undefined', function () { let pixel = spec.getUserSyncs({pixelEnabled: true}, {}, undefined); - expect(pixel[2].url).to.equal('https://sync-tm.everesttech.net/upi/pid/m7y5t93k?gdpr=0&gdpr_consent=&redir=https%3A%2F%2Fpixel.advertising.com%2Fups%2F55986%2Fsync%3Fuid%3D%24%7BUSER_ID%7D%26_origin%3D0&gdpr=0&gdpr_consent='); + expect(pixel[1].url).to.equal('https://sync-tm.everesttech.net/upi/pid/m7y5t93k?gdpr=0&gdpr_consent=&redir=https%3A%2F%2Fpixel.advertising.com%2Fups%2F55986%2Fsync%3Fuid%3D%24%7BUSER_ID%7D%26_origin%3D0&gdpr=0&gdpr_consent='); }); }); + + describe('verify sync pixels', function () { + let pixel = spec.getUserSyncs({pixelEnabled: true}, {}, undefined); + it('should be UPS sync pixel for DBM', function () { + expect(pixel[0].url).to.equal('https://pixel.advertising.com/ups/57304/sync?gdpr=&gdpr_consent=&_origin=0&redir=true') + }); + + it('should be TTD sync pixel', function () { + expect(pixel[2].url).to.equal('https://match.adsrvr.org/track/cmf/generic?ttd_pid=adaptv&ttd_tpi=1') + }); + }) }); }); diff --git a/test/spec/modules/onetagBidAdapter_spec.js b/test/spec/modules/onetagBidAdapter_spec.js index 2b31c875502..c1462c3814d 100644 --- a/test/spec/modules/onetagBidAdapter_spec.js +++ b/test/spec/modules/onetagBidAdapter_spec.js @@ -1,6 +1,8 @@ import { spec, isValid, hasTypeVideo } from 'modules/onetagBidAdapter.js'; import { expect } from 'chai'; +import find from 'core-js-pure/features/array/find.js'; import { BANNER, VIDEO } from 'src/mediaTypes.js'; +import {INSTREAM, OUTSTREAM} from 'src/video.js'; describe('onetag', function () { function createBid() { @@ -26,7 +28,7 @@ describe('onetag', function () { return bid; } - function createVideoBid(bidRequest) { + function createInstreamVideoBid(bidRequest) { const bid = bidRequest || createBid(); bid.mediaTypes = bid.mediaTypes || {}; bid.mediaTypes.video = { @@ -37,7 +39,7 @@ describe('onetag', function () { return bid; } - function createWrongVideoOutstreamBid(bidRequest) { + function createOutstreamVideoBid(bidRequest) { const bid = bidRequest || createBid(); bid.mediaTypes = bid.mediaTypes || {}; bid.mediaTypes.video = { @@ -49,12 +51,12 @@ describe('onetag', function () { } function createMultiFormatBid() { - return createVideoBid(createBannerBid()); + return createInstreamVideoBid(createBannerBid()); } const bannerBid = createBannerBid(); - const videoBid = createVideoBid(); - const outstreamVideoBid = createWrongVideoOutstreamBid(); + const instreamVideoBid = createInstreamVideoBid(); + const outstreamVideoBid = createOutstreamVideoBid(); describe('isBidRequestValid', function () { it('Should return true when required params are found', function () { @@ -76,30 +78,30 @@ describe('onetag', function () { }); describe('video bidRequest', function () { it('Should return false when the context is undefined', function () { - videoBid.mediaTypes.video.context = undefined; - expect(spec.isBidRequestValid(videoBid)).to.be.false; + instreamVideoBid.mediaTypes.video.context = undefined; + expect(spec.isBidRequestValid(instreamVideoBid)).to.be.false; }); it('Should return false when the context is not instream or outstream', function () { - videoBid.mediaTypes.video.context = 'wrong'; - expect(spec.isBidRequestValid(videoBid)).to.be.false; + instreamVideoBid.mediaTypes.video.context = 'wrong'; + expect(spec.isBidRequestValid(instreamVideoBid)).to.be.false; }); it('Should return false when playerSize is undefined', function () { - const videoBid = createVideoBid(); + const videoBid = createInstreamVideoBid(); videoBid.mediaTypes.video.playerSize = undefined; expect(spec.isBidRequestValid(videoBid)).to.be.false; }); it('Should return false when playerSize is not an array', function () { - const videoBid = createVideoBid(); + const videoBid = createInstreamVideoBid(); videoBid.mediaTypes.video.playerSize = 30; expect(spec.isBidRequestValid(videoBid)).to.be.false; }); it('Should return false when playerSize is an empty array', function () { - const videoBid = createVideoBid(); + const videoBid = createInstreamVideoBid(); videoBid.mediaTypes.video.playerSize = []; expect(spec.isBidRequestValid(videoBid)).to.be.false; }); - it('Should return false when context is outstream but no renderer object is defined', function () { - expect(spec.isBidRequestValid(outstreamVideoBid)).to.be.false; + it('Should return true when context is outstream', function () { + expect(spec.isBidRequestValid(outstreamVideoBid)).to.be.true; }); }); describe('multi format bidRequest', function () { @@ -111,7 +113,7 @@ describe('onetag', function () { }); describe('buildRequests', function () { - let serverRequest = spec.buildRequests([bannerBid, videoBid]); + let serverRequest = spec.buildRequests([bannerBid, instreamVideoBid]); it('Creates a ServerRequest object with method, URL and data', function () { expect(serverRequest).to.exist; expect(serverRequest.method).to.exist; @@ -128,12 +130,12 @@ describe('onetag', function () { const d = serverRequest.data; try { const data = JSON.parse(d); - it('Should contains all keys', function () { + it('Should contain all keys', function () { expect(data).to.be.an('object'); - expect(data).to.have.all.keys('location', 'masked', 'referrer', 'sHeight', 'sWidth', 'timeOffset', 'date', 'wHeight', 'wWidth', 'oHeight', 'oWidth', 'aWidth', 'aHeight', 'sLeft', 'sTop', 'hLength', 'bids', 'docHidden', 'xOffset', 'yOffset'); + expect(data).to.include.all.keys('location', 'referrer', 'masked', 'sHeight', 'sWidth', 'docHeight', 'wHeight', 'wWidth', 'oHeight', 'oWidth', 'aWidth', 'aHeight', 'sLeft', 'sTop', 'hLength', 'bids', 'docHidden', 'xOffset', 'yOffset', 'timing', 'version'); expect(data.location).to.be.a('string'); - expect(data.masked).to.be.a('number'); - expect(data.referrer).to.be.a('string'); + expect(data.masked).to.be.oneOf([0, 1, 2]); + expect(data.referrer).to.satisfy(referrer => referrer === null || typeof referrer === 'string'); expect(data.sHeight).to.be.a('number'); expect(data.sWidth).to.be.a('number'); expect(data.wWidth).to.be.a('number'); @@ -145,10 +147,8 @@ describe('onetag', function () { expect(data.sLeft).to.be.a('number'); expect(data.sTop).to.be.a('number'); expect(data.hLength).to.be.a('number'); - expect(data.timeOffset).to.be.a('number'); - expect(data.date).to.be.a('string'); expect(data.bids).to.be.an('array'); - + expect(data.version).to.have.all.keys('prebid', 'adapter'); const bids = data['bids']; for (let i = 0; i < bids.length; i++) { const bid = bids[i]; @@ -190,7 +190,7 @@ describe('onetag', function () { expect(payload.gdprConsent.consentString).to.exist.and.to.equal(consentString); expect(payload.gdprConsent.consentRequired).to.exist.and.to.be.true; }); - it('should send us privacy string', function () { + it('Should send us privacy string', function () { let consentString = 'us_foo'; let bidderRequest = { 'bidderCode': 'onetag', @@ -207,70 +207,44 @@ describe('onetag', function () { }); }); describe('interpretResponse', function () { - function getBannerRes() { - return { - ad: '
Advertising
', - cpm: 13, - width: 300, - height: 250, - creativeId: '1820', - dealId: 'dishfo', - currency: 'USD', - requestId: 'sdiceobxcw', - mediaType: BANNER - } - } - function getVideoRes() { - return { - ad: '', - cpm: 13, - width: 300, - height: 250, - creativeId: '1820', - dealId: 'dishfo', - currency: 'USD', - requestId: 'sdiceobxcw', - mediaType: VIDEO - } - } - function getBannerAdnVideoRes() { - return { - body: { - nobid: false, - bids: [getBannerRes(), getVideoRes()] - } - }; - } - const responseObj = getBannerAdnVideoRes(); + const request = getBannerVideoRequest(); + const response = getBannerVideoResponse(); + const requestData = JSON.parse(request.data); it('Returns an array of valid server responses if response object is valid', function () { - const serverResponses = spec.interpretResponse(responseObj); - - expect(serverResponses).to.be.an('array').that.is.not.empty; - for (let i = 0; i < serverResponses.length; i++) { - let dataItem = serverResponses[i]; - if (dataItem.mediaType === VIDEO) { - expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'vastXml', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'dealId'); - } else if (dataItem.mediaType === BANNER) { - expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', 'netRevenue', 'currency', 'mediaType', 'dealId'); + const interpretedResponse = spec.interpretResponse(response, request); + expect(interpretedResponse).to.be.an('array').that.is.not.empty; + for (let i = 0; i < interpretedResponse.length; i++) { + let dataItem = interpretedResponse[i]; + expect(dataItem).to.include.all.keys('requestId', 'cpm', 'width', 'height', 'ttl', 'creativeId', 'netRevenue', 'currency', 'meta', 'dealId'); + if (dataItem.meta.mediaType === VIDEO) { + const {context} = find(requestData.bids, (item) => item.bidId === dataItem.requestId); + if (context === INSTREAM) { + expect(dataItem).to.include.all.keys('videoCacheKey', 'vastUrl'); + expect(dataItem.vastUrl).to.be.a('string'); + expect(dataItem.videoCacheKey).to.be.a('string'); + } else if (context === OUTSTREAM) { + expect(dataItem).to.include.all.keys('renderer', 'vastXml', 'vastUrl'); + expect(dataItem.renderer).to.be.an('object'); + expect(dataItem.vastUrl).to.be.a('string'); + expect(dataItem.vastXml).to.be.a('string'); + } + } else if (dataItem.meta.mediaType === BANNER) { + expect(dataItem).to.include.all.keys('ad'); + expect(dataItem.ad).to.be.a('string'); } expect(dataItem.requestId).to.be.a('string'); expect(dataItem.cpm).to.be.a('number'); expect(dataItem.width).to.be.a('number'); expect(dataItem.height).to.be.a('number'); - if (dataItem.mediaType === VIDEO) { - expect(dataItem.vastXml).to.be.a('string'); - } else if (dataItem.mediaType === BANNER) { - expect(dataItem.ad).to.be.a('string'); - } expect(dataItem.ttl).to.be.a('number'); expect(dataItem.creativeId).to.be.a('string'); expect(dataItem.netRevenue).to.be.a('boolean'); expect(dataItem.currency).to.be.a('string'); } - it('Returns an empty array if invalid response is passed', function () { - const serverResponses = spec.interpretResponse('invalid_response'); - expect(serverResponses).to.be.an('array').that.is.empty; - }); + }); + it('Returns an empty array if response is not valid', function () { + const serverResponses = spec.interpretResponse('invalid_response', { data: '{}' }); + expect(serverResponses).to.be.an('array').that.is.empty; }); }); describe('getUserSyncs', function () { @@ -333,3 +307,105 @@ describe('onetag', function () { }); }); }); + +function getBannerVideoResponse() { + return { + body: { + nobid: false, + bids: [ + { + ad: '
Advertising
', + cpm: 13, + width: 300, + height: 250, + creativeId: '1820', + dealId: 'dishfo', + currency: 'USD', + requestId: 'banner', + mediaType: BANNER, + }, + { + cpm: 13, + width: 300, + height: 250, + creativeId: '1820', + dealId: 'dishfo', + currency: 'USD', + requestId: 'videoInstream', + vastUrl: 'https://videoinstream.org', + videoCacheKey: 'key', + mediaType: VIDEO + }, + { + cpm: 13, + width: 300, + height: 250, + creativeId: '1820', + dealId: 'dishfo', + currency: 'USD', + vastUrl: 'https://videooutstream.org', + requestId: 'videoOutstream', + ad: '', + rendererUrl: 'https://testRenderer', + mediaType: VIDEO + } + ] + } + }; +} + +function getBannerVideoRequest() { + return { + data: JSON.stringify({ + bids: [ + { + adUnitCode: 'target-div', + bidId: 'videoOutstream', + bidderRequestId: '12bb1e0f9fb669', + auctionId: '80784b4d-79ad-49ef-a006-75d8888b7609', + transactionId: '5f132731-3091-49b2-8fab-0e9c917733bc', + pubId: '386276e072', + context: 'outstream', + mimes: [], + playerSize: [], + type: 'video' + }, + { + adUnitCode: 'target-div', + bidId: 'videoInstream', + bidderRequestId: '12bb1e0f9fb669', + auctionId: '80784b4d-79ad-49ef-a006-75d8888b7609', + transactionId: '5f132731-3091-49b2-8fab-0e9c917733bc', + pubId: '386276e072', + context: 'instream', + mimes: [], + playerSize: [], + type: 'video' + } + ], + location: 'https%3A%2F%2Flocal.onetag.net%3A9000%2Fv2%2Fprebid-video%2Fvideo.html%3Fpbjs_debug%3Dtrue', + referrer: '0', + masked: 0, + wWidth: 860, + wHeight: 949, + oWidth: 1853, + oHeight: 1053, + sWidth: 1920, + sHeight: 1080, + aWidth: 1920, + aHeight: 1053, + sLeft: 1987, + sTop: 27, + xOffset: 0, + yOffset: 0, + docHidden: false, + hLength: 2, + timing: { + pageLoadTime: -1593433770022, + connectTime: 42, + renderTime: -1593433770092 + }, + onetagSid: 'user_id' + }) + } +} diff --git a/test/spec/modules/onomagicBidAdapter_spec.js b/test/spec/modules/onomagicBidAdapter_spec.js new file mode 100644 index 00000000000..7c71c3e5764 --- /dev/null +++ b/test/spec/modules/onomagicBidAdapter_spec.js @@ -0,0 +1,285 @@ +import { expect } from 'chai'; +import * as utils from 'src/utils.js'; +import { spec } from 'modules/onomagicBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; + +const URL = 'https://bidder.onomagic.com/hb'; + +describe('onomagicBidAdapter', function() { + const adapter = newBidder(spec); + let element, win; + let bidRequests; + let sandbox; + + beforeEach(function() { + element = { + x: 0, + y: 0, + + width: 0, + height: 0, + + getBoundingClientRect: () => { + return { + width: element.width, + height: element.height, + + left: element.x, + top: element.y, + right: element.x + element.width, + bottom: element.y + element.height + }; + } + }; + win = { + document: { + visibilityState: 'visible' + }, + + innerWidth: 800, + innerHeight: 600 + }; + bidRequests = [{ + 'bidder': 'onomagic', + 'params': { + 'publisherId': 1234567 + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, + 'bidId': '5fb26ac22bde4', + 'bidderRequestId': '4bf93aeb730cb9', + 'auctionId': 'ffe9a1f7-7b67-4bda-a8e0-9ee5dc9f442e' + }]; + + sandbox = sinon.sandbox.create(); + sandbox.stub(document, 'getElementById').withArgs('adunit-code').returns(element); + sandbox.stub(utils, 'getWindowTop').returns(win); + sandbox.stub(utils, 'getWindowSelf').returns(win); + }); + + afterEach(function() { + sandbox.restore(); + }); + + describe('isBidRequestValid', function () { + let bid = { + 'bidder': 'onomagic', + 'params': { + 'publisherId': 1234567 + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, + 'bidId': '5fb26ac22bde4', + 'bidderRequestId': '4bf93aeb730cb9', + 'auctionId': 'ffe9a1f7-7b67-4bda-a8e0-9ee5dc9f442e', + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when publisherId not passed correctly', function () { + bid.params.publisherId = undefined; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when require params are not passed', function () { + let bid = Object.assign({}, bid); + bid.params = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + it('sends bid request to our endpoint via POST', function () { + const request = spec.buildRequests(bidRequests); + expect(request.method).to.equal('POST'); + }); + + it('request url should match our endpoint url', function () { + const request = spec.buildRequests(bidRequests); + expect(request.url).to.equal(URL); + }); + + it('sets the proper banner object', function() { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}, {w: 300, h: 600}]); + }); + + it('accepts a single array as a size', function() { + bidRequests[0].mediaTypes.banner.sizes = [300, 250]; + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}]); + }); + + it('sends bidfloor param if present', function () { + bidRequests[0].params.bidFloor = 0.05; + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].bidfloor).to.equal(0.05); + }); + + it('sends tagid', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].tagid).to.equal('adunit-code'); + }); + + it('sends publisher id', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.site.publisher.id).to.equal(1234567); + }); + + context('when element is fully in view', function() { + it('returns 100', function() { + Object.assign(element, { width: 600, height: 400 }); + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal(100); + }); + }); + + context('when element is out of view', function() { + it('returns 0', function() { + Object.assign(element, { x: -300, y: 0, width: 207, height: 320 }); + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal(0); + }); + }); + + context('when element is partially in view', function() { + it('returns percentage', function() { + Object.assign(element, { width: 800, height: 800 }); + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal(75); + }); + }); + + context('when width or height of the element is zero', function() { + it('try to use alternative values', function() { + Object.assign(element, { width: 0, height: 0 }); + bidRequests[0].mediaTypes.banner.sizes = [[800, 2400]]; + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal(25); + }); + }); + + context('when nested iframes', function() { + it('returns \'na\'', function() { + Object.assign(element, { width: 600, height: 400 }); + + utils.getWindowTop.restore(); + utils.getWindowSelf.restore(); + sandbox.stub(utils, 'getWindowTop').returns(win); + sandbox.stub(utils, 'getWindowSelf').returns({}); + + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal('na'); + }); + }); + + context('when tab is inactive', function() { + it('returns 0', function() { + Object.assign(element, { width: 600, height: 400 }); + + utils.getWindowTop.restore(); + win.document.visibilityState = 'hidden'; + sandbox.stub(utils, 'getWindowTop').returns(win); + + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.imp[0].banner.ext.viewability).to.equal(0); + }); + }); + }); + + describe('interpretResponse', function () { + let response; + beforeEach(function () { + response = { + body: { + 'id': '37386aade21a71', + 'seatbid': [{ + 'bid': [{ + 'id': '376874781', + 'impid': '283a9f4cd2415d', + 'price': 0.35743275, + 'nurl': '', + 'adm': '', + 'w': 300, + 'h': 250 + }] + }] + } + }; + }); + + it('should get the correct bid response', function () { + let expectedResponse = [{ + 'requestId': '283a9f4cd2415d', + 'cpm': 0.35743275, + 'width': 300, + 'height': 250, + 'creativeId': '376874781', + 'currency': 'USD', + 'netRevenue': true, + 'mediaType': 'banner', + 'ad': `
`, + 'ttl': 60 + }]; + + let result = spec.interpretResponse(response); + expect(result[0]).to.deep.equal(expectedResponse[0]); + }); + + it('crid should default to the bid id if not on the response', function () { + let expectedResponse = [{ + 'requestId': '283a9f4cd2415d', + 'cpm': 0.35743275, + 'width': 300, + 'height': 250, + 'creativeId': response.body.seatbid[0].bid[0].id, + 'currency': 'USD', + 'netRevenue': true, + 'mediaType': 'banner', + 'ad': `
`, + 'ttl': 60 + }]; + + let result = spec.interpretResponse(response); + expect(result[0]).to.deep.equal(expectedResponse[0]); + }); + + it('handles empty bid response', function () { + let response = { + body: '' + }; + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); + }); + }); + + describe('getUserSyncs ', () => { + let syncOptions = {iframeEnabled: true, pixelEnabled: true}; + + it('should not return', () => { + let returnStatement = spec.getUserSyncs(syncOptions, []); + expect(returnStatement).to.be.empty; + }); + }); +}); diff --git a/test/spec/modules/openxAnalyticsAdapter_spec.js b/test/spec/modules/openxAnalyticsAdapter_spec.js index 805435abf80..b946efe922d 100644 --- a/test/spec/modules/openxAnalyticsAdapter_spec.js +++ b/test/spec/modules/openxAnalyticsAdapter_spec.js @@ -1,114 +1,192 @@ import { expect } from 'chai'; -import openxAdapter from 'modules/openxAnalyticsAdapter.js'; -import { config } from 'src/config.js'; +import openxAdapter, {AUCTION_STATES} from 'modules/openxAnalyticsAdapter.js'; import events from 'src/events.js'; import CONSTANTS from 'src/constants.json'; import * as utils from 'src/utils.js'; import { server } from 'test/mocks/xhr.js'; +import find from 'core-js-pure/features/array/find.js'; const { - EVENTS: { AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, BID_TIMEOUT, BID_WON } + EVENTS: { AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, BID_TIMEOUT, BID_WON, AUCTION_END } } = CONSTANTS; - const SLOT_LOADED = 'slotOnload'; +const CURRENT_TIME = 1586000000000; describe('openx analytics adapter', function() { - it('should require publisher id', function() { - sinon.spy(utils, 'logError'); + describe('when validating the configuration', function () { + let spy; + beforeEach(function () { + spy = sinon.spy(utils, 'logError'); + }); + + afterEach(function() { + utils.logError.restore(); + }); + + it('should require organization id when no configuration is passed', function() { + openxAdapter.enableAnalytics(); + expect(spy.firstCall.args[0]).to.match(/publisherPlatformId/); + expect(spy.firstCall.args[0]).to.match(/to exist/); + }); - openxAdapter.enableAnalytics(); - expect( - utils.logError.calledWith( - 'OpenX analytics adapter: publisherId is required.' - ) - ).to.be.true; + it('should require publisher id when no orgId is passed', function() { + openxAdapter.enableAnalytics({ + provider: 'openx', + options: { + publisherAccountId: 12345 + } + }); + expect(spy.firstCall.args[0]).to.match(/publisherPlatformId/); + expect(spy.firstCall.args[0]).to.match(/to exist/); + }); - utils.logError.restore(); + it('should validate types', function() { + openxAdapter.enableAnalytics({ + provider: 'openx', + options: { + orgId: 'test platformId', + sampling: 'invalid-float' + } + }); + + expect(spy.firstCall.args[0]).to.match(/sampling/); + expect(spy.firstCall.args[0]).to.match(/type 'number'/); + }); }); - describe('sending analytics event', function() { - const auctionInit = { auctionId: 'add5eb0f-587d-441d-86ec-bbb722c70f79' }; + describe('when tracking analytic events', function () { + const AD_UNIT_CODE = 'test-div-1'; + const SLOT_LOAD_WAIT_TIME = 10; + + const DEFAULT_V2_ANALYTICS_CONFIG = { + orgId: 'test-org-id', + publisherAccountId: 123, + publisherPlatformId: 'test-platform-id', + sample: 1.0, + enableV2: true, + payloadWaitTime: SLOT_LOAD_WAIT_TIME, + payloadWaitTimePadding: SLOT_LOAD_WAIT_TIME + }; + + const auctionInit = { + auctionId: 'test-auction-id', + timestamp: CURRENT_TIME, + timeout: 3000, + adUnitCodes: [AD_UNIT_CODE], + }; const bidRequestedOpenX = { - auctionId: 'add5eb0f-587d-441d-86ec-bbb722c70f79', - auctionStart: 1540944528017, + auctionId: 'test-auction-id', + auctionStart: CURRENT_TIME, + timeout: 2000, bids: [ { - adUnitCode: 'div-1', - bidId: '2f0c647b904e25', + adUnitCode: AD_UNIT_CODE, + bidId: 'test-openx-request-id', bidder: 'openx', - params: { unit: '540249866' }, - transactionId: 'ac66c3e6-3118-4213-a3ae-8cdbe4f72873' + params: { unit: 'test-openx-ad-unit-id' }, + userId: { + tdid: 'test-tradedesk-id', + empty_id: '', + null_id: null, + bla_id: '', + digitrustid: { data: { id: '1' } }, + lipbid: { lipb: '2' } + } } ], - start: 1540944528021 + start: CURRENT_TIME + 10 }; const bidRequestedCloseX = { - auctionId: 'add5eb0f-587d-441d-86ec-bbb722c70f79', - auctionStart: 1540944528017, + auctionId: 'test-auction-id', + auctionStart: CURRENT_TIME, + timeout: 1000, bids: [ { - adUnitCode: 'div-1', - bidId: '43d454020e9409', + adUnitCode: AD_UNIT_CODE, + bidId: 'test-closex-request-id', bidder: 'closex', - params: { unit: '513144370' }, - transactionId: 'ac66c3e6-3118-4213-a3ae-8cdbe4f72873' + params: { unit: 'test-closex-ad-unit-id' }, + userId: { + bla_id: '2', + tdid: 'test-tradedesk-id' + } } ], - start: 1540944528026 + start: CURRENT_TIME + 20 }; const bidResponseOpenX = { - requestId: '2f0c647b904e25', - adId: '33dddbb61d359a', - adUnitCode: 'div-1', - auctionId: 'add5eb0f-587d-441d-86ec-bbb722c70f79', + adUnitCode: AD_UNIT_CODE, cpm: 0.5, + netRevenue: true, + requestId: 'test-openx-request-id', + mediaType: 'banner', + width: 300, + height: 250, + adId: 'test-openx-ad-id', + auctionId: 'test-auction-id', creativeId: 'openx-crid', - responseTimestamp: 1540944528184, - ts: '2DAABBgABAAECAAIBAAsAAgAAAJccGApKSGt6NUZxRXYyHBbinsLj' + currency: 'USD', + timeToRespond: 100, + responseTimestamp: CURRENT_TIME + 30, + ts: 'test-openx-ts' }; const bidResponseCloseX = { - requestId: '43d454020e9409', - adId: '43dddbb61d359a', - adUnitCode: 'div-1', - auctionId: 'add5eb0f-587d-441d-86ec-bbb722c70f79', + adUnitCode: AD_UNIT_CODE, cpm: 0.3, + netRevenue: true, + requestId: 'test-closex-request-id', + mediaType: 'video', + width: 300, + height: 250, + adId: 'test-closex-ad-id', + auctionId: 'test-auction-id', creativeId: 'closex-crid', - responseTimestamp: 1540944528196, - ts: 'hu1QWo6iD3MHs6NG_AQAcFtyNqsj9y4S0YRbX7Kb06IrGns0BABb' + currency: 'USD', + timeToRespond: 200, + dealId: 'test-closex-deal-id', + responseTimestamp: CURRENT_TIME + 40, + ts: 'test-closex-ts' }; const bidTimeoutOpenX = { 0: { - adUnitCode: 'div-1', - auctionId: 'add5eb0f-587d-441d-86ec-bbb722c70f79', - bidId: '2f0c647b904e25' - } - }; + adUnitCode: AD_UNIT_CODE, + auctionId: 'test-auction-id', + bidId: 'test-openx-request-id' + }}; const bidTimeoutCloseX = { 0: { - adUnitCode: 'div-1', - auctionId: 'add5eb0f-587d-441d-86ec-bbb722c70f79', - bidId: '43d454020e9409' + adUnitCode: AD_UNIT_CODE, + auctionId: 'test-auction-id', + bidId: 'test-closex-request-id' } }; const bidWonOpenX = { - requestId: '2f0c647b904e25', - adId: '33dddbb61d359a', - adUnitCode: 'div-1', - auctionId: 'add5eb0f-587d-441d-86ec-bbb722c70f79' + requestId: 'test-openx-request-id', + adId: 'test-openx-ad-id', + adUnitCode: AD_UNIT_CODE, + auctionId: 'test-auction-id' + }; + + const auctionEnd = { + auctionId: 'test-auction-id', + timestamp: CURRENT_TIME, + auctionEnd: CURRENT_TIME + 100, + timeout: 3000, + adUnitCodes: [AD_UNIT_CODE], }; const bidWonCloseX = { - requestId: '43d454020e9409', - adId: '43dddbb61d359a', - adUnitCode: 'div-1', - auctionId: 'add5eb0f-587d-441d-86ec-bbb722c70f79' + requestId: 'test-closex-request-id', + adId: 'test-closex-ad-id', + adUnitCode: AD_UNIT_CODE, + auctionId: 'test-auction-id' }; function simulateAuction(events) { @@ -116,328 +194,446 @@ describe('openx analytics adapter', function() { events.forEach(event => { const [eventType, args] = event; - openxAdapter.track({ eventType, args }); if (eventType === BID_RESPONSE) { highestBid = highestBid || args; if (highestBid.cpm < args.cpm) { highestBid = args; } } - }); - openxAdapter.track({ - eventType: SLOT_LOADED, - args: { - slot: { - getAdUnitPath: () => { - return '/90577858/test_ad_unit'; - }, - getTargetingKeys: () => { - return []; - }, - getTargeting: sinon - .stub() - .withArgs('hb_adid') - .returns(highestBid ? [highestBid.adId] : []) - } + if (eventType === SLOT_LOADED) { + const slotLoaded = { + slot: { + getAdUnitPath: () => { + return '/12345678/test_ad_unit'; + }, + getSlotElementId: () => { + return AD_UNIT_CODE; + }, + getTargeting: (key) => { + if (key === 'hb_adid') { + return highestBid ? [highestBid.adId] : []; + } else { + return []; + } + } + } + }; + openxAdapter.track({ eventType, args: slotLoaded }); + } else { + openxAdapter.track({ eventType, args }); } }); } - function getQueryData(url) { - const queryArgs = url.split('?')[1].split('&'); - return queryArgs.reduce((data, arg) => { - const [key, val] = arg.split('='); - data[key] = val; - return data; - }, {}); - } + let clock; - before(function() { + beforeEach(function() { sinon.stub(events, 'getEvents').returns([]); - openxAdapter.enableAnalytics({ - options: { - publisherId: 'test123' - } - }); + clock = sinon.useFakeTimers(CURRENT_TIME); }); - after(function() { + afterEach(function() { events.getEvents.restore(); - openxAdapter.disableAnalytics(); + clock.restore(); }); - beforeEach(function() { - openxAdapter.reset(); - }); + describe('when there is an auction', function () { + let auction; + let auction2; + beforeEach(function () { + openxAdapter.enableAnalytics({options: DEFAULT_V2_ANALYTICS_CONFIG}); - afterEach(function() {}); + simulateAuction([ + [AUCTION_INIT, auctionInit], + [SLOT_LOADED] + ]); - it('should not send request if no bid response', function() { - simulateAuction([ - [AUCTION_INIT, auctionInit], - [BID_REQUESTED, bidRequestedOpenX] - ]); + simulateAuction([ + [AUCTION_INIT, {...auctionInit, auctionId: 'second-auction-id'}], + [SLOT_LOADED] + ]); - expect(server.requests.length).to.equal(0); - }); + clock.tick(SLOT_LOAD_WAIT_TIME); + auction = JSON.parse(server.requests[0].requestBody)[0]; + auction2 = JSON.parse(server.requests[1].requestBody)[0]; + }); + + afterEach(function () { + openxAdapter.reset(); + openxAdapter.disableAnalytics(); + }); + + it('should track auction start time', function () { + expect(auction.startTime).to.equal(auctionInit.timestamp); + }); + + it('should track auction time limit', function () { + expect(auction.timeLimit).to.equal(auctionInit.timeout); + }); + + it('should track the \'default\' test code', function () { + expect(auction.testCode).to.equal('default'); + }); - it('should send 1 request to the right endpoint', function() { - simulateAuction([ - [AUCTION_INIT, auctionInit], - [BID_REQUESTED, bidRequestedOpenX], - [BID_RESPONSE, bidResponseOpenX] - ]); + it('should track auction count', function () { + expect(auction.auctionOrder).to.equal(1); + expect(auction2.auctionOrder).to.equal(2); + }); - expect(server.requests.length).to.equal(1); + it('should track the orgId', function () { + expect(auction.orgId).to.equal(DEFAULT_V2_ANALYTICS_CONFIG.orgId); + }); - const endpoint = server.requests[0].url.split('?')[0]; - // note IE11 returns the default secure port, so we look for this alternate value as well in these tests - expect(endpoint).to.be.oneOf(['https://ads.openx.net/w/1.0/pban', 'https://ads.openx.net:443/w/1.0/pban']); + it('should track the orgId', function () { + expect(auction.publisherPlatformId).to.equal(DEFAULT_V2_ANALYTICS_CONFIG.publisherPlatformId); + }); + + it('should track the orgId', function () { + expect(auction.publisherAccountId).to.equal(DEFAULT_V2_ANALYTICS_CONFIG.publisherAccountId); + }); }); - describe('hb.ct, hb.rid, dddid, hb.asiid, hb.pubid', function() { - it('should always be in the query string', function() { + describe('when there is a custom test code', function () { + let auction; + beforeEach(function () { + openxAdapter.enableAnalytics({ + options: { + ...DEFAULT_V2_ANALYTICS_CONFIG, + testCode: 'test-code' + } + }); + simulateAuction([ [AUCTION_INIT, auctionInit], - [BID_REQUESTED, bidRequestedOpenX], - [BID_RESPONSE, bidResponseOpenX] + [SLOT_LOADED], ]); + clock.tick(SLOT_LOAD_WAIT_TIME); + auction = JSON.parse(server.requests[0].requestBody)[0]; + }); - const queryData = getQueryData(server.requests[0].url); - expect(queryData).to.include({ - 'hb.ct': String(bidRequestedOpenX.auctionStart), - 'hb.rid': auctionInit.auctionId, - dddid: bidRequestedOpenX.bids[0].transactionId, - 'hb.asiid': '/90577858/test_ad_unit', - 'hb.pubid': 'test123' - }); + afterEach(function () { + openxAdapter.reset(); + openxAdapter.disableAnalytics(); + }); + + it('should track the custom test code', function () { + expect(auction.testCode).to.equal('test-code'); }); }); - describe('hb.cur', function() { - it('should be in the query string if currency is set', function() { - sinon - .stub(config, 'getConfig') - .withArgs('currency.adServerCurrency') - .returns('bitcoin'); + describe('when there is campaign (utm) data', function () { + let auction; + beforeEach(function () { + + }); + + afterEach(function () { + openxAdapter.reset(); + utils.getWindowLocation.restore(); + openxAdapter.disableAnalytics(); + }); + + it('should track values from query params when they exist', function () { + sinon.stub(utils, 'getWindowLocation').returns({search: '?' + + 'utm_campaign=test%20campaign-name&' + + 'utm_source=test-source&' + + 'utm_medium=test-medium&' + }); + + openxAdapter.enableAnalytics({options: DEFAULT_V2_ANALYTICS_CONFIG}); simulateAuction([ [AUCTION_INIT, auctionInit], - [BID_REQUESTED, bidRequestedOpenX], - [BID_RESPONSE, bidResponseOpenX] + [SLOT_LOADED], ]); + clock.tick(SLOT_LOAD_WAIT_TIME); + auction = JSON.parse(server.requests[0].requestBody)[0]; + + // ensure that value are URI decoded + expect(auction.campaign.name).to.equal('test campaign-name'); + expect(auction.campaign.source).to.equal('test-source'); + expect(auction.campaign.medium).to.equal('test-medium'); + expect(auction.campaign.content).to.be.undefined; + expect(auction.campaign.term).to.be.undefined; + }); - config.getConfig.restore(); + it('should override query params if configuration parameters exist', function () { + sinon.stub(utils, 'getWindowLocation').returns({search: '?' + + 'utm_campaign=test-campaign-name&' + + 'utm_source=test-source&' + + 'utm_medium=test-medium&' + + 'utm_content=test-content&' + + 'utm_term=test-term' + }); - const queryData = getQueryData(server.requests[0].url); - expect(queryData).to.include({ - 'hb.cur': 'bitcoin' + openxAdapter.enableAnalytics({ + options: { + ...DEFAULT_V2_ANALYTICS_CONFIG, + campaign: { + name: 'test-config-name', + source: 'test-config-source', + medium: 'test-config-medium' + } + } }); - }); - it('should not be in the query string if currency is not set', function() { simulateAuction([ [AUCTION_INIT, auctionInit], - [BID_REQUESTED, bidRequestedOpenX], - [BID_RESPONSE, bidResponseOpenX] + [SLOT_LOADED], ]); - - const queryData = getQueryData(server.requests[0].url); - expect(queryData).to.not.have.key('hb.cur'); + clock.tick(SLOT_LOAD_WAIT_TIME); + auction = JSON.parse(server.requests[0].requestBody)[0]; + + expect(auction.campaign.name).to.equal('test-config-name'); + expect(auction.campaign.source).to.equal('test-config-source'); + expect(auction.campaign.medium).to.equal('test-config-medium'); + expect(auction.campaign.content).to.equal('test-content'); + expect(auction.campaign.term).to.equal('test-term'); }); }); - describe('hb.dcl, hb.dl, hb.tta, hb.ttr', function() { - it('should be in the query string if browser supports performance API', function() { - const timing = { - fetchStart: 1540944528000, - domContentLoadedEventEnd: 1540944528010, - loadEventEnd: 1540944528110 - }; - const originalPerf = window.top.performance; - window.top.performance = { timing }; + describe('when there are bid requests', function () { + let auction; + let openxBidder; + let closexBidder; - const renderTime = 1540944528100; - sinon.stub(Date, 'now').returns(renderTime); + beforeEach(function () { + openxAdapter.enableAnalytics({options: DEFAULT_V2_ANALYTICS_CONFIG}); simulateAuction([ [AUCTION_INIT, auctionInit], + [BID_REQUESTED, bidRequestedCloseX], [BID_REQUESTED, bidRequestedOpenX], - [BID_RESPONSE, bidResponseOpenX] + [SLOT_LOADED], ]); + clock.tick(SLOT_LOAD_WAIT_TIME * 2); + auction = JSON.parse(server.requests[0].requestBody)[0]; + openxBidder = find(auction.adUnits[0].bidRequests, bidderRequest => bidderRequest.bidder === 'openx'); + closexBidder = find(auction.adUnits[0].bidRequests, bidderRequest => bidderRequest.bidder === 'closex'); + }); - window.top.performance = originalPerf; - Date.now.restore(); + afterEach(function () { + openxAdapter.reset(); + openxAdapter.disableAnalytics(); + }); - const queryData = getQueryData(server.requests[0].url); - expect(queryData).to.include({ - 'hb.dcl': String(timing.domContentLoadedEventEnd - timing.fetchStart), - 'hb.dl': String(timing.loadEventEnd - timing.fetchStart), - 'hb.tta': String(bidRequestedOpenX.auctionStart - timing.fetchStart), - 'hb.ttr': String(renderTime - timing.fetchStart) - }); + it('should track the bidder', function () { + expect(openxBidder.bidder).to.equal('openx'); + expect(closexBidder.bidder).to.equal('closex'); + }); + + it('should track the adunit code', function () { + expect(auction.adUnits[0].code).to.equal(AD_UNIT_CODE); + }); + + it('should track the user ids', function () { + expect(auction.userIdProviders).to.deep.equal(['bla_id', 'digitrustid', 'lipbid', 'tdid']); }); - it('should not be in the query string if browser does not support performance API', function() { - const originalPerf = window.top.performance; - window.top.performance = undefined; + it('should not have responded', function () { + expect(openxBidder.hasBidderResponded).to.equal(false); + expect(closexBidder.hasBidderResponded).to.equal(false); + }); + }); + + describe('when there are request timeouts', function () { + let auction; + let openxBidRequest; + let closexBidRequest; + + beforeEach(function () { + openxAdapter.enableAnalytics({options: DEFAULT_V2_ANALYTICS_CONFIG}); simulateAuction([ [AUCTION_INIT, auctionInit], + [BID_REQUESTED, bidRequestedCloseX], [BID_REQUESTED, bidRequestedOpenX], - [BID_RESPONSE, bidResponseOpenX] + [BID_TIMEOUT, bidTimeoutCloseX], + [BID_TIMEOUT, bidTimeoutOpenX], + [AUCTION_END, auctionEnd] ]); + clock.tick(SLOT_LOAD_WAIT_TIME * 2); + auction = JSON.parse(server.requests[0].requestBody)[0]; - window.top.performance = originalPerf; + openxBidRequest = find(auction.adUnits[0].bidRequests, bidderRequest => bidderRequest.bidder === 'openx'); + closexBidRequest = find(auction.adUnits[0].bidRequests, bidderRequest => bidderRequest.bidder === 'closex'); + }); + + afterEach(function () { + openxAdapter.reset(); + openxAdapter.disableAnalytics(); + }); + + it('should track the timeout', function () { + expect(openxBidRequest.timedOut).to.equal(true); + expect(closexBidRequest.timedOut).to.equal(true); + }); - const queryData = getQueryData(server.requests[0].url); - expect(queryData).to.not.have.keys( - 'hb.dcl', - 'hb.dl', - 'hb.tta', - 'hb.ttr' - ); + it('should track the timeout value ie timeLimit', function () { + expect(openxBidRequest.timeLimit).to.equal(2000); + expect(closexBidRequest.timeLimit).to.equal(1000); }); }); - describe('ts, auid', function() { - it('OpenX is in auction and has a bid response', function() { + describe('when there are bid responses', function () { + let auction; + let openxBidResponse; + let closexBidResponse; + + beforeEach(function () { + openxAdapter.enableAnalytics({options: DEFAULT_V2_ANALYTICS_CONFIG}); + simulateAuction([ [AUCTION_INIT, auctionInit], - [BID_REQUESTED, bidRequestedOpenX], [BID_REQUESTED, bidRequestedCloseX], + [BID_REQUESTED, bidRequestedOpenX], [BID_RESPONSE, bidResponseOpenX], - [BID_RESPONSE, bidResponseCloseX] + [BID_RESPONSE, bidResponseCloseX], + [AUCTION_END, auctionEnd] ]); - const queryData = getQueryData(server.requests[0].url); - expect(queryData).to.include({ - ts: bidResponseOpenX.ts, - auid: bidRequestedOpenX.bids[0].params.unit - }); + clock.tick(SLOT_LOAD_WAIT_TIME * 2); + auction = JSON.parse(server.requests[0].requestBody)[0]; + + openxBidResponse = find(auction.adUnits[0].bidRequests, bidderRequest => bidderRequest.bidder === 'openx').bidResponses[0]; + closexBidResponse = find(auction.adUnits[0].bidRequests, bidderRequest => bidderRequest.bidder === 'closex').bidResponses[0]; }); - it('OpenX is in auction but no bid response', function() { - simulateAuction([ - [AUCTION_INIT, auctionInit], - [BID_REQUESTED, bidRequestedOpenX], - [BID_REQUESTED, bidRequestedCloseX], - [BID_RESPONSE, bidResponseCloseX] - ]); + afterEach(function () { + openxAdapter.reset(); + openxAdapter.disableAnalytics(); + }); - const queryData = getQueryData(server.requests[0].url); - expect(queryData).to.include({ - auid: bidRequestedOpenX.bids[0].params.unit - }); - expect(queryData).to.not.have.key('ts'); + it('should track the cpm in microCPM', function () { + expect(openxBidResponse.microCpm).to.equal(bidResponseOpenX.cpm * 1000000); + expect(closexBidResponse.microCpm).to.equal(bidResponseCloseX.cpm * 1000000); }); - it('OpenX is not in auction', function() { - simulateAuction([ - [AUCTION_INIT, auctionInit], - [BID_REQUESTED, bidRequestedCloseX], - [BID_RESPONSE, bidResponseCloseX] - ]); + it('should track if the bid is in net revenue', function () { + expect(openxBidResponse.netRevenue).to.equal(bidResponseOpenX.netRevenue); + expect(closexBidResponse.netRevenue).to.equal(bidResponseCloseX.netRevenue); + }); + + it('should track the mediaType', function () { + expect(openxBidResponse.mediaType).to.equal(bidResponseOpenX.mediaType); + expect(closexBidResponse.mediaType).to.equal(bidResponseCloseX.mediaType); + }); + + it('should track the currency', function () { + expect(openxBidResponse.currency).to.equal(bidResponseOpenX.currency); + expect(closexBidResponse.currency).to.equal(bidResponseCloseX.currency); + }); + + it('should track the ad width and height', function () { + expect(openxBidResponse.width).to.equal(bidResponseOpenX.width); + expect(openxBidResponse.height).to.equal(bidResponseOpenX.height); + + expect(closexBidResponse.width).to.equal(bidResponseCloseX.width); + expect(closexBidResponse.height).to.equal(bidResponseCloseX.height); + }); + + it('should track the bid dealId', function () { + expect(openxBidResponse.dealId).to.equal(bidResponseOpenX.dealId); // no deal id defined + expect(closexBidResponse.dealId).to.equal(bidResponseCloseX.dealId); // deal id defined + }); + + it('should track the bid\'s latency', function () { + expect(openxBidResponse.latency).to.equal(bidResponseOpenX.timeToRespond); + expect(closexBidResponse.latency).to.equal(bidResponseCloseX.timeToRespond); + }); + + it('should not have any bid winners', function () { + expect(openxBidResponse.winner).to.equal(false); + expect(closexBidResponse.winner).to.equal(false); + }); + + it('should track the bid currency', function () { + expect(openxBidResponse.currency).to.equal(bidResponseOpenX.currency); + expect(closexBidResponse.currency).to.equal(bidResponseCloseX.currency); + }); + + it('should track the auction end time', function () { + expect(auction.endTime).to.equal(auctionEnd.auctionEnd); + }); - const queryData = getQueryData(server.requests[0].url); - expect(queryData).to.not.have.keys('auid', 'ts'); + it('should track that the auction ended', function () { + expect(auction.state).to.equal(AUCTION_STATES.ENDED); }); }); - describe('hb.exn, hb.sts, hb.ets, hb.bv, hb.crid, hb.to', function() { - it('2 bidders in auction', function() { + describe('when there are bidder wins', function () { + let auction; + beforeEach(function () { + openxAdapter.enableAnalytics({options: DEFAULT_V2_ANALYTICS_CONFIG}); + simulateAuction([ [AUCTION_INIT, auctionInit], [BID_REQUESTED, bidRequestedOpenX], [BID_REQUESTED, bidRequestedCloseX], [BID_RESPONSE, bidResponseOpenX], - [BID_RESPONSE, bidResponseCloseX] + [BID_RESPONSE, bidResponseCloseX], + [AUCTION_END, auctionEnd], + [BID_WON, bidWonOpenX] ]); - const queryData = getQueryData(server.requests[0].url); - const auctionStart = bidRequestedOpenX.auctionStart; - expect(queryData).to.include({ - 'hb.exn': [ - bidRequestedOpenX.bids[0].bidder, - bidRequestedCloseX.bids[0].bidder - ].join(','), - 'hb.sts': [ - bidRequestedOpenX.start - auctionStart, - bidRequestedCloseX.start - auctionStart - ].join(','), - 'hb.ets': [ - bidResponseOpenX.responseTimestamp - auctionStart, - bidResponseCloseX.responseTimestamp - auctionStart - ].join(','), - 'hb.bv': [bidResponseOpenX.cpm, bidResponseCloseX.cpm].join(','), - 'hb.crid': [ - bidResponseOpenX.creativeId, - bidResponseCloseX.creativeId - ].join(','), - 'hb.to': [false, false].join(',') - }); + clock.tick(SLOT_LOAD_WAIT_TIME * 2); + auction = JSON.parse(server.requests[0].requestBody)[0]; }); - it('OpenX timed out', function() { - simulateAuction([ - [AUCTION_INIT, auctionInit], - [BID_REQUESTED, bidRequestedOpenX], - [BID_REQUESTED, bidRequestedCloseX], - [BID_RESPONSE, bidResponseCloseX], - [BID_TIMEOUT, bidTimeoutOpenX] - ]); + afterEach(function () { + openxAdapter.reset(); + openxAdapter.disableAnalytics(); + }); - const queryData = getQueryData(server.requests[0].url); - const auctionStart = bidRequestedOpenX.auctionStart; - expect(queryData).to.include({ - 'hb.exn': [ - bidRequestedOpenX.bids[0].bidder, - bidRequestedCloseX.bids[0].bidder - ].join(','), - 'hb.sts': [ - bidRequestedOpenX.start - auctionStart, - bidRequestedCloseX.start - auctionStart - ].join(','), - 'hb.ets': [ - undefined, - bidResponseCloseX.responseTimestamp - auctionStart - ].join(','), - 'hb.bv': [0, bidResponseCloseX.cpm].join(','), - 'hb.crid': [undefined, bidResponseCloseX.creativeId].join(','), - 'hb.to': [true, false].join(',') - }); + it('should track that bidder as the winner', function () { + let openxBidder = find(auction.adUnits[0].bidRequests, bidderRequest => bidderRequest.bidder === 'openx'); + expect(openxBidder.bidResponses[0]).to.contain({winner: true}); + }); + + it('should track that bidder as the losers', function () { + let closexBidder = find(auction.adUnits[0].bidRequests, bidderRequest => bidderRequest.bidder === 'closex'); + expect(closexBidder.bidResponses[0]).to.contain({winner: false}); }); }); - describe('hb.we, hb.g1', function() { - it('OpenX won', function() { + describe('when a winning bid renders', function () { + let auction; + beforeEach(function () { + openxAdapter.enableAnalytics({options: DEFAULT_V2_ANALYTICS_CONFIG}); + simulateAuction([ [AUCTION_INIT, auctionInit], [BID_REQUESTED, bidRequestedOpenX], + [BID_REQUESTED, bidRequestedCloseX], [BID_RESPONSE, bidResponseOpenX], - [BID_WON, bidWonOpenX] + [BID_RESPONSE, bidResponseCloseX], + [AUCTION_END, auctionEnd], + [BID_WON, bidWonOpenX], + [SLOT_LOADED] ]); - const queryData = getQueryData(server.requests[0].url); - expect(queryData).to.include({ - 'hb.we': '0', - 'hb.g1': 'false' - }); + clock.tick(SLOT_LOAD_WAIT_TIME * 2); + auction = JSON.parse(server.requests[0].requestBody)[0]; }); - it('DFP won', function() { - simulateAuction([ - [AUCTION_INIT, auctionInit], - [BID_REQUESTED, bidRequestedOpenX], - [BID_RESPONSE, bidResponseOpenX] - ]); + afterEach(function () { + openxAdapter.reset(); + openxAdapter.disableAnalytics(); + }); - const queryData = getQueryData(server.requests[0].url); - expect(queryData).to.include({ - 'hb.we': '-1', - 'hb.g1': 'true' - }); + it('should track that winning bid rendered', function () { + let openxBidder = find(auction.adUnits[0].bidRequests, bidderRequest => bidderRequest.bidder === 'openx'); + expect(openxBidder.bidResponses[0]).to.contain({rendered: true}); + }); + + it('should track that winning bid render time', function () { + let openxBidder = find(auction.adUnits[0].bidRequests, bidderRequest => bidderRequest.bidder === 'openx'); + expect(openxBidder.bidResponses[0]).to.contain({renderTime: CURRENT_TIME}); + }); + + it('should track that the auction completed', function () { + expect(auction.state).to.equal(AUCTION_STATES.COMPLETED); }); }); }); diff --git a/test/spec/modules/openxBidAdapter_spec.js b/test/spec/modules/openxBidAdapter_spec.js index 49584ea8b43..121f8e76a07 100644 --- a/test/spec/modules/openxBidAdapter_spec.js +++ b/test/spec/modules/openxBidAdapter_spec.js @@ -290,6 +290,38 @@ describe('OpenxAdapter', function () { expect(spec.isBidRequestValid(videoBidWithMediaType)).to.equal(false); }); }); + + describe('and request config uses test', () => { + const videoBidWithTest = { + bidder: 'openx', + params: { + unit: '12345678', + delDomain: 'test-del-domain', + test: true + }, + adUnitCode: 'adunit-code', + mediaTypes: { + video: { + playerSize: [640, 480] + } + }, + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e' + }; + + let mockBidderRequest = {refererInfo: {}}; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(videoBidWithTest)).to.equal(true); + }); + + it('should send video bid request to openx url via GET, with vtest=1 video parameter', function () { + const request = spec.buildRequests([videoBidWithTest], mockBidderRequest); + expect(request[0].data.vtest).to.equal(1); + }); + }); }); }); @@ -508,25 +540,6 @@ describe('OpenxAdapter', function () { expect(dataParams.tps).to.equal(btoa('test1=testval1.&test2=testval2_,testval3')); }); - it('should send out custom floors on bids that have customFloors specified', function () { - const bidRequest = Object.assign({}, - bidRequestsWithMediaTypes[0], - { - params: { - 'unit': '12345678', - 'delDomain': 'test-del-domain', - 'customFloor': 1.500001 - } - } - ); - - const request = spec.buildRequests([bidRequest], mockBidderRequest); - const dataParams = request[0].data; - - expect(dataParams.aumfs).to.exist; - expect(dataParams.aumfs).to.equal('1500'); - }); - it('should send out custom bc parameter, if override is present', function () { const bidRequest = Object.assign({}, bidRequestsWithMediaTypes[0], @@ -1030,11 +1043,11 @@ describe('OpenxAdapter', function () { britepoolid: '1111-britepoolid', criteoId: '1111-criteoId', digitrustid: {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}, - id5id: '1111-id5id', + id5id: {uid: '1111-id5id'}, idl_env: '1111-idl_env', lipb: {lipbid: '1111-lipb'}, netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg', - parrableid: 'eidVersion.encryptionKeyReference.encryptedValue', + parrableId: { eid: 'eidVersion.encryptionKeyReference.encryptedValue' }, pubcid: '1111-pubcid', tdid: '1111-tdid', }; @@ -1080,6 +1093,12 @@ describe('OpenxAdapter', function () { case 'lipb': userIdValue = EXAMPLE_DATA_BY_ATTR.lipb.lipbid; break; + case 'parrableId': + userIdValue = EXAMPLE_DATA_BY_ATTR.parrableId.eid; + break; + case 'id5id': + userIdValue = EXAMPLE_DATA_BY_ATTR.id5id.uid; + break; default: userIdValue = EXAMPLE_DATA_BY_ATTR[userIdProviderKey]; } @@ -1089,6 +1108,107 @@ describe('OpenxAdapter', function () { }); }); }); + + describe('floors', function () { + it('should send out custom floors on bids that have customFloors specified', function () { + const bidRequest = Object.assign({}, + bidRequestsWithMediaTypes[0], + { + params: { + 'unit': '12345678', + 'delDomain': 'test-del-domain', + 'customFloor': 1.500001 + } + } + ); + + const request = spec.buildRequests([bidRequest], mockBidderRequest); + const dataParams = request[0].data; + + expect(dataParams.aumfs).to.exist; + expect(dataParams.aumfs).to.equal('1500'); + }); + + context('with floors module', function () { + let adServerCurrencyStub; + + beforeEach(function () { + adServerCurrencyStub = sinon + .stub(config, 'getConfig') + .withArgs('currency.adServerCurrency') + }); + + afterEach(function () { + config.getConfig.restore(); + }); + + it('should send out floors on bids', function () { + const bidRequest1 = Object.assign({}, + bidRequestsWithMediaTypes[0], + { + getFloor: () => { + return { + currency: 'AUS', + floor: 9.99 + } + } + } + ); + + const bidRequest2 = Object.assign({}, + bidRequestsWithMediaTypes[1], + { + getFloor: () => { + return { + currency: 'AUS', + floor: 18.881 + } + } + } + ); + + const request = spec.buildRequests([bidRequest1, bidRequest2], mockBidderRequest); + const dataParams = request[0].data; + + expect(dataParams.aumfs).to.exist; + expect(dataParams.aumfs).to.equal('9990,18881'); + }); + + it('should send out floors on bids in the default currency', function () { + const bidRequest1 = Object.assign({}, + bidRequestsWithMediaTypes[0], + { + getFloor: () => { + return {}; + } + } + ); + + let getFloorSpy = sinon.spy(bidRequest1, 'getFloor'); + + spec.buildRequests([bidRequest1], mockBidderRequest); + expect(getFloorSpy.args[0][0].currency).to.equal('USD'); + }); + + it('should send out floors on bids in the ad server currency if defined', function () { + adServerCurrencyStub.returns('bitcoin'); + + const bidRequest1 = Object.assign({}, + bidRequestsWithMediaTypes[0], + { + getFloor: () => { + return {}; + } + } + ); + + let getFloorSpy = sinon.spy(bidRequest1, 'getFloor'); + + spec.buildRequests([bidRequest1], mockBidderRequest); + expect(getFloorSpy.args[0][0].currency).to.equal('bitcoin'); + }); + }) + }) }); describe('buildRequests for video', function () { @@ -1126,6 +1246,11 @@ describe('OpenxAdapter', function () { expect(dataParams.vwd).to.equal(640); }); + it('shouldn\'t have the test parameter', function () { + const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + expect(request[0].data.vtest).to.be.undefined; + }); + it('should send a bc parameter', function () { const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); const dataParams = request[0].data; @@ -1155,7 +1280,7 @@ describe('OpenxAdapter', function () { 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e' - } + }; mockBidderRequest = {refererInfo: {}}; }); @@ -1587,32 +1712,31 @@ describe('OpenxAdapter', function () { payload: {'bid': bidsWithMediaType[0], 'startTime': new Date()} }; const bidResponse = { - 'pub_rev': '1', + 'pub_rev': '1000', 'width': '640', 'height': '480', 'adid': '5678', - 'vastUrl': 'https://testvast.com/vastpath?colo=https://test-colo.com&ph=test-ph&ts=test-ts', + 'currency': 'AUD', + 'vastUrl': 'https://testvast.com', 'pixels': 'https://testpixels.net' }; it('should return correct bid response with MediaTypes', function () { - const expectedResponse = [ - { - 'requestId': '30b31c1838de1e', - 'cpm': 1, - 'width': '640', - 'height': '480', - 'mediaType': 'video', - 'creativeId': '5678', - 'vastUrl': 'https://testvast.com', - 'ttl': 300, - 'netRevenue': true, - 'currency': 'USD' - } - ]; + const expectedResponse = { + 'requestId': '30b31c1838de1e', + 'cpm': 1, + 'width': 640, + 'height': 480, + 'mediaType': 'video', + 'creativeId': '5678', + 'vastUrl': 'https://testvast.com', + 'ttl': 300, + 'netRevenue': true, + 'currency': 'AUD' + }; const result = spec.interpretResponse({body: bidResponse}, bidRequestsWithMediaTypes); - expect(JSON.stringify(Object.keys(result[0]).sort())).to.eql(JSON.stringify(Object.keys(expectedResponse[0]).sort())); + expect(result[0]).to.eql(expectedResponse); }); it('should return correct bid response with MediaType', function () { diff --git a/test/spec/modules/orbidderBidAdapter_spec.js b/test/spec/modules/orbidderBidAdapter_spec.js index c20f11da5b5..df551311c0b 100644 --- a/test/spec/modules/orbidderBidAdapter_spec.js +++ b/test/spec/modules/orbidderBidAdapter_spec.js @@ -1,8 +1,6 @@ import {expect} from 'chai'; import {spec} from 'modules/orbidderBidAdapter.js'; import {newBidder} from 'src/adapters/bidderFactory.js'; -import openxAdapter from '../../../modules/openxAnalyticsAdapter.js'; -import {detectReferer} from 'src/refererDetection.js'; describe('orbidderBidAdapter', () => { const adapter = newBidder(spec); @@ -93,7 +91,7 @@ describe('orbidderBidAdapter', () => { it('sends bid request to endpoint via https using post', () => { expect(request.method).to.equal('POST'); expect(request.url.indexOf('https://')).to.equal(0); - expect(request.url).to.equal(`${spec.orbidderHost}/bid`); + expect(request.url).to.equal(`${spec.hostname}/bid`); }); it('contains prebid version parameter', () => { @@ -153,40 +151,6 @@ describe('orbidderBidAdapter', () => { }); }); - describe('onCallbackHandler', () => { - let ajaxStub; - const bidObj = { - adId: 'testId', - test: 1, - pageUrl: 'www.someurl.de', - referrer: 'www.somereferrer.de', - requestId: '123req456' - }; - - spec.bidParams['123req456'] = {'accountId': '123acc456'}; - - let bidObjClone = deepClone(bidObj); - bidObjClone.v = $$PREBID_GLOBAL$$.version; - bidObjClone.pageUrl = detectReferer(window)().referer; - bidObjClone.params = [{'accountId': '123acc456'}]; - - beforeEach(() => { - ajaxStub = sinon.stub(spec, 'ajaxCall'); - }); - - afterEach(() => { - ajaxStub.restore(); - }); - - it('calls orbidder\'s callback endpoint', () => { - spec.onBidWon(bidObj); - expect(ajaxStub.calledOnce).to.equal(true); - expect(ajaxStub.firstCall.args[0].indexOf('https://')).to.equal(0); - expect(ajaxStub.firstCall.args[0]).to.equal(`${spec.orbidderHost}/win`); - expect(ajaxStub.firstCall.args[1]).to.equal(JSON.stringify(bidObjClone)); - }); - }); - describe('interpretResponse', () => { it('should get correct bid response', () => { const serverResponse = [ diff --git a/test/spec/modules/ozoneBidAdapter_spec.js b/test/spec/modules/ozoneBidAdapter_spec.js index 16ebb5c321b..c1022608b4a 100644 --- a/test/spec/modules/ozoneBidAdapter_spec.js +++ b/test/spec/modules/ozoneBidAdapter_spec.js @@ -11,6 +11,7 @@ const BIDDER_CODE = 'ozone'; NOTE - use firefox console to deep copy the objects to use here */ +var originalPropertyBag = {'lotameWasOverridden': 0, 'pageId': null}; var validBidRequests = [ { adUnitCode: 'div-gpt-ad-1460505748561-0', @@ -20,7 +21,35 @@ var validBidRequests = [ bidder: 'ozone', bidderRequestId: '1c1586b27a1b5c8', crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, - params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}], 'ThirdPartyAudience': [{'id': '123', 'name': 'Automobiles'}, {'id': '456', 'name': 'Ages: 30-39'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, banner: { format: [{ w: 300, h: 250 }, { w: 300, h: 600 }], h: 250, topframe: 1, w: 300 } } ] }, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, banner: { format: [{ w: 300, h: 250 }, { w: 300, h: 600 }], h: 250, topframe: 1, w: 300 } } ] }, + sizes: [[300, 250], [300, 600]], + transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' + } +]; +var validBidRequestsMulti = [ + { + testId: 1, + adUnitCode: 'div-gpt-ad-1460505748561-0', + auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', + bidId: '2899ec066a91ff8', + bidRequestsCount: 1, + bidder: 'ozone', + bidderRequestId: '1c1586b27a1b5c8', + crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, banner: { format: [{ w: 300, h: 250 }, { w: 300, h: 600 }], h: 250, topframe: 1, w: 300 } } ] }, + sizes: [[300, 250], [300, 600]], + transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' + }, + { + testId: 2, + adUnitCode: 'div-gpt-ad-1460505748561-0', + auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', + bidId: '2899ec066a91ff0', + bidRequestsCount: 1, + bidder: 'ozone', + bidderRequestId: '1c1586b27a1b5c0', + crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, banner: { format: [{ w: 300, h: 250 }, { w: 300, h: 600 }], h: 250, topframe: 1, w: 300 } } ] }, sizes: [[300, 250], [300, 600]], transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' } @@ -34,10 +63,10 @@ var validBidRequestsWithUserIdData = [ bidder: 'ozone', bidderRequestId: '1c1586b27a1b5c8', crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, - params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}], 'ThirdPartyAudience': [{'id': '123', 'name': 'Automobiles'}, {'id': '456', 'name': 'Ages: 30-39'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, banner: { format: [{ w: 300, h: 250 }, { w: 300, h: 600 }], h: 250, topframe: 1, w: 300 } } ] }, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, banner: { format: [{ w: 300, h: 250 }, { w: 300, h: 600 }], h: 250, topframe: 1, w: 300 } } ] }, sizes: [[300, 250], [300, 600]], transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87', - userId: {'pubcid': '12345678', 'id5id': 'ID5-someId', 'criteortus': {'ozone': {'userid': 'critId123'}}, 'idl_env': 'liverampId', 'lipb': {'lipbid': 'lipbidId123'}, 'parrableid': 'parrableid123'} + userId: {'pubcid': '12345678', 'id5id': { 'uid': 'ID5-someId' }, 'criteortus': {'ozone': {'userid': 'critId123'}}, 'idl_env': 'liverampId', 'lipb': {'lipbid': 'lipbidId123'}, 'parrableId': {eid: 'parrableid123'}} } ]; var validBidRequestsMinimal = [ @@ -62,7 +91,7 @@ var validBidRequestsNoSizes = [ bidder: 'ozone', bidderRequestId: '1c1586b27a1b5c8', crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, - params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}], 'ThirdPartyAudience': [{'id': '123', 'name': 'Automobiles'}, {'id': '456', 'name': 'Ages: 30-39'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, banner: { format: [{ w: 300, h: 250 }, { w: 300, h: 600 }], h: 250, topframe: 1, w: 300 } } ] }, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, banner: { format: [{ w: 300, h: 250 }, { w: 300, h: 600 }], h: 250, topframe: 1, w: 300 } } ] }, transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' } ]; @@ -76,7 +105,7 @@ var validBidRequestsWithBannerMediaType = [ bidder: 'ozone', bidderRequestId: '1c1586b27a1b5c8', crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, - params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}], 'ThirdPartyAudience': [{'id': '123', 'name': 'Automobiles'}, {'id': '456', 'name': 'Ages: 30-39'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, banner: { format: [{ w: 300, h: 250 }, { w: 300, h: 600 }], h: 250, topframe: 1, w: 300 } } ] }, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, banner: { format: [{ w: 300, h: 250 }, { w: 300, h: 600 }], h: 250, topframe: 1, w: 300 } } ] }, mediaTypes: {banner: {sizes: [[300, 250], [300, 600]]}}, transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' } @@ -90,90 +119,325 @@ var validBidRequestsWithNonBannerMediaTypesAndValidOutstreamVideo = [ bidder: 'ozone', bidderRequestId: '1c1586b27a1b5c8', crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, - params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}], 'ThirdPartyAudience': [{'id': '123', 'name': 'Automobiles'}, {'id': '456', 'name': 'Ages: 30-39'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, video: {skippable: true, playback_method: ['auto_play_sound_off'], targetDiv: 'some-different-div-id-to-my-adunitcode'} } ] }, - mediaTypes: {video: {mimes: ['video/mp4'], 'context': 'outstream', 'sizes': [640, 480]}, native: {info: 'dummy data'}}, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { id: '2899ec066a91ff8', tagid: 'undefined', secure: 1, video: {skippable: true, playback_method: ['auto_play_sound_off'], targetDiv: 'some-different-div-id-to-my-adunitcode'} } ] }, + mediaTypes: {video: {mimes: ['video/mp4'], 'context': 'outstream', 'sizes': [640, 480], playerSize: [640, 480]}, native: {info: 'dummy data'}}, transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' } ]; +var validBidRequests1OutstreamVideo2020 = [ + { + 'bidder': 'ozone', + 'testname': 'validBidRequests1OutstreamVideo2020', + 'params': { + 'publisherId': 'OZONERUP0001', + 'placementId': '8000000009', + 'siteId': '4204204201', + 'video': { + 'skippable': true, + 'playback_method': [ + 'auto_play_sound_off' + ] + }, + 'customData': [ + { + 'settings': {}, + 'targeting': { + 'sens': 'f', + 'pt1': '/uk', + 'pt2': 'uk', + 'pt3': 'network-front', + 'pt4': 'ng', + 'pt5': [ + 'uk' + ], + 'pt7': 'desktop', + 'pt8': [ + 'tfmqxwj7q', + 'penl4dfdk', + 'sek9ghqwi' + ], + 'pt9': '|k0xw2vqzp33kklb3j5w4|||' + } + } + ], + 'lotameData': { + 'Profile': { + 'tpid': '4e5c21fc7c181c2b1eb3a73d543a27f6', + 'pid': '3a45fd4872fa01f35c49586d8dcb7c60', + 'Audiences': { + 'Audience': [ + { + 'id': '439847', + 'abbr': 'all' + }, + { + 'id': '446197', + 'abbr': 'Arts, Culture & Literature' + }, + { + 'id': '446198', + 'abbr': 'Business' + } + ] + } + } + } + }, + 'userId': { + 'pubcid': '2ada6ae6-aeca-4e07-8922-a99b3aaf8a56' + }, + 'userIdAsEids': [ + { + 'source': 'pubcid.org', + 'uids': [ + { + 'id': '2ada6ae6-aeca-4e07-8922-a99b3aaf8a56', + 'atype': 1 + } + ] + } + ], + 'mediaTypes': { + 'video': { + 'playerSize': [ + [ + 640, + 480 + ] + ], + 'mimes': [ + 'video/mp4' + ], + 'context': 'outstream' + } + }, + 'adUnitCode': 'video-ad', + 'transactionId': '02c1ea7d-0bf2-451b-a122-1420040d1cf8', + 'sizes': [ + [ + 640, + 480 + ] + ], + 'bidId': '2899ec066a91ff8', + 'bidderRequestId': '1c1586b27a1b5c8', + 'auctionId': '0456c9b7-5ab2-4fec-9e10-f418d3d1f04c', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + } +]; + +// WHEN sent as bidderRequest to buildRequests you should send the child: .bidderRequest +var validBidderRequest1OutstreamVideo2020 = { + bidderRequest: { + auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', + auctionStart: 1536838908986, + bidderCode: 'ozone', + bidderRequestId: '1c1586b27a1b5c8', + bids: [ + { + 'bidder': 'ozone', + 'params': { + 'publisherId': 'OZONERUP0001', + 'placementId': '8000000009', + 'siteId': '4204204201', + 'video': { + 'skippable': true, + 'playback_method': [ + 'auto_play_sound_off' + ] + }, + 'customData': [ + { + 'settings': {}, + 'targeting': { + 'sens': 'f', + 'pt1': '/uk', + 'pt2': 'uk', + 'pt3': 'network-front', + 'pt4': 'ng', + 'pt5': [ + 'uk' + ], + 'pt7': 'desktop', + 'pt8': [ + 'tfmqxwj7q', + 'penl4dfdk', + 'uayf5jmv3', + 'sek9ghqwi' + ], + 'pt9': '|k0xw2vqzp33kklb3j5w4|||' + } + } + ], + 'lotameData': { + 'Profile': { + 'tpid': '4e5c21fc7c181c2b1eb3a73d543a27f6', + 'pid': '3a45fd4872fa01f35c49586d8dcb7c60', + 'Audiences': { + 'Audience': [ + { + 'id': '439847', + 'abbr': 'all' + }, + { + 'id': '446197', + 'abbr': 'Arts, Culture & Literature' + }, + { + 'id': '446198', + 'abbr': 'Business' + } + ] + } + } + } + }, + 'userId': { + 'id5id': { uid: 'ID5-ZHMOpSv9CkZNiNd1oR4zc62AzCgSS73fPjmQ6Od7OA' }, + 'pubcid': '2ada6ae6-aeca-4e07-8922-a99b3aaf8a56' + }, + 'userIdAsEids': [ + { + 'source': 'id5-sync.com', + 'uids': [ + { + 'id': 'ID5-ZHMOpSv9CkZNiNd1oR4zc62AzCgSS73fPjmQ6Od7OA', + 'atype': 1 + } + ] + }, + { + 'source': 'pubcid.org', + 'uids': [ + { + 'id': '2ada6ae6-aeca-4e07-8922-a99b3aaf8a56', + 'atype': 1 + } + ] + } + ], + 'mediaTypes': { + 'video': { + 'playerSize': [ + [ + 640, + 480 + ] + ], + 'mimes': [ + 'video/mp4' + ], + 'context': 'outstream' + } + }, + 'adUnitCode': 'video-ad', + 'transactionId': 'ec20cc65-de38-4410-b5b3-50de5b7df66a', + 'sizes': [ + [ + 640, + 480 + ] + ], + 'bidId': '2899ec066a91ff8', + 'bidderRequestId': '1c1586b27a1b5c8', + 'auctionId': '0456c9b7-5ab2-4fec-9e10-f418d3d1f04c', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + }], + doneCbCallCount: 1, + start: 1536838908987, + timeout: 3000 + } +}; +// WHEN sent as bidderRequest to buildRequests you should send the child: .bidderRequest var validBidderRequest = { - auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', - auctionStart: 1536838908986, - bidderCode: 'ozone', - bidderRequestId: '1c1586b27a1b5c8', - bids: [{ - adUnitCode: 'div-gpt-ad-1460505748561-0', + bidderRequest: { auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', - bidId: '2899ec066a91ff8', - bidRequestsCount: 1, - bidder: 'ozone', + auctionStart: 1536838908986, + bidderCode: 'ozone', bidderRequestId: '1c1586b27a1b5c8', - crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, - params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}], 'ThirdPartyAudience': [{'id': '123', 'name': 'Automobiles'}, {'id': '456', 'name': 'Ages: 30-39'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { banner: { topframe: 1, w: 300, h: 250, format: [{ w: 300, h: 250 }, { w: 300, h: 600 }] }, id: '2899ec066a91ff8', secure: 1, tagid: 'undefined' } ] }, - sizes: [[300, 250], [300, 600]], - transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' - }], - doneCbCallCount: 1, - start: 1536838908987, - timeout: 3000 + bids: [{ + adUnitCode: 'div-gpt-ad-1460505748561-0', + auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', + bidId: '2899ec066a91ff8', + bidRequestsCount: 1, + bidder: 'ozone', + bidderRequestId: '1c1586b27a1b5c8', + crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { banner: { topframe: 1, w: 300, h: 250, format: [{ w: 300, h: 250 }, { w: 300, h: 600 }] }, id: '2899ec066a91ff8', secure: 1, tagid: 'undefined' } ] }, + sizes: [[300, 250], [300, 600]], + transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' + }], + doneCbCallCount: 1, + start: 1536838908987, + timeout: 3000 + } }; // bidder request with GDPR - change the values for testing: // gdprConsent.gdprApplies (true/false) // gdprConsent.vendorData.purposeConsents (make empty, make null, remove it) // gdprConsent.vendorData.vendorConsents (remove 524, remove all, make the element null, remove it) +// WHEN sent as bidderRequest to buildRequests you should send the child: .bidderRequest var bidderRequestWithFullGdpr = { - auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', - auctionStart: 1536838908986, - bidderCode: 'ozone', - bidderRequestId: '1c1586b27a1b5c8', - bids: [{ - adUnitCode: 'div-gpt-ad-1460505748561-0', + bidderRequest: { auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', - bidId: '2899ec066a91ff8', - bidRequestsCount: 1, - bidder: 'ozone', + auctionStart: 1536838908986, + bidderCode: 'ozone', bidderRequestId: '1c1586b27a1b5c8', - crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, - params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}], 'ThirdPartyAudience': [{'id': '123', 'name': 'Automobiles'}, {'id': '456', 'name': 'Ages: 30-39'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { banner: { topframe: 1, w: 300, h: 250, format: [{ w: 300, h: 250 }, { w: 300, h: 600 }] }, id: '2899ec066a91ff8', secure: 1, tagid: 'undefined' } ] }, - sizes: [[300, 250], [300, 600]], - transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' - }], - doneCbCallCount: 1, - start: 1536838908987, - timeout: 3000, - gdprConsent: { - 'consentString': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', - 'vendorData': { - 'metadata': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', - 'gdprApplies': true, - 'hasGlobalScope': false, - 'cookieVersion': '1', - 'created': '2019-05-31T12:46:48.825', - 'lastUpdated': '2019-05-31T12:46:48.825', - 'cmpId': '28', - 'cmpVersion': '1', - 'consentLanguage': 'en', - 'consentScreen': '1', - 'vendorListVersion': 148, - 'maxVendorId': 631, - 'purposeConsents': { - '1': true, - '2': true, - '3': true, - '4': true, - '5': true + bids: [{ + adUnitCode: 'div-gpt-ad-1460505748561-0', + auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', + bidId: '2899ec066a91ff8', + bidRequestsCount: 1, + bidder: 'ozone', + bidderRequestId: '1c1586b27a1b5c8', + crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, + params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { banner: { topframe: 1, w: 300, h: 250, format: [{ w: 300, h: 250 }, { w: 300, h: 600 }] }, id: '2899ec066a91ff8', secure: 1, tagid: 'undefined' } ] }, + sizes: [[300, 250], [300, 600]], + transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' + }], + doneCbCallCount: 1, + start: 1536838908987, + timeout: 3000, + gdprConsent: { + 'consentString': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', + 'vendorData': { + 'metadata': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', + 'gdprApplies': true, + 'hasGlobalScope': false, + 'cookieVersion': '1', + 'created': '2019-05-31T12:46:48.825', + 'lastUpdated': '2019-05-31T12:46:48.825', + 'cmpId': '28', + 'cmpVersion': '1', + 'consentLanguage': 'en', + 'consentScreen': '1', + 'vendorListVersion': 148, + 'maxVendorId': 631, + 'purposeConsents': { + '1': true, + '2': true, + '3': true, + '4': true, + '5': true + }, + 'vendorConsents': { + '468': true, + '522': true, + '524': true, /* 524 is ozone */ + '565': true, + '591': true + } }, - 'vendorConsents': { - '468': true, - '522': true, - '524': true, /* 524 is ozone */ - '565': true, - '591': true - } - }, - 'gdprApplies': true - }, + 'gdprApplies': true + }, } }; var gdpr1 = { @@ -211,33 +475,59 @@ var gdpr1 = { // simulating the Mirror var bidderRequestWithPartialGdpr = { - auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', - auctionStart: 1536838908986, - bidderCode: 'ozone', - bidderRequestId: '1c1586b27a1b5c8', - bids: [{ - adUnitCode: 'div-gpt-ad-1460505748561-0', + bidderRequest: { auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', - bidId: '2899ec066a91ff8', - bidRequestsCount: 1, - bidder: 'ozone', + auctionStart: 1536838908986, + bidderCode: 'ozone', bidderRequestId: '1c1586b27a1b5c8', - crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, - params: { publisherId: '9876abcd12-3', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}], 'ThirdPartyAudience': [{'id': '123', 'name': 'Automobiles'}, {'id': '456', 'name': 'Ages: 30-39'}]}}}, placementId: '1310000099', siteId: '1234567890', id: 'fea37168-78f1-4a23-a40e-88437a99377e', auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', imp: [ { banner: { topframe: 1, w: 300, h: 250, format: [{ w: 300, h: 250 }, { w: 300, h: 600 }] }, id: '2899ec066a91ff8', secure: 1, tagid: 'undefined' } ] }, - sizes: [[300, 250], [300, 600]], - transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' - }], - doneCbCallCount: 1, - start: 1536838908987, - timeout: 3000, - gdprConsent: { - 'consentString': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', - 'gdprApplies': true, - 'vendorData': { - 'metadata': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', - 'gdprApplies': true + bids: [{ + adUnitCode: 'div-gpt-ad-1460505748561-0', + auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', + bidId: '2899ec066a91ff8', + bidRequestsCount: 1, + bidder: 'ozone', + bidderRequestId: '1c1586b27a1b5c8', + crumbs: {pubcid: '203a0692-f728-4856-87f6-9a25a6b63715'}, + params: { + publisherId: '9876abcd12-3', + customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], + lotameData: { + 'Profile': { + 'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', + 'Audiences': { + 'Audience': [{'id': '99999', 'abbr': 'sports'}, { + 'id': '88888', + 'abbr': 'movie' + }, {'id': '77777', 'abbr': 'blogger'}] + } + } + }, + placementId: '1310000099', + siteId: '1234567890', + id: 'fea37168-78f1-4a23-a40e-88437a99377e', + auctionId: '27dcb421-95c6-4024-a624-3c03816c5f99', + imp: [{ + banner: {topframe: 1, w: 300, h: 250, format: [{w: 300, h: 250}, {w: 300, h: 600}]}, + id: '2899ec066a91ff8', + secure: 1, + tagid: 'undefined' + }] + }, + sizes: [[300, 250], [300, 600]], + transactionId: '2e63c0ed-b10c-4008-aed5-84582cecfe87' + }], + doneCbCallCount: 1, + start: 1536838908987, + timeout: 3000, + gdprConsent: { + 'consentString': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', + 'gdprApplies': true, + 'vendorData': { + 'metadata': 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', + 'gdprApplies': true + } } - }, + } }; // make sure the impid matches the request bidId @@ -297,158 +587,984 @@ var validResponse = { }, 'headers': {} }; -var validOutstreamResponse = { + +var validResponse2Bids = { + 'body': { + 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', + 'seatbid': [ + { + 'bid': [ + { + 'id': '677903815252395017', + 'impid': '2899ec066a91ff8', + 'price': 0.5, + 'adm': '', + 'adid': '98493581', + 'adomain': [ + 'http://prebid.org' + ], + 'iurl': 'https://fra1-ib.adnxs.com/cr?id=98493581', + 'cid': '9325', + 'crid': '98493581', + 'cat': [ + 'IAB3-1' + ], + 'w': 300, + 'h': 600, + 'ext': { + 'prebid': { + 'type': 'banner' + }, + 'bidder': { + 'appnexus': { + 'brand_id': 555545, + 'auction_id': 6500448734132353000, + 'bidder_id': 2, + 'bid_ad_type': 0 + } + } + } + }, + { + 'id': '677903815252395010', + 'impid': '2899ec066a91ff0', + 'price': 0.9, + 'adm': '', + 'adid': '98493580', + 'adomain': [ + 'http://prebid.org' + ], + 'iurl': 'https://fra1-ib.adnxs.com/cr?id=98493581', + 'cid': '9320', + 'crid': '98493580', + 'cat': [ + 'IAB3-1' + ], + 'w': 300, + 'h': 600, + 'ext': { + 'prebid': { + 'type': 'banner' + }, + 'bidder': { + 'appnexus': { + 'brand_id': 555540, + 'auction_id': 6500448734132353000, + 'bidder_id': 2, + 'bid_ad_type': 0 + } + } + } + } ], + 'seat': 'appnexus' + } + ], + 'cur': 'GBP', /* NOTE - this is where cur is, not in the seatbids. */ + 'ext': { + 'responsetimemillis': { + 'appnexus': 47, + 'openx': 30 + } + }, + 'timing': { + 'start': 1536848078.089177, + 'end': 1536848078.142203, + 'TimeTaken': 0.05302619934082031 + } + }, + 'headers': {} +}; +/* +A bidder returns a bid for both sizes in an adunit + */ +var validResponse2BidsSameAdunit = { + 'body': { + 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', + 'seatbid': [ + { + 'bid': [ + { + 'id': '677903815252395017', + 'impid': '2899ec066a91ff8', + 'price': 0.5, + 'adm': '', + 'adid': '98493581', + 'adomain': [ + 'http://prebid.org' + ], + 'iurl': 'https://fra1-ib.adnxs.com/cr?id=98493581', + 'cid': '9325', + 'crid': '98493581', + 'cat': [ + 'IAB3-1' + ], + 'w': 300, + 'h': 600, + 'ext': { + 'prebid': { + 'type': 'banner' + }, + 'bidder': { + 'appnexus': { + 'brand_id': 555545, + 'auction_id': 6500448734132353000, + 'bidder_id': 2, + 'bid_ad_type': 0 + } + } + } + }, + { + 'id': '677903815252395010', + 'impid': '2899ec066a91ff8', + 'price': 0.9, + 'adm': '', + 'adid': '98493580', + 'adomain': [ + 'http://prebid.org' + ], + 'iurl': 'https://fra1-ib.adnxs.com/cr?id=98493581', + 'cid': '9320', + 'crid': '98493580', + 'cat': [ + 'IAB3-1' + ], + 'w': 300, + 'h': 250, + 'ext': { + 'prebid': { + 'type': 'banner' + }, + 'bidder': { + 'appnexus': { + 'brand_id': 555540, + 'auction_id': 6500448734132353000, + 'bidder_id': 2, + 'bid_ad_type': 0 + } + } + } + } ], + 'seat': 'ozappnexus' + } + ], + 'cur': 'GBP', /* NOTE - this is where cur is, not in the seatbids. */ + 'ext': { + 'responsetimemillis': { + 'appnexus': 47, + 'openx': 30 + } + }, + 'timing': { + 'start': 1536848078.089177, + 'end': 1536848078.142203, + 'TimeTaken': 0.05302619934082031 + } + }, + 'headers': {} +}; +/* + +SPECIAL CONSIDERATION FOR VIDEO TESTS: + +DO NOT USE _validVideoResponse directly - the interpretResponse function will modify it (adding a renderer!!!) so all +subsequent calls will already have a renderer attached!!! + +*/ +function getCleanValidVideoResponse() { + return JSON.parse(JSON.stringify(_validVideoResponse)); +} +var _validVideoResponse = { + 'body': { + 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', + 'seatbid': [ + { + 'bid': [ + { + 'id': '2899ec066a91ff8', + 'impid': '2899ec066a91ff8', + 'price': 31.7, + 'adm': '', + 'adomain': [ + 'sarr.properties' + ], + 'crid': 'ozone-655', + 'cat': [ + 'IAB21' + ], + 'w': 640, + 'h': 360, + 'ext': { + 'prebid': { + 'type': 'video' + } + }, + 'adId': '2899ec066a91ff8-2', + 'cpm': 31.7, + 'bidId': '2899ec066a91ff8', + 'requestId': '2899ec066a91ff8', + 'width': 640, + 'height': 360, + 'ad': '', + 'netRevenue': true, + 'creativeId': 'ozone-655', + 'currency': 'USD', + 'ttl': 300, + 'adserverTargeting': { + 'oz_ozbeeswax': 'ozbeeswax', + 'oz_ozbeeswax_pb': '31.7', + 'oz_ozbeeswax_crid': 'ozone-655', + 'oz_ozbeeswax_adv': 'sarr.properties', + 'oz_ozbeeswax_imp_id': '49d16ccc28663a8', + 'oz_ozbeeswax_adId': '49d16ccc28663a8-2', + 'oz_ozbeeswax_pb_r': '20.00', + 'oz_ozbeeswax_omp': '1', + 'oz_ozbeeswax_vid': 'outstream', + 'oz_auc_id': 'efa7fea0-7e87-4811-be86-fefb38c35fbb', + 'oz_winner': 'ozbeeswax', + 'oz_response_id': 'efa7fea0-7e87-4811-be86-fefb38c35fbb', + 'oz_winner_auc_id': '49d16ccc28663a8', + 'oz_winner_imp_id': '49d16ccc28663a8', + 'oz_pb_v': '2.4.0', + 'hb_bidder': 'ozone', + 'hb_adid': '49d16ccc28663a8-2', + 'hb_pb': '20.00', + 'hb_size': '640x360', + 'hb_source': 'client', + 'hb_format': 'banner' + }, + 'originalCpm': 31.7, + 'originalCurrency': 'USD' + } + ], + 'seat': 'ozbeeswax' + } + ], + 'ext': { + 'responsetimemillis': { + 'beeswax': 9, + 'openx': 43, + 'ozappnexus': 31, + 'ozbeeswax': 7 + } + }, + 'timing': { + 'start': 1536848078.089177, + 'end': 1536848078.142203, + 'TimeTaken': 0.05302619934082031 + } + }, + 'headers': {} +}; + +var validBidResponse1adWith2Bidders = { + 'body': { + 'id': '91221f96-b931-4acc-8f05-c2a1186fa5ac', + 'seatbid': [ + { + 'bid': [ + { + 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', + 'impid': '2899ec066a91ff8', + 'price': 0.36754, + 'adm': '', + 'adid': '134928661', + 'adomain': [ + 'somecompany.com' + ], + 'iurl': 'https:\/\/ams1-ib.adnxs.com\/cr?id=134928661', + 'cid': '8825', + 'crid': '134928661', + 'cat': [ + 'IAB8-15', + 'IAB8-16', + 'IAB8-4', + 'IAB8-1', + 'IAB8-14', + 'IAB8-6', + 'IAB8-13', + 'IAB8-3', + 'IAB8-17', + 'IAB8-12', + 'IAB8-8', + 'IAB8-7', + 'IAB8-2', + 'IAB8-9', + 'IAB8', + 'IAB8-11' + ], + 'w': 300, + 'h': 250, + 'ext': { + 'prebid': { + 'type': 'banner' + }, + 'bidder': { + 'appnexus': { + 'brand_id': 14640, + 'auction_id': 1.8369641905139e+18, + 'bidder_id': 2, + 'bid_ad_type': 0 + } + } + } + } + ], + 'seat': 'appnexus' + }, + { + 'bid': [ + { + 'id': '75665207-a1ca-49db-ba0e-a5e9c7d26f32', + 'impid': '37fff511779365a', + 'price': 1.046, + 'adm': '
removed
', + 'adomain': [ + 'kx.com' + ], + 'crid': '13005', + 'w': 300, + 'h': 250, + 'ext': { + 'prebid': { + 'type': 'banner' + } + } + } + ], + 'seat': 'openx' + } + ], + 'ext': { + 'responsetimemillis': { + 'appnexus': 91, + 'openx': 109, + 'ozappnexus': 46, + 'ozbeeswax': 2, + 'pangaea': 91 + } + } + }, + 'headers': {} +}; + +/* +testing 2 ads, 2 bidders, one bidder bids for both slots in one adunit + */ + +var multiRequest1 = [ + { + 'bidder': 'ozone', + 'params': { + 'publisherId': 'OZONERUP0001', + 'siteId': '4204204201', + 'placementId': '0420420421', + 'customData': [ + { + 'settings': {}, + 'targeting': { + 'sens': 'f', + 'pt1': '/uk', + 'pt2': 'uk', + 'pt3': 'network-front', + 'pt4': 'ng', + 'pt5': [ + 'uk' + ], + 'pt7': 'desktop', + 'pt8': [ + 'tfmqxwj7q', + 'penl4dfdk', + 'uayf5jmv3', + 't8nyiude5', + 'sek9ghqwi' + ], + 'pt9': '|k0xw2vqzp33kklb3j5w4|||' + } + } + ], + 'lotameData': { + 'Profile': { + 'tpid': '4e5c21fc7c181c2b1eb3a73d543a27f6', + 'pid': '3a45fd4872fa01f35c49586d8dcb7c60', + 'Audiences': { + 'Audience': [ + { + 'id': '439847', + 'abbr': 'all' + }, + { + 'id': '446197', + 'abbr': 'Arts, Culture & Literature' + }, + { + 'id': '446198', + 'abbr': 'Business' + } + ] + } + } + } + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ], + [ + 300, + 600 + ] + ] + } + }, + 'adUnitCode': 'mpu', + 'transactionId': '6480bac7-31b5-4723-9145-ad8966660651', + 'sizes': [ + [ + 300, + 250 + ], + [ + 300, + 600 + ] + ], + 'bidId': '2d30e86db743a8', + 'bidderRequestId': '1d03a1dfc563fc', + 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + }, + { + 'bidder': 'ozone', + 'params': { + 'publisherId': 'OZONERUP0001', + 'siteId': '4204204201', + 'placementId': '0420420421', + 'customData': [ + { + 'settings': {}, + 'targeting': { + 'sens': 'f', + 'pt1': '/uk', + 'pt2': 'uk', + 'pt3': 'network-front', + 'pt4': 'ng', + 'pt5': [ + 'uk' + ], + 'pt7': 'desktop', + 'pt8': [ + 'tfmqxwj7q', + 'penl4dfdk', + 't8nxz6qzd', + 't8nyiude5', + 'sek9ghqwi' + ], + 'pt9': '|k0xw2vqzp33kklb3j5w4|||' + } + } + ], + 'lotameData': { + 'Profile': { + 'tpid': '4e5c21fc7c181c2b1eb3a73d543a27f6', + 'pid': '3a45fd4872fa01f35c49586d8dcb7c60', + 'Audiences': { + 'Audience': [ + { + 'id': '439847', + 'abbr': 'all' + }, + { + 'id': '446197', + 'abbr': 'Arts, Culture & Literature' + }, + { + 'id': '446198', + 'abbr': 'Business' + } + ] + } + } + } + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 728, + 90 + ], + [ + 970, + 250 + ] + ] + } + }, + 'adUnitCode': 'leaderboard', + 'transactionId': 'a49988e6-ae7c-46c4-9598-f18db49892a0', + 'sizes': [ + [ + 728, + 90 + ], + [ + 970, + 250 + ] + ], + 'bidId': '3025f169863b7f8', + 'bidderRequestId': '1d03a1dfc563fc', + 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + } +]; + +// WHEN sent as bidderRequest to buildRequests you should send the child: .bidderRequest +var multiBidderRequest1 = { + bidderRequest: { + 'bidderCode': 'ozone', + 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', + 'bidderRequestId': '1d03a1dfc563fc', + 'bids': [ + { + 'bidder': 'ozone', + 'params': { + 'publisherId': 'OZONERUP0001', + 'siteId': '4204204201', + 'placementId': '0420420421', + 'customData': [ + { + 'settings': {}, + 'targeting': { + 'sens': 'f', + 'pt1': '/uk', + 'pt2': 'uk', + 'pt3': 'network-front', + 'pt4': 'ng', + 'pt5': [ + 'uk' + ], + 'pt7': 'desktop', + 'pt8': [ + 'tfmqxwj7q', + 'txeh7uyo0', + 't8nxz6qzd', + 't8nyiude5', + 'sek9ghqwi' + ], + 'pt9': '|k0xw2vqzp33kklb3j5w4|||' + } + } + ], + 'lotameData': { + 'Profile': { + 'tpid': '4e5c21fc7c181c2b1eb3a73d543a27f6', + 'pid': '3a45fd4872fa01f35c49586d8dcb7c60', + 'Audiences': { + 'Audience': [ + { + 'id': '439847', + 'abbr': 'all' + }, + { + 'id': '446197', + 'abbr': 'Arts, Culture & Literature' + }, + { + 'id': '446198', + 'abbr': 'Business' + } + ] + } + } + } + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ], + [ + 300, + 600 + ] + ] + } + }, + 'adUnitCode': 'mpu', + 'transactionId': '6480bac7-31b5-4723-9145-ad8966660651', + 'sizes': [ + [ + 300, + 250 + ], + [ + 300, + 600 + ] + ], + 'bidId': '2d30e86db743a8', + 'bidderRequestId': '1d03a1dfc563fc', + 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + }, + { + 'bidder': 'ozone', + 'params': { + 'publisherId': 'OZONERUP0001', + 'siteId': '4204204201', + 'placementId': '0420420421', + 'customData': [ + { + 'settings': {}, + 'targeting': { + 'sens': 'f', + 'pt1': '/uk', + 'pt2': 'uk', + 'pt3': 'network-front', + 'pt4': 'ng', + 'pt5': [ + 'uk' + ], + 'pt7': 'desktop', + 'pt8': [ + 'tfmqxwj7q', + 'penl4dfdk', + 't8nxz6qzd', + 't8nyiude5', + 'sek9ghqwi' + ], + 'pt9': '|k0xw2vqzp33kklb3j5w4|||' + } + } + ], + 'lotameData': { + 'Profile': { + 'tpid': '4e5c21fc7c181c2b1eb3a73d543a27f6', + 'pid': '3a45fd4872fa01f35c49586d8dcb7c60', + 'Audiences': { + 'Audience': [ + { + 'id': '439847', + 'abbr': 'all' + }, + { + 'id': '446197', + 'abbr': 'Arts, Culture & Literature' + }, + { + 'id': '446198', + 'abbr': 'Business' + } + ] + } + } + } + }, + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 728, + 90 + ], + [ + 970, + 250 + ] + ] + } + }, + 'adUnitCode': 'leaderboard', + 'transactionId': 'a49988e6-ae7c-46c4-9598-f18db49892a0', + 'sizes': [ + [ + 728, + 90 + ], + [ + 970, + 250 + ] + ], + 'bidId': '3025f169863b7f8', + 'bidderRequestId': '1d03a1dfc563fc', + 'auctionId': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + } + ], + 'auctionStart': 1592918645574, + 'timeout': 3000, + 'refererInfo': { + 'referer': 'http://ozone.ardm.io/adapter/2.4.0/620x350-switch.html?guardian=true&pbjs_debug=true', + 'reachedTop': true, + 'numIframes': 0, + 'stack': [ + 'http://ozone.ardm.io/adapter/2.4.0/620x350-switch.html?guardian=true&pbjs_debug=true' + ] + }, + 'gdprConsent': { + 'consentString': 'BOvy5sFO1dBa2AKAiBENDP-AAAAwVrv7_77-_9f-_f__9uj3Gr_v_f__32ccL5tv3h_7v-_7fi_-0nV4u_1tft9ydk1-5ctDztp507iakiPHmqNeb9n_mz1eZpRP58E09j53z7Ew_v8_v-b7BCPN_Y3v-8K96kA', + 'vendorData': { + 'metadata': 'BOvy5sFO1dBa2AKAiBENDPA', + 'gdprApplies': true, + 'hasGlobalConsent': false, + 'hasGlobalScope': false, + 'purposeConsents': { + '1': true, + '2': true, + '3': true, + '4': true, + '5': true + }, + 'vendorConsents': { + '1': true, + '2': true, + '3': false, + '4': true, + '5': true + } + }, + 'gdprApplies': true + }, + 'start': 1592918645578 + } +}; + +var multiResponse1 = { 'body': { - 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', + 'id': '592ee33b-fb2e-4c00-b2d5-383e99cac57f', 'seatbid': [ { 'bid': [ { - 'id': '677903815252395017', - 'impid': '2899ec066a91ff8', - 'price': 0.5, - 'adm': '', - 'adid': '98493581', + 'id': '4419718600113204943', + 'impid': '2d30e86db743a8', + 'price': 0.2484, + 'adm': '', + 'adid': '119683582', 'adomain': [ - 'http://prebid.org' + 'https://ozoneproject.com' ], - 'iurl': 'https://fra1-ib.adnxs.com/cr?id=98493581', - 'cid': '9325', - 'crid': '98493581', + 'iurl': 'https://ams1-ib.adnxs.com/cr?id=119683582', + 'cid': '9979', + 'crid': '119683582', 'cat': [ - 'IAB3-1' + 'IAB3' ], 'w': 300, - 'h': 600, + 'h': 250, 'ext': { 'prebid': { - 'type': 'video' + 'type': 'banner' }, 'bidder': { - 'unruly': { - 'renderer': { - 'config': { - 'targetingUUID': 'aafd3388-afaf-41f4-b271-0ac8e0325a7f', - 'siteId': 1052815, - 'featureOverrides': {} - }, - 'url': 'https://video.unrulymedia.com/native/native-loader.js#supplyMode=prebid?cb=6284685353877994', - 'id': 'unruly_inarticle' - }, - 'vast_url': 'data:text/xml;base64,PD94bWwgdmVyc2lvbj0i' + 'ozone': {}, + 'appnexus': { + 'brand_id': 734921, + 'auction_id': 2995348111857539600, + 'bidder_id': 2, + 'bid_ad_type': 0 } } - } - } - ], - 'seat': 'unruly' - } - ], - 'ext': { - 'responsetimemillis': { - 'appnexus': 47, - 'openx': 30 - } - }, - 'timing': { - 'start': 1536848078.089177, - 'end': 1536848078.142203, - 'TimeTaken': 0.05302619934082031 - } - }, - 'headers': {} -}; -var validBidResponse1adWith2Bidders = { - 'body': { - 'id': '91221f96-b931-4acc-8f05-c2a1186fa5ac', - 'seatbid': [ - { - 'bid': [ + }, + 'cpm': 0.2484, + 'bidId': '2d30e86db743a8', + 'requestId': '2d30e86db743a8', + 'width': 300, + 'height': 250, + 'ad': '', + 'netRevenue': true, + 'creativeId': '119683582', + 'currency': 'USD', + 'ttl': 300, + 'originalCpm': 0.2484, + 'originalCurrency': 'USD' + }, { - 'id': 'd6198807-7a53-4141-b2db-d2cb754d68ba', - 'impid': '2899ec066a91ff8', - 'price': 0.36754, - 'adm': '', - 'adid': '134928661', + 'id': '18552976939844681', + 'impid': '3025f169863b7f8', + 'price': 0.0621, + 'adm': '', + 'adid': '120179216', 'adomain': [ - 'somecompany.com' - ], - 'iurl': 'https:\/\/ams1-ib.adnxs.com\/cr?id=134928661', - 'cid': '8825', - 'crid': '134928661', - 'cat': [ - 'IAB8-15', - 'IAB8-16', - 'IAB8-4', - 'IAB8-1', - 'IAB8-14', - 'IAB8-6', - 'IAB8-13', - 'IAB8-3', - 'IAB8-17', - 'IAB8-12', - 'IAB8-8', - 'IAB8-7', - 'IAB8-2', - 'IAB8-9', - 'IAB8', - 'IAB8-11' + 'appnexus.com' ], - 'w': 300, + 'iurl': 'https://ams1-ib.adnxs.com/cr?id=120179216', + 'cid': '9979', + 'crid': '120179216', + 'w': 970, 'h': 250, 'ext': { 'prebid': { 'type': 'banner' }, 'bidder': { + 'ozone': {}, 'appnexus': { - 'brand_id': 14640, - 'auction_id': 1.8369641905139e+18, + 'brand_id': 1, + 'auction_id': 3449036134472542700, 'bidder_id': 2, 'bid_ad_type': 0 } } - } + }, + 'cpm': 0.0621, + 'bidId': '3025f169863b7f8', + 'requestId': '3025f169863b7f8', + 'width': 970, + 'height': 250, + 'ad': '', + 'netRevenue': true, + 'creativeId': '120179216', + 'currency': 'USD', + 'ttl': 300, + 'originalCpm': 0.0621, + 'originalCurrency': 'USD' + }, + { + 'id': '18552976939844999', + 'impid': '3025f169863b7f8', + 'price': 0.521, + 'adm': '', + 'adid': '120179216', + 'adomain': [ + 'appnexus.com' + ], + 'iurl': 'https://ams1-ib.adnxs.com/cr?id=120179216', + 'cid': '9999', + 'crid': '120179299', + 'w': 728, + 'h': 90, + 'ext': { + 'prebid': { + 'type': 'banner' + }, + 'bidder': { + 'ozone': {}, + 'appnexus': { + 'brand_id': 1, + 'auction_id': 3449036134472542700, + 'bidder_id': 2, + 'bid_ad_type': 0 + } + } + }, + 'cpm': 0.521, + 'bidId': '3025f169863b7f8', + 'requestId': '3025f169863b7f8', + 'width': 728, + 'height': 90, + 'ad': '', + 'netRevenue': true, + 'creativeId': '120179299', + 'currency': 'USD', + 'ttl': 300, + 'originalCpm': 0.0621, + 'originalCurrency': 'USD' } ], - 'seat': 'appnexus' + 'seat': 'ozappnexus' }, { 'bid': [ { - 'id': '75665207-a1ca-49db-ba0e-a5e9c7d26f32', - 'impid': '37fff511779365a', - 'price': 1.046, - 'adm': '
removed
', - 'adomain': [ - 'kx.com' - ], - 'crid': '13005', + 'id': '1c605e8a-4992-4ec6-8a5c-f82e2938c2db', + 'impid': '2d30e86db743a8', + 'price': 0.01, + 'adm': '
', + 'crid': '540463358', 'w': 300, 'h': 250, 'ext': { 'prebid': { 'type': 'banner' + }, + 'bidder': { + 'ozone': {} } - } + }, + 'cpm': 0.01, + 'bidId': '2d30e86db743a8', + 'requestId': '2d30e86db743a8', + 'width': 300, + 'height': 250, + 'ad': '
', + 'netRevenue': true, + 'creativeId': '540463358', + 'currency': 'USD', + 'ttl': 300, + 'originalCpm': 0.01, + 'originalCurrency': 'USD' + }, + { + 'id': '3edeb4f7-d91d-44e2-8aeb-4a2f6d295ce5', + 'impid': '3025f169863b7f8', + 'price': 0.01, + 'adm': '
', + 'crid': '540221061', + 'w': 970, + 'h': 250, + 'ext': { + 'prebid': { + 'type': 'banner' + }, + 'bidder': { + 'ozone': {} + } + }, + 'cpm': 0.01, + 'bidId': '3025f169863b7f8', + 'requestId': '3025f169863b7f8', + 'width': 970, + 'height': 250, + 'ad': '
', + 'netRevenue': true, + 'creativeId': '540221061', + 'currency': 'USD', + 'ttl': 300, + 'originalCpm': 0.01, + 'originalCurrency': 'USD' } ], 'seat': 'openx' } ], 'ext': { + 'debug': {}, 'responsetimemillis': { - 'appnexus': 91, - 'openx': 109, - 'ozappnexus': 46, - 'ozbeeswax': 2, - 'pangaea': 91 + 'beeswax': 6, + 'openx': 91, + 'ozappnexus': 40, + 'ozbeeswax': 6 } } }, 'headers': {} }; +/* +--------------------end of 2 slots, 2 ---------------------------- + */ + describe('ozone Adapter', function () { describe('isBidRequestValid', function () { // A test ad unit that will consistently return test creatives @@ -473,7 +1589,7 @@ describe('ozone Adapter', function () { publisherId: '9876abcd12-3', siteId: '1234567890', customData: [{'settings': {}, 'targeting': {'gender': 'bart', 'age': 'low'}}], - lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}], 'ThirdPartyAudience': [{'id': '123', 'name': 'Automobiles'}, {'id': '456', 'name': 'Ages: 30-39'}]}}}, + lotameData: {'Profile': {'tpid': 'c8ef27a0d4ba771a81159f0d2e792db4', 'Audiences': {'Audience': [{'id': '99999', 'abbr': 'sports'}, {'id': '88888', 'abbr': 'movie'}, {'id': '77777', 'abbr': 'blogger'}]}}}, }, siteId: 1234567890 } @@ -854,26 +1970,26 @@ describe('ozone Adapter', function () { describe('buildRequests', function () { it('sends bid request to OZONEURI via POST', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); expect(request.url).to.equal(OZONEURI); expect(request.method).to.equal('POST'); }); it('sends data as a string', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); expect(request.data).to.be.a('string'); }); it('sends all bid parameters', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); it('adds all parameters inside the ext object only', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); expect(request.data).to.be.a('string'); var data = JSON.parse(request.data); - expect(data.imp[0].ext.ozone.lotameData).to.be.an('object'); + expect(data.ext.ozone.lotameData).to.be.an('object'); expect(data.imp[0].ext.ozone.customData).to.be.an('array'); expect(request).not.to.have.key('lotameData'); expect(request).not.to.have.key('customData'); @@ -882,10 +1998,10 @@ describe('ozone Adapter', function () { it('ignores ozoneData in & after version 2.1.1', function () { let validBidRequestsWithOzoneData = validBidRequests; validBidRequestsWithOzoneData[0].params.ozoneData = {'networkID': '3048', 'dfpSiteID': 'd.thesun', 'sectionID': 'homepage', 'path': '/', 'sec_id': 'null', 'sec': 'sec', 'topics': 'null', 'kw': 'null', 'aid': 'null', 'search': 'null', 'article_type': 'null', 'hide_ads': '', 'article_slug': 'null'}; - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); expect(request.data).to.be.a('string'); var data = JSON.parse(request.data); - expect(data.imp[0].ext.ozone.lotameData).to.be.an('object'); + expect(data.ext.ozone.lotameData).to.be.an('object'); expect(data.imp[0].ext.ozone.customData).to.be.an('array'); expect(data.imp[0].ext.ozone.ozoneData).to.be.undefined; expect(request).not.to.have.key('lotameData'); @@ -893,33 +2009,33 @@ describe('ozone Adapter', function () { }); it('has correct bidder', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); expect(request.bidderRequest.bids[0].bidder).to.equal(BIDDER_CODE); }); it('handles mediaTypes element correctly', function () { - const request = spec.buildRequests(validBidRequestsWithBannerMediaType, validBidderRequest); + const request = spec.buildRequests(validBidRequestsWithBannerMediaType, validBidderRequest.bidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); it('handles no ozone, lotame or custom data', function () { - const request = spec.buildRequests(validBidRequestsMinimal, validBidderRequest); + const request = spec.buildRequests(validBidRequestsMinimal, validBidderRequest.bidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); it('handles video mediaType element correctly, with outstream video', function () { - const request = spec.buildRequests(validBidRequestsWithNonBannerMediaTypesAndValidOutstreamVideo, validBidderRequest); + const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest.bidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); it('should not crash when there is no sizes element at all', function () { - const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); }); it('should be able to handle non-single requests', function () { config.setConfig({'ozone': {'singleRequest': false}}); - const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); expect(request).to.be.a('array'); expect(request[0]).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); // need to reset the singleRequest config flag: @@ -928,7 +2044,7 @@ describe('ozone Adapter', function () { it('should add gdpr consent information to the request when ozone is true', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest; + let bidderRequest = validBidderRequest.bidderRequest; bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: true, @@ -947,9 +2063,9 @@ describe('ozone Adapter', function () { }); // mirror - it('should add gdpr consent information to the request when ozone.oz_enforceGdpr is false and vendorData is missing vendorConsents (Mirror)', function () { + it('should add gdpr consent information to the request when vendorData is missing vendorConsents (Mirror)', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest; + let bidderRequest = validBidderRequest.bidderRequest; bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: true, @@ -964,43 +2080,9 @@ describe('ozone Adapter', function () { expect(payload.regs.ext.gdpr).to.equal(1); expect(payload.user.ext.consent).to.equal(consentString); }); - it('should add gdpr consent information to the request when ozone.oz_enforceGdpr is NOT PRESENT and vendorData is missing vendorConsents (Mirror)', function () { - let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest; - bidderRequest.gdprConsent = { - consentString: consentString, - gdprApplies: true, - vendorData: { - metadata: consentString, - gdprApplies: true - } - } - const request = spec.buildRequests(validBidRequestsNoSizes, bidderRequest); - const payload = JSON.parse(request.data); - expect(payload.regs.ext.gdpr).to.equal(1); - expect(payload.user.ext.consent).to.equal(consentString); - config.resetConfig(); - }); - it('should kill the auction request when ozone.oz_enforceGdpr is true & vendorData is missing vendorConsents (Mirror)', function () { - let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest; - bidderRequest.gdprConsent = { - consentString: consentString, - gdprApplies: true, - vendorData: { - metadata: consentString, - gdprApplies: true - } - } - config.setConfig({'ozone': {'oz_enforceGdpr': true}}); - const request = spec.buildRequests(validBidRequestsNoSizes, bidderRequest); - expect(request.length).to.equal(0); - config.resetConfig(); - }); - it('should set regs.ext.gdpr flag to 0 when gdprApplies is false', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest; + let bidderRequest = validBidderRequest.bidderRequest; bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: false, @@ -1019,7 +2101,7 @@ describe('ozone Adapter', function () { it('should not have imp[N].ext.ozone.userId', function () { let consentString = 'BOcocyaOcocyaAfEYDENCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NphLgA=='; - let bidderRequest = validBidderRequest; + let bidderRequest = validBidderRequest.bidderRequest; bidderRequest.gdprConsent = { consentString: consentString, gdprApplies: false, @@ -1036,10 +2118,10 @@ describe('ozone Adapter', function () { bidRequests[0]['userId'] = { 'criteortus': '1111', 'digitrustid': {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}, - 'id5id': '2222', + 'id5id': {'uid': '2222'}, 'idl_env': '3333', 'lipb': {'lipbid': '4444'}, - 'parrableid': 'eidVersion.encryptionKeyReference.encryptedValue', + 'parrableId': {eid: 'eidVersion.encryptionKeyReference.encryptedValue'}, 'pubcid': '5555', 'tdid': '6666' }; @@ -1056,21 +2138,21 @@ describe('ozone Adapter', function () { bidRequests[0]['userId'] = { 'criteortus': '1111', 'digitrustid': {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}, - 'id5id': '2222', + 'id5id': {'uid': '2222'}, 'idl_env': '3333', 'lipb': {'lipbid': '4444'}, - 'parrableid': 'eidVersion.encryptionKeyReference.encryptedValue', + 'parrableId': {eid: 'eidVersion.encryptionKeyReference.encryptedValue'}, // 'pubcid': '5555', // remove pubcid from here to emulate the OLD module & cause the failover code to kick in 'tdid': '6666' }; - const request = spec.buildRequests(bidRequests, validBidderRequest); + const request = spec.buildRequests(bidRequests, validBidderRequest.bidderRequest); const payload = JSON.parse(request.data); expect(payload.ext.ozone.pubcid).to.equal(bidRequests[0]['crumbs']['pubcid']); delete validBidRequests[0].userId; // tidy up now, else it will screw with other tests }); it('should add a user.ext.eids object to contain user ID data in the new location (Nov 2019)', function() { - const request = spec.buildRequests(validBidRequestsWithUserIdData, validBidderRequest); + const request = spec.buildRequests(validBidRequestsWithUserIdData, validBidderRequest.bidderRequest); const payload = JSON.parse(request.data); expect(payload.user).to.exist; expect(payload.user.ext).to.exist; @@ -1096,7 +2178,7 @@ describe('ozone Adapter', function () { spec.getGetParametersAsObject = function() { return {'oztestmode': 'mytestvalue_123'}; }; - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); const data = JSON.parse(request.data); expect(data.imp[0].ext.ozone.customData).to.be.an('array'); expect(data.imp[0].ext.ozone.customData[0].targeting.oztestmode).to.equal('mytestvalue_123'); @@ -1106,7 +2188,7 @@ describe('ozone Adapter', function () { spec.getGetParametersAsObject = function() { return {'oztestmode': 'mytestvalue_123'}; }; - const request = spec.buildRequests(validBidRequestsMinimal, validBidderRequest); + const request = spec.buildRequests(validBidRequestsMinimal, validBidderRequest.bidderRequest); const data = JSON.parse(request.data); expect(data.imp[0].ext.ozone.customData).to.be.an('array'); expect(data.imp[0].ext.ozone.customData[0].targeting.oztestmode).to.equal('mytestvalue_123'); @@ -1117,7 +2199,7 @@ describe('ozone Adapter', function () { specMock.getGetParametersAsObject = function() { return {'ozstoredrequest': '1122334455'}; // 10 digits are valid }; - const request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest); + const request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest.bidderRequest); const data = JSON.parse(request.data); expect(data.ext.ozone.oz_rw).to.equal(1); expect(data.imp[0].ext.prebid.storedrequest.id).to.equal('1122334455'); @@ -1127,7 +2209,7 @@ describe('ozone Adapter', function () { specMock.getGetParametersAsObject = function() { return {'ozstoredrequest': 'BADVAL'}; // 10 digits are valid }; - const request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest); + const request = specMock.buildRequests(validBidRequestsMinimal, validBidderRequest.bidderRequest); const data = JSON.parse(request.data); expect(data.ext.ozone.oz_rw).to.equal(0); expect(data.imp[0].ext.prebid.storedrequest.id).to.equal('1310000099'); @@ -1137,9 +2219,9 @@ describe('ozone Adapter', function () { spec.getGetParametersAsObject = function() { return {'oz_lotameid': '123abc', 'oz_lotamepid': 'pid123', 'oz_lotametpid': '123eee'}; }; - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); const payload = JSON.parse(request.data); - expect(payload.imp[0].ext.ozone.lotameData.Profile.Audiences.Audience[0].id).to.equal('123abc'); + expect(payload.ext.ozone.lotameData.Profile.Audiences.Audience[0].id).to.equal('123abc'); expect(payload.ext.ozone.oz_lot_rw).to.equal(1); }); it('should pick up the value of valid lotame override parameters when there is an empty lotame object', function () { @@ -1148,11 +2230,11 @@ describe('ozone Adapter', function () { spec.getGetParametersAsObject = function() { return {'oz_lotameid': '123abc', 'oz_lotamepid': 'pid123', 'oz_lotametpid': '123eeetpid'}; }; - const request = spec.buildRequests(nolotameBidReq, validBidderRequest); + const request = spec.buildRequests(nolotameBidReq, validBidderRequest.bidderRequest); const payload = JSON.parse(request.data); - expect(payload.imp[0].ext.ozone.lotameData.Profile.Audiences.Audience[0].id).to.equal('123abc'); - expect(payload.imp[0].ext.ozone.lotameData.Profile.tpid).to.equal('123eeetpid'); - expect(payload.imp[0].ext.ozone.lotameData.Profile.pid).to.equal('pid123'); + expect(payload.ext.ozone.lotameData.Profile.Audiences.Audience[0].id).to.equal('123abc'); + expect(payload.ext.ozone.lotameData.Profile.tpid).to.equal('123eeetpid'); + expect(payload.ext.ozone.lotameData.Profile.pid).to.equal('pid123'); expect(payload.ext.ozone.oz_lot_rw).to.equal(1); }); it('should pick up the value of valid lotame override parameters when there is NO "lotame" key at all', function () { @@ -1161,27 +2243,29 @@ describe('ozone Adapter', function () { spec.getGetParametersAsObject = function() { return {'oz_lotameid': '123abc', 'oz_lotamepid': 'pid123', 'oz_lotametpid': '123eeetpid'}; }; - const request = spec.buildRequests(nolotameBidReq, validBidderRequest); + const request = spec.buildRequests(nolotameBidReq, validBidderRequest.bidderRequest); const payload = JSON.parse(request.data); - expect(payload.imp[0].ext.ozone.lotameData.Profile.Audiences.Audience[0].id).to.equal('123abc'); - expect(payload.imp[0].ext.ozone.lotameData.Profile.tpid).to.equal('123eeetpid'); - expect(payload.imp[0].ext.ozone.lotameData.Profile.pid).to.equal('pid123'); + expect(payload.ext.ozone.lotameData.Profile.Audiences.Audience[0].id).to.equal('123abc'); + expect(payload.ext.ozone.lotameData.Profile.tpid).to.equal('123eeetpid'); + expect(payload.ext.ozone.lotameData.Profile.pid).to.equal('pid123'); expect(payload.ext.ozone.oz_lot_rw).to.equal(1); + spec.propertyBag = originalPropertyBag; // tidy up }); // NOTE - only one negative test case; // you can't send invalid lotame params to buildRequests because 'validate' will have rejected them it('should not use lotame override parameters if they dont exist', function () { + expect(spec.propertyBag.lotameWasOverridden).to.equal(0); spec.getGetParametersAsObject = function() { return {}; // no lotame override params }; - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); const payload = JSON.parse(request.data); expect(payload.ext.ozone.oz_lot_rw).to.equal(0); }); it('should pick up the config value of coppa & set it in the request', function () { config.setConfig({'coppa': true}); - const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); const payload = JSON.parse(request.data); expect(payload.regs).to.include.keys('coppa'); expect(payload.regs.coppa).to.equal(1); @@ -1189,22 +2273,75 @@ describe('ozone Adapter', function () { }); it('should pick up the config value of coppa & only set it in the request if its true', function () { config.setConfig({'coppa': false}); - const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); const payload = JSON.parse(request.data); expect(utils.deepAccess(payload, 'regs.coppa')).to.be.undefined; config.resetConfig(); }); + it('should handle oz_omp_floor correctly', function () { + config.setConfig({'ozone': {'oz_omp_floor': 1.56}}); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); + const payload = JSON.parse(request.data); + expect(utils.deepAccess(payload, 'ext.ozone.oz_omp_floor')).to.equal(1.56); + config.resetConfig(); + }); + it('should ignore invalid oz_omp_floor values', function () { + config.setConfig({'ozone': {'oz_omp_floor': '1.56'}}); + const request = spec.buildRequests(validBidRequestsNoSizes, validBidderRequest.bidderRequest); + const payload = JSON.parse(request.data); + expect(utils.deepAccess(payload, 'ext.ozone.oz_omp_floor')).to.be.undefined; + config.resetConfig(); + }); + it('should should contain a unique page view id in the auction request which persists across calls', function () { + let request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + let payload = JSON.parse(request.data); + expect(utils.deepAccess(payload, 'ext.ozone.pv')).to.be.a('string'); + request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest.bidderRequest); + let payload2 = JSON.parse(request.data); + expect(utils.deepAccess(payload2, 'ext.ozone.pv')).to.be.a('string'); + expect(utils.deepAccess(payload2, 'ext.ozone.pv')).to.equal(utils.deepAccess(payload, 'ext.ozone.pv')); + }); + it('should indicate that the whitelist was used when it contains valid data', function () { + config.setConfig({'ozone': {'oz_whitelist_adserver_keys': ['oz_ozappnexus_pb', 'oz_ozappnexus_imp_id']}}); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.ext.ozone.oz_kvp_rw).to.equal(1); + config.resetConfig(); + }); + it('should indicate that the whitelist was not used when it contains no data', function () { + config.setConfig({'ozone': {'oz_whitelist_adserver_keys': []}}); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.ext.ozone.oz_kvp_rw).to.equal(0); + config.resetConfig(); + }); + it('should indicate that the whitelist was not used when it is not set in the config', function () { + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.ext.ozone.oz_kvp_rw).to.equal(0); + }); + it('should have openrtb video params', function() { + let allowed = ['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']; + const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest.bidderRequest); + const payload = JSON.parse(request.data); + const vid = (payload.imp[0].video); + const keys = Object.keys(vid); + for (let i = 0; i < keys.length; i++) { + expect(allowed).to.include(keys[i]); + } + expect(payload.imp[0].video.ext).to.include({'context': 'outstream'}); + }); }); describe('interpretResponse', function () { it('should build bid array', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); const result = spec.interpretResponse(validResponse, request); expect(result.length).to.equal(1); }); it('should have all relevant fields', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); const result = spec.interpretResponse(validResponse, request); const bid = result[0]; expect(bid.cpm).to.equal(validResponse.body.seatbid[0].bid[0].cpm); @@ -1213,16 +2350,15 @@ describe('ozone Adapter', function () { }); it('should build bid array with gdpr', function () { - let validBR = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); + let validBR = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr.bidderRequest)); validBR.gdprConsent = {'gdprApplies': 1, 'consentString': 'This is the gdpr consent string'}; const request = spec.buildRequests(validBidRequests, validBR); // works the old way, with GDPR not enforced by default - // const request = spec.buildRequests(validBidRequests, bidderRequestWithFullGdpr); // works with oz_enforceGdpr true by default const result = spec.interpretResponse(validResponse, request); expect(result.length).to.equal(1); }); it('should build bid array with only partial gdpr', function () { - var validBidderRequestWithGdpr = bidderRequestWithPartialGdpr; + var validBidderRequestWithGdpr = bidderRequestWithPartialGdpr.bidderRequest; validBidderRequestWithGdpr.gdprConsent = {'gdprApplies': 1, 'consentString': 'This is the gdpr consent string'}; const request = spec.buildRequests(validBidRequests, validBidderRequestWithGdpr); }); @@ -1239,24 +2375,164 @@ describe('ozone Adapter', function () { expect(result).to.be.empty; }); - it('should have video renderer', function () { - const request = spec.buildRequests(validBidRequestsWithNonBannerMediaTypesAndValidOutstreamVideo, validBidderRequest); - const result = spec.interpretResponse(validOutstreamResponse, request); + it('should have video renderer for outstream video', function () { + const request = spec.buildRequests(validBidRequests1OutstreamVideo2020, validBidderRequest1OutstreamVideo2020.bidderRequest); + const result = spec.interpretResponse(getCleanValidVideoResponse(), validBidderRequest1OutstreamVideo2020); const bid = result[0]; expect(bid.renderer).to.be.an.instanceOf(Renderer); }); + it('should have NO video renderer for instream video', function () { + let instreamRequestsObj = JSON.parse(JSON.stringify(validBidRequests1OutstreamVideo2020)); + instreamRequestsObj[0].mediaTypes.video.context = 'instream'; + let instreamBidderReq = JSON.parse(JSON.stringify(validBidderRequest1OutstreamVideo2020)); + instreamBidderReq.bidderRequest.bids[0].mediaTypes.video.context = 'instream'; + const request = spec.buildRequests(instreamRequestsObj, validBidderRequest1OutstreamVideo2020.bidderRequest); + const result = spec.interpretResponse(getCleanValidVideoResponse(), instreamBidderReq); + const bid = result[0]; + expect(bid.hasOwnProperty('renderer')).to.be.false; + }); + it('should correctly parse response where there are more bidders than ad slots', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); const result = spec.interpretResponse(validBidResponse1adWith2Bidders, request); expect(result.length).to.equal(2); }); it('should have a ttl of 600', function () { - const request = spec.buildRequests(validBidRequests, validBidderRequest); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); const result = spec.interpretResponse(validResponse, request); expect(result[0].ttl).to.equal(300); }); + + it('should handle oz_omp_floor_dollars correctly, inserting 1 as necessary', function () { + config.setConfig({'ozone': {'oz_omp_floor': 0.01}}); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const result = spec.interpretResponse(validResponse, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_omp')).to.equal('1'); + config.resetConfig(); + }); + it('should handle oz_omp_floor_dollars correctly, inserting 0 as necessary', function () { + config.setConfig({'ozone': {'oz_omp_floor': 2.50}}); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const result = spec.interpretResponse(validResponse, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_omp')).to.equal('0'); + config.resetConfig(); + }); + it('should handle missing oz_omp_floor_dollars correctly, inserting nothing', function () { + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const result = spec.interpretResponse(validResponse, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_omp')).to.be.undefined; + }); + it('should handle ext.bidder.ozone.floor correctly, setting flr & rid as necessary', function () { + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + let vres = JSON.parse(JSON.stringify(validResponse)); + vres.body.seatbid[0].bid[0].ext.bidder.ozone = {floor: 1, ruleId: 'ZjbsYE1q'}; + const result = spec.interpretResponse(vres, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_flr')).to.equal(1); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_rid')).to.equal('ZjbsYE1q'); + config.resetConfig(); + }); + it('should handle ext.bidder.ozone.floor correctly, inserting 0 as necessary', function () { + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + let vres = JSON.parse(JSON.stringify(validResponse)); + vres.body.seatbid[0].bid[0].ext.bidder.ozone = {floor: 0, ruleId: 'ZjbXXE1q'}; + const result = spec.interpretResponse(vres, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_flr')).to.equal(0); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_rid')).to.equal('ZjbXXE1q'); + config.resetConfig(); + }); + it('should handle ext.bidder.ozone.floor correctly, inserting nothing as necessary', function () { + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + let vres = JSON.parse(JSON.stringify(validResponse)); + vres.body.seatbid[0].bid[0].ext.bidder.ozone = {}; + const result = spec.interpretResponse(vres, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_flr', null)).to.equal(null); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_rid', null)).to.equal(null); + config.resetConfig(); + }); + it('should handle ext.bidder.ozone.floor correctly, when bidder.ozone is not there', function () { + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + let vres = JSON.parse(JSON.stringify(validResponse)); + const result = spec.interpretResponse(vres, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_flr', null)).to.equal(null); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_rid', null)).to.equal(null); + config.resetConfig(); + }); + it('should handle a valid whitelist, removing items not on the list & leaving others', function () { + config.setConfig({'ozone': {'oz_whitelist_adserver_keys': ['oz_appnexus_crid', 'oz_appnexus_adId']}}); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const result = spec.interpretResponse(validResponse, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_adv')).to.be.undefined; + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_adId')).to.equal('2899ec066a91ff8-0-0'); + config.resetConfig(); + }); + it('should ignore a whitelist if enhancedAdserverTargeting is false', function () { + config.setConfig({'ozone': {'oz_whitelist_adserver_keys': ['oz_appnexus_crid', 'oz_appnexus_imp_id'], 'enhancedAdserverTargeting': false}}); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const result = spec.interpretResponse(validResponse, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_adv')).to.be.undefined; + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_imp_id')).to.be.undefined; + config.resetConfig(); + }); + it('should correctly handle enhancedAdserverTargeting being false', function () { + config.setConfig({'ozone': {'enhancedAdserverTargeting': false}}); + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const result = spec.interpretResponse(validResponse, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_adv')).to.be.undefined; + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_imp_id')).to.be.undefined; + config.resetConfig(); + }); + it('should add flr into ads request if floor exists in the auction response', function () { + const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest.bidderRequest); + let validres = JSON.parse(JSON.stringify(validResponse2Bids)); + validres.body.seatbid[0].bid[0].ext.bidder.ozone = {'floor': 1}; + const result = spec.interpretResponse(validres, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_flr')).to.equal(1); + expect(utils.deepAccess(result[1].adserverTargeting, 'oz_appnexus_flr', '')).to.equal(''); + }); + it('should add rid into ads request if ruleId exists in the auction response', function () { + const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest.bidderRequest); + let validres = JSON.parse(JSON.stringify(validResponse2Bids)); + validres.body.seatbid[0].bid[0].ext.bidder.ozone = {'ruleId': 123}; + const result = spec.interpretResponse(validres, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_appnexus_rid')).to.equal(123); + expect(utils.deepAccess(result[1].adserverTargeting, 'oz_appnexus_rid', '')).to.equal(''); + }); + it('should add oz_ozappnexus_sid (cid value) for all appnexus bids', function () { + const request = spec.buildRequests(validBidRequestsMulti, validBidderRequest.bidderRequest); + let validres = JSON.parse(JSON.stringify(validResponse2BidsSameAdunit)); + const result = spec.interpretResponse(validres, request); + expect(utils.deepAccess(result[0].adserverTargeting, 'oz_ozappnexus_sid')).to.equal(result[0].cid); + }); + it('should add unique adId values to each bid', function() { + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + let validres = JSON.parse(JSON.stringify(validResponse2BidsSameAdunit)); + const result = spec.interpretResponse(validres, request); + expect(result.length).to.equal(1); + expect(result[0]['price']).to.equal(0.9); + expect(result[0]['adserverTargeting']['oz_ozappnexus_adId']).to.equal('2899ec066a91ff8-0-1'); + }); + it('should correctly process an auction with 2 adunits & multiple bidders one of which bids for both adslots', function() { + let validres = JSON.parse(JSON.stringify(multiResponse1)); + let request = spec.buildRequests(multiRequest1, multiBidderRequest1.bidderRequest); + let result = spec.interpretResponse(validres, request); + expect(result.length).to.equal(4); // one of the 5 bids will have been removed + expect(result[1]['price']).to.equal(0.521); + expect(result[1]['impid']).to.equal('3025f169863b7f8'); + expect(result[1]['id']).to.equal('18552976939844999'); + expect(result[1]['adserverTargeting']['oz_ozappnexus_adId']).to.equal('3025f169863b7f8-0-2'); + // change the bid values so a different second bid for an impid by the same bidder gets dropped + validres = JSON.parse(JSON.stringify(multiResponse1)); + validres.body.seatbid[0].bid[1].price = 1.1; + validres.body.seatbid[0].bid[1].cpm = 1.1; + request = spec.buildRequests(multiRequest1, multiBidderRequest1.bidderRequest); + result = spec.interpretResponse(validres, request); + expect(result[1]['price']).to.equal(1.1); + expect(result[1]['impid']).to.equal('3025f169863b7f8'); + expect(result[1]['id']).to.equal('18552976939844681'); + expect(result[1]['adserverTargeting']['oz_ozappnexus_adId']).to.equal('3025f169863b7f8-0-1'); + }); }); describe('userSyncs', function () { @@ -1270,7 +2546,7 @@ describe('ozone Adapter', function () { }); it('should append the various values if they exist', function() { // get the cookie bag populated - spec.buildRequests(validBidRequests, validBidderRequest); + spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); const result = spec.getUserSyncs({iframeEnabled: true}, 'good server response', gdpr1); expect(result).to.be.an('array'); expect(result[0].url).to.include('publisherId=9876abcd12-3'); @@ -1383,83 +2659,7 @@ describe('ozone Adapter', function () { expect(result).to.be.false; config.resetConfig(); }); - it('should return true if oz_enforceGdpr is true and consentString is undefined', function() { - config.setConfig({'ozone': {'oz_enforceGdpr': true}}); - let req = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); - delete req.gdprConsent.consentString; - let result = spec.blockTheRequest(req); - expect(result).to.be.true; - config.resetConfig(); - }); - it('should return false if oz_enforceGdpr is false and consentString is undefined', function() { - config.setConfig({'ozone': {'oz_enforceGdpr': false}}); - let req = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); - delete req.gdprConsent.consentString; - let result = spec.blockTheRequest(req); - expect(result).to.be.false; - config.resetConfig(); - }); - it('should return false if oz_enforceGdpr is NOT SET (default) and consentString is undefined', function() { - let req = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); - delete req.gdprConsent.consentString; - let result = spec.blockTheRequest(req); - expect(result).to.be.false; - }); - it('should return false if gdprApplies is false', function() { - config.setConfig({'ozone': {'oz_request': true}}); - let req = {'gdprConsent': {'gdprApplies': false}}; - let result = spec.blockTheRequest(req); - expect(result).to.be.false; - config.resetConfig(); - }); - it('should return false if gdprConsent key does not exist', function() { - let req = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); - config.setConfig({'ozone': {'oz_enforceGdpr': true}}); - delete req.gdprConsent; - let result = spec.blockTheRequest(req); - expect(result).to.be.false; - config.resetConfig(); - }); - it('should return false if gdpr is set, and all is ok', function() { - let req = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); - config.setConfig({'ozone': {'oz_enforceGdpr': true}}); - let result = spec.blockTheRequest(req); - expect(result).to.be.false; - config.resetConfig(); - }); - }); - - describe('failsGdprCheck', function() { - it('should return false for a a fully accepted user', function () { - let result = spec.failsGdprCheck(bidderRequestWithFullGdpr); - expect(result).to.be.false; - }); - it('should return false if gdprConsent is not present on the bidder object', function () { - let result = spec.failsGdprCheck(validBidderRequest); - expect(result).to.be.false; - }); - it('should return true if gdpr applies and vendorData is not an array', function () { - let req = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); - req.gdprConsent.vendorData = null; - let result = spec.failsGdprCheck(req); - expect(result).to.be.true; - }); - it('should return true if gdpr applies and purposeConsents do not contain all the required true values', function () { - let req = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); - req.gdprConsent.vendorData.purposeConsents[1] = false; - let result = spec.failsGdprCheck(req); - expect(result).to.be.true; - }); - it('should return true if gdpr applies and vendorConsents[524] is not true', function () { - config.setConfig({'ozone': {'oz_enforceGdpr': true}}); - let req = JSON.parse(JSON.stringify(bidderRequestWithFullGdpr)); - req.gdprConsent.vendorData.vendorConsents[524] = false; - let result = spec.failsGdprCheck(req); - expect(result).to.be.true; - config.resetConfig(); - }); }); - describe('makeLotameObjectFromOverride', function() { it('should update an object with valid lotame data', function () { let objLotameOverride = {'oz_lotametpid': '1234', 'oz_lotameid': '12345', 'oz_lotamepid': '123456'}; @@ -1498,4 +2698,125 @@ describe('ozone Adapter', function () { expect(result).to.be.false; }); }); + describe('getPageId', function() { + it('should return the same Page ID for multiple calls', function () { + let result = spec.getPageId(); + expect(result).to.be.a('string'); + let result2 = spec.getPageId(); + expect(result2).to.equal(result); + }); + }); + describe('getBidRequestForBidId', function() { + it('should locate a bid inside a bid array', function () { + let result = spec.getBidRequestForBidId('2899ec066a91ff8', validBidRequestsMulti); + expect(result.testId).to.equal(1); + result = spec.getBidRequestForBidId('2899ec066a91ff0', validBidRequestsMulti); + expect(result.testId).to.equal(2); + }); + }); + describe('getVideoContextForBidId', function() { + it('should locate the video context inside a bid', function () { + let result = spec.getVideoContextForBidId('2899ec066a91ff8', validBidRequestsWithNonBannerMediaTypesAndValidOutstreamVideo); + expect(result).to.equal('outstream'); + }); + }); + describe('getLotameOverrideParams', function() { + it('should get 3 valid lotame params that exist in GET params', function () { + // mock the getGetParametersAsObject function to simulate GET parameters for lotame overrides: + spec.getGetParametersAsObject = function() { + return {'oz_lotameid': '123abc', 'oz_lotamepid': 'pid123', 'oz_lotametpid': 'tpid123'}; + }; + let result = spec.getLotameOverrideParams(); + expect(Object.keys(result).length).to.equal(3); + }); + it('should get only 1 valid lotame param that exists in GET params', function () { + // mock the getGetParametersAsObject function to simulate GET parameters for lotame overrides: + spec.getGetParametersAsObject = function() { + return {'oz_lotameid': '123abc', 'xoz_lotamepid': 'pid123', 'xoz_lotametpid': 'tpid123'}; + }; + let result = spec.getLotameOverrideParams(); + expect(Object.keys(result).length).to.equal(1); + }); + }); + describe('unpackVideoConfigIntoIABformat', function() { + it('should correctly unpack a usual video config', function () { + let mediaTypes = { + playerSize: [640, 480], + mimes: ['video/mp4'], + context: 'outstream', + testKey: 'parent value' + }; + let bid_params_video = { + skippable: true, + playback_method: ['auto_play_sound_off'], + playbackmethod: 2, /* start on load, no sound */ + minduration: 5, + maxduration: 60, + skipmin: 5, + skipafter: 5, + testKey: 'child value' + }; + let result = spec.unpackVideoConfigIntoIABformat(mediaTypes, bid_params_video); + expect(result.mimes).to.be.an('array').that.includes('video/mp4'); + expect(result.ext.context).to.equal('outstream'); + expect(result.ext.skippable).to.be.true; // note - we add skip in a different step: addVideoDefaults + expect(result.ext.testKey).to.equal('child value'); + }); + }); + describe('addVideoDefaults', function() { + it('should correctly add video defaults', function () { + let mediaTypes = { + playerSize: [640, 480], + mimes: ['video/mp4'], + context: 'outstream', + }; + let bid_params_video = { + skippable: true, + playback_method: ['auto_play_sound_off'], + playbackmethod: 2, /* start on load, no sound */ + minduration: 5, + maxduration: 60, + skipmin: 5, + skipafter: 5, + testKey: 'child value' + }; + let result = spec.addVideoDefaults({}, mediaTypes, mediaTypes); + expect(result.placement).to.equal(3); + expect(result.skip).to.equal(0); + result = spec.addVideoDefaults({}, mediaTypes, bid_params_video); + expect(result.skip).to.equal(1); + }); + it('should correctly add video defaults including skippable in parent', function () { + let mediaTypes = { + playerSize: [640, 480], + mimes: ['video/mp4'], + context: 'outstream', + skippable: true + }; + let bid_params_video = { + playback_method: ['auto_play_sound_off'], + playbackmethod: 2, /* start on load, no sound */ + minduration: 5, + maxduration: 60, + skipmin: 5, + skipafter: 5, + testKey: 'child value' + }; + let result = spec.addVideoDefaults({}, mediaTypes, bid_params_video); + expect(result.placement).to.equal(3); + expect(result.skip).to.equal(1); + }); + }); + describe('removeSingleBidderMultipleBids', function() { + it('should remove the multi bid by ozappnexus for adslot 2d30e86db743a8', function() { + let validres = JSON.parse(JSON.stringify(multiResponse1)); + expect(validres.body.seatbid[0].bid.length).to.equal(3); + expect(validres.body.seatbid[0].seat).to.equal('ozappnexus'); + let response = spec.removeSingleBidderMultipleBids(validres.body.seatbid); + expect(response.length).to.equal(2); + expect(response[0].bid.length).to.equal(2); + expect(response[0].seat).to.equal('ozappnexus'); + expect(response[1].bid.length).to.equal(2); + }); + }); }); diff --git a/test/spec/modules/padsquadBidAdapter_spec.js b/test/spec/modules/padsquadBidAdapter_spec.js index d30b1f34a9e..7d0858ed25e 100644 --- a/test/spec/modules/padsquadBidAdapter_spec.js +++ b/test/spec/modules/padsquadBidAdapter_spec.js @@ -212,6 +212,7 @@ describe('Padsquad bid adapter', function () { expect(bids[index]).to.have.property('height', RESPONSE.body.seatbid[0].bid[index].h); expect(bids[index]).to.have.property('ad', RESPONSE.body.seatbid[0].bid[index].adm); expect(bids[index]).to.have.property('creativeId', RESPONSE.body.seatbid[0].bid[index].crid); + expect(bids[index].meta.advertiserDomains).to.deep.equal(RESPONSE.body.seatbid[0].bid[index].adomain); expect(bids[index]).to.have.property('ttl', 30); expect(bids[index]).to.have.property('netRevenue', true); } diff --git a/test/spec/modules/parrableIdSystem_spec.js b/test/spec/modules/parrableIdSystem_spec.js index 0183a6f79d4..1cc89240bc3 100644 --- a/test/spec/modules/parrableIdSystem_spec.js +++ b/test/spec/modules/parrableIdSystem_spec.js @@ -1,4 +1,5 @@ import { expect } from 'chai'; +import find from 'core-js-pure/features/array/find.js'; import { config } from 'src/config.js'; import * as utils from 'src/utils.js'; import { newStorageManager } from 'src/storageManager.js'; @@ -11,151 +12,436 @@ import { server } from 'test/mocks/xhr.js'; const storage = newStorageManager(); const EXPIRED_COOKIE_DATE = 'Thu, 01 Jan 1970 00:00:01 GMT'; -const P_COOKIE_NAME = '_parrable_eid'; +const P_COOKIE_NAME = '_parrable_id'; const P_COOKIE_EID = '01.1563917337.test-eid'; const P_XHR_EID = '01.1588030911.test-new-eid' const P_CONFIG_MOCK = { name: 'parrableId', params: { partner: 'parrable_test_partner_123,parrable_test_partner_456' - }, - storage: { - name: '_parrable_eid', - type: 'cookie', - expires: 364 } }; -describe('Parrable ID System', function() { - function getConfigMock() { - return { - userSync: { - syncDelay: 0, - userIds: [P_CONFIG_MOCK] - } +function getConfigMock() { + return { + userSync: { + syncDelay: 0, + userIds: [P_CONFIG_MOCK] } } +} + +function getAdUnitMock(code = 'adUnit-code') { + return { + code, + mediaTypes: {banner: {}, native: {}}, + sizes: [ + [300, 200], + [300, 600] + ], + bids: [{ + bidder: 'sampleBidder', + params: { placementId: 'banner-only-bidder' } + }] + }; +} - function getAdUnitMock(code = 'adUnit-code') { - return { - code, - mediaTypes: {banner: {}, native: {}}, - sizes: [ - [300, 200], - [300, 600] - ], - bids: [{ - bidder: 'sampleBidder', - params: { placementId: 'banner-only-bidder' } - }] - }; +function serializeParrableId(parrableId) { + let str = ''; + if (parrableId.eid) { + str += 'eid:' + parrableId.eid; + } + if (parrableId.ibaOptout) { + str += ',ibaOptout:1'; } + if (parrableId.ccpaOptout) { + str += ',ccpaOptout:1'; + } + return str; +} + +function writeParrableCookie(parrableId) { + let cookieValue = encodeURIComponent(serializeParrableId(parrableId)); + storage.setCookie( + P_COOKIE_NAME, + cookieValue, + (new Date(Date.now() + 5000).toUTCString()), + 'lax' + ); +} + +function removeParrableCookie() { + storage.setCookie(P_COOKIE_NAME, '', EXPIRED_COOKIE_DATE); +} +describe('Parrable ID System', function() { describe('parrableIdSystem.getId()', function() { - let callbackSpy = sinon.spy(); + describe('response callback function', function() { + let logErrorStub; + let callbackSpy = sinon.spy(); - beforeEach(function() { - callbackSpy.resetHistory(); - }); + beforeEach(function() { + logErrorStub = sinon.stub(utils, 'logError'); + callbackSpy.resetHistory(); + writeParrableCookie({ eid: P_COOKIE_EID }); + }); + + afterEach(function() { + removeParrableCookie(); + logErrorStub.restore(); + }) + + it('creates xhr to Parrable that synchronizes the ID', function() { + let getIdResult = parrableIdSubmodule.getId(P_CONFIG_MOCK.params); + + getIdResult.callback(callbackSpy); + + let request = server.requests[0]; + let queryParams = utils.parseQS(request.url.split('?')[1]); + let data = JSON.parse(atob(queryParams.data)); + + expect(getIdResult.callback).to.be.a('function'); + expect(request.url).to.contain('h.parrable.com'); + + expect(queryParams).to.not.have.property('us_privacy'); + expect(data).to.deep.equal({ + eid: P_COOKIE_EID, + trackers: P_CONFIG_MOCK.params.partner.split(','), + url: getRefererInfo().referer + }); + + server.requests[0].respond(200, + { 'Content-Type': 'text/plain' }, + JSON.stringify({ eid: P_XHR_EID }) + ); + + expect(callbackSpy.lastCall.lastArg).to.deep.equal({ + eid: P_XHR_EID + }); + + expect(storage.getCookie(P_COOKIE_NAME)).to.equal( + encodeURIComponent('eid:' + P_XHR_EID) + ); + }); - it('returns a callback used to refresh the ID', function() { - let getIdResponse = parrableIdSubmodule.getId( - P_CONFIG_MOCK.params, - null, - P_COOKIE_EID - ); - expect(getIdResponse.callback).to.be.a('function'); + it('xhr passes the uspString to Parrable', function() { + let uspString = '1YNN'; + uspDataHandler.setConsentData(uspString); + parrableIdSubmodule.getId( + P_CONFIG_MOCK.params, + null, + null + ).callback(callbackSpy); + uspDataHandler.setConsentData(null); + expect(server.requests[0].url).to.contain('us_privacy=' + uspString); + }); + + it('should log an error and continue to callback if ajax request errors', function () { + let callBackSpy = sinon.spy(); + let submoduleCallback = parrableIdSubmodule.getId({partner: 'prebid'}).callback; + submoduleCallback(callBackSpy); + let request = server.requests[0]; + expect(request.url).to.contain('h.parrable.com'); + request.respond( + 503, + null, + 'Unavailable' + ); + expect(logErrorStub.calledOnce).to.be.true; + expect(callBackSpy.calledOnce).to.be.true; + }); }); - it('callback creates xhr to Parrable that synchronizes the ID', function() { - let getIdCallback = parrableIdSubmodule.getId( - P_CONFIG_MOCK.params, - null, - P_COOKIE_EID - ).callback; + describe('response id', function() { + it('provides the stored Parrable values if a cookie exists', function() { + writeParrableCookie({ eid: P_COOKIE_EID }); + let getIdResult = parrableIdSubmodule.getId(P_CONFIG_MOCK.params); + removeParrableCookie(); + + expect(getIdResult.id).to.deep.equal({ + eid: P_COOKIE_EID + }); + }); - getIdCallback(callbackSpy); + it('provides the stored legacy Parrable ID values if cookies exist', function() { + let oldEid = '01.111.old-eid'; + let oldEidCookieName = '_parrable_eid'; + let oldOptoutCookieName = '_parrable_optout'; - let request = server.requests[0]; - let queryParams = utils.parseQS(request.url.split('?')[1]); - let data = JSON.parse(atob(queryParams.data)); + storage.setCookie(oldEidCookieName, oldEid); + storage.setCookie(oldOptoutCookieName, 'true'); - expect(request.url).to.contain('h.parrable.com'); - expect(queryParams).to.not.have.property('us_privacy'); - expect(data).to.deep.equal({ - eid: P_COOKIE_EID, - trackers: P_CONFIG_MOCK.params.partner.split(','), - url: getRefererInfo().referer + let getIdResult = parrableIdSubmodule.getId(P_CONFIG_MOCK.params); + expect(getIdResult.id).to.deep.equal({ + eid: oldEid, + ibaOptout: true + }); + + // The ID system is expected to migrate old cookies to the new format + expect(storage.getCookie(P_COOKIE_NAME)).to.equal( + encodeURIComponent('eid:' + oldEid + ',ibaOptout:1') + ); + expect(storage.getCookie(oldEidCookieName)).to.equal(null); + expect(storage.getCookie(oldOptoutCookieName)).to.equal(null); + removeParrableCookie(); }); + }); + }); + + describe('parrableIdSystem.decode()', function() { + it('provides the Parrable ID (EID) from a stored object', function() { + let eid = '01.123.4567890'; + let parrableId = { + eid, + ibaOptout: true + }; + + expect(parrableIdSubmodule.decode(parrableId)).to.deep.equal({ + parrableId + }); + }); + }); + + describe('timezone filtering', function() { + before(function() { + sinon.stub(Intl, 'DateTimeFormat'); + }); + + after(function() { + Intl.DateTimeFormat.restore(); + }); + + it('permits an impression when no timezoneFilter is configured', function() { + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + })).to.have.property('callback'); + }); - server.requests[0].respond(200, - { 'Content-Type': 'text/plain' }, - JSON.stringify({ eid: P_XHR_EID }) - ); + it('permits an impression from a blocked timezone when a cookie exists', function() { + const blockedZone = 'Antarctica/South_Pole'; + const resolvedOptions = sinon.stub().returns({ timeZone: blockedZone }); + Intl.DateTimeFormat.returns({ resolvedOptions }); - expect(callbackSpy.calledWith(P_XHR_EID)).to.be.true; + writeParrableCookie({ eid: P_COOKIE_EID }); + + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + timezoneFilter: { + blockedZones: [ blockedZone ] + } + })).to.have.property('callback'); + expect(resolvedOptions.called).to.equal(false); + + removeParrableCookie(); + }) + + it('permits an impression from an allowed timezone', function() { + const allowedZone = 'America/New_York'; + const resolvedOptions = sinon.stub().returns({ timeZone: allowedZone }); + Intl.DateTimeFormat.returns({ resolvedOptions }); + + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + timezoneFilter: { + allowedZones: [ allowedZone ] + } + })).to.have.property('callback'); + expect(resolvedOptions.called).to.equal(true); }); - it('passes the uspString to Parrable', function() { - let uspString = '1YNN'; - uspDataHandler.setConsentData(uspString); - parrableIdSubmodule.getId( - P_CONFIG_MOCK.params, - null, - P_COOKIE_EID - ).callback(callbackSpy); - expect(server.requests[0].url).to.contain('us_privacy=' + uspString); + it('permits an impression from a timezone that is not blocked', function() { + const blockedZone = 'America/New_York'; + const resolvedOptions = sinon.stub().returns({ timeZone: 'Iceland' }); + Intl.DateTimeFormat.returns({ resolvedOptions }); + + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + timezoneFilter: { + blockedZones: [ blockedZone ] + } + })).to.have.property('callback'); + expect(resolvedOptions.called).to.equal(true); + }); + + it('does not permit an impression from a blocked timezone', function() { + const blockedZone = 'America/New_York'; + const resolvedOptions = sinon.stub().returns({ timeZone: blockedZone }); + Intl.DateTimeFormat.returns({ resolvedOptions }); + + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + timezoneFilter: { + blockedZones: [ blockedZone ] + } + })).to.equal(null); + expect(resolvedOptions.called).to.equal(true); + }); + + it('does not permit an impression from a blocked timezone even when also allowed', function() { + const timezone = 'America/New_York'; + const resolvedOptions = sinon.stub().returns({ timeZone: timezone }); + Intl.DateTimeFormat.returns({ resolvedOptions }); + + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + timezoneFilter: { + allowedZones: [ timezone ], + blockedZones: [ timezone ] + } + })).to.equal(null); + expect(resolvedOptions.called).to.equal(true); }); }); - describe('Parrable ID in Bid Request', function() { + describe('timezone offset filtering', function() { + before(function() { + sinon.stub(Date.prototype, 'getTimezoneOffset'); + }); + + afterEach(function() { + Date.prototype.getTimezoneOffset.reset(); + }) + + after(function() { + Date.prototype.getTimezoneOffset.restore(); + }); + + it('permits an impression from a blocked offset when a cookie exists', function() { + const blockedOffset = -4; + Date.prototype.getTimezoneOffset.returns(blockedOffset * 60); + + writeParrableCookie({ eid: P_COOKIE_EID }); + + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + timezoneFilter: { + blockedOffsets: [ blockedOffset ] + } + })).to.have.property('callback'); + + removeParrableCookie(); + }); + + it('permits an impression from an allowed offset', function() { + const allowedOffset = -5; + Date.prototype.getTimezoneOffset.returns(allowedOffset * 60); + + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + timezoneFilter: { + allowedOffsets: [ allowedOffset ] + } + })).to.have.property('callback'); + expect(Date.prototype.getTimezoneOffset.called).to.equal(true); + }); + + it('permits an impression from an offset that is not blocked', function() { + const allowedOffset = -5; + const blockedOffset = 5; + Date.prototype.getTimezoneOffset.returns(allowedOffset * 60); + + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + timezoneFilter: { + blockedOffsets: [ blockedOffset ] + } + })).to.have.property('callback'); + expect(Date.prototype.getTimezoneOffset.called).to.equal(true); + }); + + it('does not permit an impression from a blocked offset', function() { + const blockedOffset = -5; + Date.prototype.getTimezoneOffset.returns(blockedOffset * 60); + + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + timezoneFilter: { + blockedOffsets: [ blockedOffset ] + } + })).to.equal(null); + expect(Date.prototype.getTimezoneOffset.called).to.equal(true); + }); + + it('does not permit an impression from a blocked offset even when also allowed', function() { + const offset = -5; + Date.prototype.getTimezoneOffset.returns(offset * 60); + + expect(parrableIdSubmodule.getId({ + partner: 'prebid-test', + timezoneFilter: { + allowedOffset: [ offset ], + blockedOffsets: [ offset ] + } + })).to.equal(null); + expect(Date.prototype.getTimezoneOffset.called).to.equal(true); + }); + }); + + describe('userId requestBids hook', function() { let adUnits; - let logErrorStub; beforeEach(function() { adUnits = [getAdUnitMock()]; - // simulate existing browser local storage values - storage.setCookie( - P_COOKIE_NAME, - P_COOKIE_EID, - (new Date(Date.now() + 5000).toUTCString()) - ); + writeParrableCookie({ eid: P_COOKIE_EID, ibaOptout: true }); setSubmoduleRegistry([parrableIdSubmodule]); init(config); config.setConfig(getConfigMock()); - logErrorStub = sinon.stub(utils, 'logError'); }); afterEach(function() { + removeParrableCookie(); storage.setCookie(P_COOKIE_NAME, '', EXPIRED_COOKIE_DATE); - logErrorStub.restore(); }); - it('provides the parrableid in the bid request', function(done) { + it('when a stored Parrable ID exists it is added to bids', function(done) { requestBidsHook(function() { adUnits.forEach(unit => { unit.bids.forEach(bid => { - expect(bid).to.have.deep.nested.property('userId.parrableid'); - expect(bid.userId.parrableid).to.equal(P_COOKIE_EID); + expect(bid).to.have.deep.nested.property('userId.parrableId'); + expect(bid.userId.parrableId.eid).to.equal(P_COOKIE_EID); + expect(bid.userId.parrableId.ibaOptout).to.equal(true); + const parrableIdAsEid = find(bid.userIdAsEids, e => e.source == 'parrable.com'); + expect(parrableIdAsEid).to.deep.equal({ + source: 'parrable.com', + uids: [{ + id: P_COOKIE_EID, + atype: 1, + ext: { + ibaOptout: true + } + }] + }); }); }); done(); }, { adUnits }); }); - it('should log an error and continue to callback if ajax request errors', function () { - let callBackSpy = sinon.spy(); - let submoduleCallback = parrableIdSubmodule.getId({partner: 'prebid'}).callback; - submoduleCallback(callBackSpy); - let request = server.requests[0]; - expect(request.url).to.contain('h.parrable.com'); - request.respond( - 503, - null, - 'Unavailable' - ); - expect(logErrorStub.calledOnce).to.be.true; - expect(callBackSpy.calledOnce).to.be.true; + it('supplies an optout reason when the EID is missing due to CCPA non-consent', function(done) { + // the ID system itself will not write a cookie with an EID when CCPA=true + writeParrableCookie({ ccpaOptout: true }); + + requestBidsHook(function() { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.parrableId'); + expect(bid.userId.parrableId).to.not.have.property('eid'); + expect(bid.userId.parrableId.ccpaOptout).to.equal(true); + const parrableIdAsEid = find(bid.userIdAsEids, e => e.source == 'parrable.com'); + expect(parrableIdAsEid).to.deep.equal({ + source: 'parrable.com', + uids: [{ + id: '', + atype: 1, + ext: { + ccpaOptout: true + } + }] + }); + }); + }); + done(); + }, { adUnits }); }); }); }); diff --git a/test/spec/modules/performaxBidAdapter_spec.js b/test/spec/modules/performaxBidAdapter_spec.js new file mode 100644 index 00000000000..43c256b9d13 --- /dev/null +++ b/test/spec/modules/performaxBidAdapter_spec.js @@ -0,0 +1,274 @@ +import * as utils from 'src/utils.js'; +import { expect } from 'chai'; +import { spec } from 'modules/performaxBidAdapter'; + +describe('PerformaxAdapter', function () { + let bidRequests, bidderRequest; + let serverResponse, serverRequest; + + const URL = + 'https://dale.performax.cz/hb?slotId[]=3,2&client=hellboy:v0.0.1&auctionId=144b5079-8cbf-49a5-aca7-a68b3296cd6c'; + + bidRequests = [ + { + adUnitCode: 'postbid_iframe', + auctionId: '144b5079-8cbf-49a5-aca7-a68b3296cd6c', + bidId: '2a4332f6b2bc74', + bidRequestsCount: 1, + bidder: 'performax', + bidderRequestId: '1c7d8bf204f11e', + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { + banner: { + sizes: [[300, 300]], + }, + }, + params: { + slotId: 3, + }, + sizes: [[300, 300]], + src: 'client', + transactionId: '14969d09-0068-4d5b-a34e-e35091561dee', + }, + { + adUnitCode: 'postbid_iframe2', + auctionId: '144b5079-8cbf-49a5-aca7-a68b3296cd6c', + bidId: '300bb0ac6a156a', + bidRequestsCount: 1, + bidder: 'performax', + bidderRequestId: '1c7d8bf204f11e', + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { + banner: { + sizes: [[300, 300]], + }, + }, + params: { + slotId: 2, + }, + sizes: [[300, 300]], + src: 'client', + transactionId: '107cbebd-8c36-4456-b28c-91a19ba80151', + }, + ]; + + bidderRequest = { + auctionId: '144b5079-8cbf-49a5-aca7-a68b3296cd6c', + auctionStart: 1594281941845, + bidderCode: 'performax', + bidderRequestId: '1c7d8bf204f11e', + bids: bidRequests, + refererInfo: { + canonicalUrl: '', + numIframes: 0, + reachedTop: true, + referer: '', + }, + stack: [''], + start: 1594281941935, + timeout: 3600, + }; + + serverResponse = { + body: [ + { + ad: { + code: '$SYS_ID$ $VAR_NAME$ rest of the code', + data: { + SYS_ID: 1, + VAR_NAME: 'name', + }, + format_id: 2, + id: 11, + size: { + width: 300, + height: 300, + }, + tag_ids: [], + type: 'creative', + }, + cpm: 30, + creativeId: 'creative:11', + currency: 'CZK', + height: 300, + meta: { + agencyId: 1, + mediaType: 'banner', + }, + netRevenue: true, + requestId: '2a4332f6b2bc74', + ttl: 60, + width: 300, + }, + { + ad: { + code: '', + reason: 'Slot 2 does not allow HB requests', + type: 'empty', + }, + cpm: 0, + creativeId: null, + currency: 'CZK', + height: null, + meta: { + agencyId: null, + mediaType: 'banner', + }, + netRevenue: true, + requestId: '1c7d8bf204f11e', + ttl: 60, + width: 300, + }, + ], + }; + + serverRequest = { + data: { + bidderRequest: bidderRequest, + validBidRequests: bidRequests, + }, + method: 'POST', + options: { + contentType: 'application/json', + }, + url: URL, + }; + + describe('Bid validations', function () { + it('Valid bid', function () { + let validBid = { + bidder: 'performax', + params: { + slotId: 2, + }, + }, + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(true); + }); + + it('Invalid bid: required param is missing', function () { + let invalidBid = { + bidder: 'performax', + params: { + invalidParam: 2, + }, + }, + isValid = spec.isBidRequestValid(invalidBid); + expect(isValid).to.equal(false); + }); + }); + + describe('Build Url', function () { + it('Should return url', function () { + let url = spec.buildUrl(bidRequests, bidderRequest); + expect(url).to.equal(URL); + }); + }); + + describe('Build Request', function () { + it('Should not modify bidRequests and bidder Requests', function () { + let originalBidRequests = utils.deepClone(bidRequests); + let originalBidderRequest = utils.deepClone(bidderRequest); + let request = spec.buildRequests(bidRequests, bidderRequest); + + expect(bidRequests).to.deep.equal(originalBidRequests); + expect(bidderRequest).to.deep.equal(originalBidderRequest); + }); + + it('Endpoint checking', function () { + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.url).to.equal(URL); + expect(request.method).to.equal('POST'); + expect(request.options).to.deep.equal({ + contentType: 'application/json', + }); + }); + + it('Request params checking', function () { + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.validBidRequests).to.deep.equal(bidRequests); + expect(request.data.bidderRequest).to.deep.equal(bidderRequest); + }); + }); + + describe('Build Html', function () { + it('Ad with data: should return build html', function () { + let validAd = { + code: '$SYS_ID$ $VAR_NAME$ rest of the code', + data: { + SYS_ID: 1, + VAR_NAME: 'name', + }, + format_id: 2, + id: 11, + size: { + width: 300, + height: 300, + }, + tag_ids: [], + type: 'creative', + }; + let html = spec.buildHtml(validAd); + expect(html).to.equal('1 name rest of the code'); + }); + + it('Ad with partial data: should return html without data change', function () { + let adWithPartialData = { + code: '$SYS_ID$ $VAR_NAME$ rest of the code', + data: { + VAR_NAME: 'name', + }, + format_id: 2, + id: 11, + size: { + width: 300, + height: 300, + }, + tag_ids: [], + type: 'creative', + }; + let html = spec.buildHtml(adWithPartialData); + expect(html).to.equal('$SYS_ID$ name rest of the code'); + }); + + it('Ad without data: should return html without data change', function () { + let adWithoutData = { + code: '$SYS_ID$ $VAR_NAME$ rest of the code', + format_id: 2, + id: 11, + size: { + width: 300, + height: 300, + }, + tag_ids: [], + type: 'creative', + }; + let html = spec.buildHtml(adWithoutData); + expect(html).to.equal('$SYS_ID$ $VAR_NAME$ rest of the code'); + }); + }); + + describe('Interpret Response', function () { + it('Ad without data: should return html without data change', function () { + let ads = spec.interpretResponse(serverResponse, serverRequest); + expect(ads).to.have.length(1); + expect(ads[0]).to.deep.equal({ + ad: '1 name rest of the code', + cpm: 30, + creativeId: 'creative:11', + currency: 'CZK', + height: 300, + meta: { + agencyId: 1, + mediaType: 'banner', + }, + netRevenue: true, + requestId: '2a4332f6b2bc74', + ttl: 60, + width: 300, + }); + }); + }); +}); diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 4744bef0ee3..d069bb74944 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { PrebidServer as Adapter, resetSyncedStatus } from 'modules/prebidServerBidAdapter/index.js'; +import { PrebidServer as Adapter, resetSyncedStatus, resetWurlMap } from 'modules/prebidServerBidAdapter/index.js'; import adapterManager from 'src/adapterManager.js'; import * as utils from 'src/utils.js'; import { ajax } from 'src/ajax.js'; @@ -261,7 +261,12 @@ const RESPONSE_OPENRTB = { 'w': 300, 'h': 250, 'ext': { - 'prebid': { 'type': 'banner' }, + 'prebid': { + 'type': 'banner', + 'event': { + 'win': 'http://wurl.org?id=333' + } + }, 'bidder': { 'appnexus': { 'brand_id': 1, @@ -304,6 +309,7 @@ const RESPONSE_OPENRTB_VIDEO = { ext: { prebid: { type: 'video', + bidid: '654321' }, bidder: { appnexus: { @@ -432,6 +438,7 @@ describe('S2S Adapter', function () { done = sinon.spy(); beforeEach(function () { + config.resetConfig(); adapter = new Adapter(); BID_REQUESTS = [ { @@ -481,17 +488,16 @@ describe('S2S Adapter', function () { done.resetHistory(); }); + after(function () { + config.resetConfig(); + }); + describe('request function', function () { beforeEach(function () { - config.resetConfig(); resetSyncedStatus(); }); - afterEach(function () { - config.resetConfig(); - }); - - it('should not add outstrean without renderer', function () { + it('should not add outstream without renderer', function () { let ortb2Config = utils.deepClone(CONFIG); ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; @@ -503,13 +509,28 @@ describe('S2S Adapter', function () { expect(requestBid.imp[0].video).to.not.exist; }); + it('should default video placement if not defined and instream', function () { + let ortb2Config = utils.deepClone(CONFIG); + ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; + + config.setConfig({ s2sConfig: ortb2Config }); + + let videoBid = utils.deepClone(VIDEO_REQUEST); + videoBid.ad_units[0].mediaTypes.video.context = 'instream'; + adapter.callBids(videoBid, BID_REQUESTS, addBidResponse, done, ajax); + + const requestBid = JSON.parse(server.requests[0].requestBody); + expect(requestBid.imp[0].banner).to.not.exist; + expect(requestBid.imp[0].video).to.exist; + expect(requestBid.imp[0].video.placement).to.equal(1); + }); + it('exists and is a function', function () { expect(adapter.callBids).to.exist.and.to.be.a('function'); }); describe('gdpr tests', function () { afterEach(function () { - config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); }); @@ -542,6 +563,37 @@ describe('S2S Adapter', function () { expect(requestBid.user).to.not.exist; }); + it('adds additional consent information to ortb2 request depending on presence of module', function () { + let ortb2Config = utils.deepClone(CONFIG); + ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; + + let consentConfig = { consentManagement: { cmpApi: 'iab' }, s2sConfig: ortb2Config }; + config.setConfig(consentConfig); + + let gdprBidRequest = utils.deepClone(BID_REQUESTS); + gdprBidRequest[0].gdprConsent = { + consentString: 'abc123', + addtlConsent: 'superduperconsent', + gdprApplies: true + }; + + adapter.callBids(REQUEST, gdprBidRequest, addBidResponse, done, ajax); + let requestBid = JSON.parse(server.requests[0].requestBody); + + expect(requestBid.regs.ext.gdpr).is.equal(1); + expect(requestBid.user.ext.consent).is.equal('abc123'); + expect(requestBid.user.ext.ConsentedProvidersSettings.consented_providers).is.equal('superduperconsent'); + + config.resetConfig(); + config.setConfig({ s2sConfig: CONFIG }); + + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + requestBid = JSON.parse(server.requests[1].requestBody); + + expect(requestBid.regs).to.not.exist; + expect(requestBid.user).to.not.exist; + }); + it('check gdpr info gets added into cookie_sync request: have consent data', function () { let cookieSyncConfig = utils.deepClone(CONFIG); cookieSyncConfig.syncEndpoint = 'https://prebid.adnxs.com/pbs/v1/cookie_sync'; @@ -608,7 +660,6 @@ describe('S2S Adapter', function () { describe('us_privacy (ccpa) consent data', function () { afterEach(function () { - config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); }); @@ -653,7 +704,6 @@ describe('S2S Adapter', function () { describe('gdpr and us_privacy (ccpa) consent data', function () { afterEach(function () { - config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); }); @@ -709,40 +759,6 @@ describe('S2S Adapter', function () { }); }); - it('adds digitrust id is present and user is not optout', function () { - let ortb2Config = utils.deepClone(CONFIG); - ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; - - let consentConfig = { s2sConfig: ortb2Config }; - config.setConfig(consentConfig); - - let digiTrustObj = { - privacy: { - optout: false - }, - id: 'testId', - keyv: 'testKeyV' - }; - - let digiTrustBidRequest = utils.deepClone(BID_REQUESTS); - digiTrustBidRequest[0].bids[0].userId = { digitrustid: { data: digiTrustObj } }; - - adapter.callBids(REQUEST, digiTrustBidRequest, addBidResponse, done, ajax); - let requestBid = JSON.parse(server.requests[0].requestBody); - - expect(requestBid.user.ext.digitrust).to.deep.equal({ - id: digiTrustObj.id, - keyv: digiTrustObj.keyv - }); - - digiTrustObj.privacy.optout = true; - - adapter.callBids(REQUEST, digiTrustBidRequest, addBidResponse, done, ajax); - requestBid = JSON.parse(server.requests[1].requestBody); - - expect(requestBid.user && request.user.ext && requestBid.user.ext.digitrust).to.not.exist; - }); - it('adds device and app objects to request', function () { const _config = { s2sConfig: CONFIG, @@ -922,7 +938,7 @@ describe('S2S Adapter', function () { expect(requestBid.site.content.language).to.exist.and.to.be.a('string'); expect(requestBid.site).to.deep.equal({ publisher: { - id: '1', + id: '1234', domain: 'test.com' }, content: { @@ -955,6 +971,7 @@ describe('S2S Adapter', function () { aliases: { brealtime: 'appnexus' }, + auctiontimestamp: 1510852447530, targeting: { includebidderkeys: false, includewinners: true @@ -989,6 +1006,7 @@ describe('S2S Adapter', function () { aliases: { [alias]: 'appnexus' }, + auctiontimestamp: 1510852447530, targeting: { includebidderkeys: false, includewinners: true @@ -1090,6 +1108,59 @@ describe('S2S Adapter', function () { expect(requestBid.imp[0].ext.appnexus.key).to.be.equal('value') }); + describe('config site value is added to the oRTB request', function () { + const s2sConfig = Object.assign({}, CONFIG, { + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction', + adapterOptions: { + appnexus: { + key: 'value' + } + } + }); + const device = { + ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', + ip: '75.97.0.47' + }; + + it('and overrides publisher and page', function () { + config.setConfig({ + s2sConfig: s2sConfig, + site: { + domain: 'nytimes.com', + page: 'http://www.nytimes.com', + publisher: { id: '2' } + }, + device: device + }); + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + const requestBid = JSON.parse(server.requests[0].requestBody); + + expect(requestBid.site).to.exist.and.to.be.a('object'); + expect(requestBid.site.domain).to.equal('nytimes.com'); + expect(requestBid.site.page).to.equal('http://www.nytimes.com'); + expect(requestBid.site.publisher).to.exist.and.to.be.a('object'); + expect(requestBid.site.publisher.id).to.equal('2'); + }); + + it('and merges domain and page with the config site value', function () { + config.setConfig({ + s2sConfig: s2sConfig, + site: { + foo: 'bar' + }, + device: device + }); + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + + const requestBid = JSON.parse(server.requests[0].requestBody); + expect(requestBid.site).to.exist.and.to.be.a('object'); + expect(requestBid.site.foo).to.equal('bar'); + expect(requestBid.site.page).to.equal('http://mytestpage.com'); + expect(requestBid.site.publisher).to.exist.and.to.be.a('object'); + expect(requestBid.site.publisher.id).to.equal('1'); + }); + }); + it('when userId is defined on bids, it\'s properties should be copied to user.ext.tpid properties', function () { let ortb2Config = utils.deepClone(CONFIG); ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; @@ -1102,12 +1173,18 @@ describe('S2S Adapter', function () { criteoId: '44VmRDeUE3ZGJ5MzRkRVJHU3BIUlJ6TlFPQUFU', tdid: 'abc123', pubcid: '1234', - parrableid: '01.1563917337.test-eid', + parrableId: { eid: '01.1563917337.test-eid' }, lipb: { lipbid: 'li-xyz', segments: ['segA', 'segB'] }, - idl_env: '0000-1111-2222-3333' + idl_env: '0000-1111-2222-3333', + id5id: { + uid: '11111', + ext: { + linkType: 'some-link-type' + } + } }; userIdBidRequest[0].bids[0].userIdAsEids = createEidsArray(userIdBidRequest[0].bids[0].userId); @@ -1128,6 +1205,9 @@ describe('S2S Adapter', function () { expect(requestBid.user.ext.eids.filter(eid => eid.source === 'liveintent.com')[0].ext.segments.length).is.equal(2); expect(requestBid.user.ext.eids.filter(eid => eid.source === 'liveintent.com')[0].ext.segments[0]).is.equal('segA'); expect(requestBid.user.ext.eids.filter(eid => eid.source === 'liveintent.com')[0].ext.segments[1]).is.equal('segB'); + expect(requestBid.user.ext.eids.filter(eid => eid.source === 'id5-sync.com')).is.not.empty; + expect(requestBid.user.ext.eids.filter(eid => eid.source === 'id5-sync.com')[0].uids[0].id).is.equal('11111'); + expect(requestBid.user.ext.eids.filter(eid => eid.source === 'id5-sync.com')[0].ext.linkType).is.equal('some-link-type'); // LiveRamp should exist expect(requestBid.user.ext.eids.filter(eid => eid.source === 'liveramp.com')[0].uids[0].id).is.equal('0000-1111-2222-3333'); }); @@ -1240,6 +1320,7 @@ describe('S2S Adapter', function () { expect(requestBid).to.haveOwnProperty('ext'); expect(requestBid.ext).to.haveOwnProperty('prebid'); expect(requestBid.ext.prebid).to.deep.equal({ + auctiontimestamp: 1510852447530, foo: 'bar', targeting: { includewinners: true, @@ -1271,6 +1352,7 @@ describe('S2S Adapter', function () { expect(requestBid).to.haveOwnProperty('ext'); expect(requestBid.ext).to.haveOwnProperty('prebid'); expect(requestBid.ext.prebid).to.deep.equal({ + auctiontimestamp: 1510852447530, targeting: { includewinners: false, includebidderkeys: true @@ -1304,6 +1386,7 @@ describe('S2S Adapter', function () { expect(requestBid).to.haveOwnProperty('ext'); expect(requestBid.ext).to.haveOwnProperty('prebid'); expect(requestBid.ext.prebid).to.deep.equal({ + auctiontimestamp: 1510852447530, cache: { vastxml: 'vastxml-set-though-extPrebid.cache.vastXml' }, @@ -1384,7 +1467,81 @@ describe('S2S Adapter', function () { }); describe('pbAdSlot config', function () { - it('should not send \"imp.ext.context.data.adslot\" if \"fpd.context\" is undefined', function () { + it('should not send \"imp.ext.context.data.pbadslot\" if \"fpd.context\" is undefined', function () { + const ortb2Config = utils.deepClone(CONFIG); + ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; + const consentConfig = { s2sConfig: ortb2Config }; + config.setConfig(consentConfig); + const bidRequest = utils.deepClone(REQUEST); + + adapter.callBids(bidRequest, BID_REQUESTS, addBidResponse, done, ajax); + const parsedRequestBody = JSON.parse(server.requests[0].requestBody); + + expect(parsedRequestBody.imp).to.be.a('array'); + expect(parsedRequestBody.imp[0]).to.be.a('object'); + expect(parsedRequestBody.imp[0]).to.not.have.deep.nested.property('ext.context.data.pbadslot'); + }); + + it('should not send \"imp.ext.context.data.pbadslot\" if \"fpd.context.pbAdSlot\" is undefined', function () { + const ortb2Config = utils.deepClone(CONFIG); + ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; + const consentConfig = { s2sConfig: ortb2Config }; + config.setConfig(consentConfig); + const bidRequest = utils.deepClone(REQUEST); + bidRequest.ad_units[0].fpd = {}; + + adapter.callBids(bidRequest, BID_REQUESTS, addBidResponse, done, ajax); + const parsedRequestBody = JSON.parse(server.requests[0].requestBody); + + expect(parsedRequestBody.imp).to.be.a('array'); + expect(parsedRequestBody.imp[0]).to.be.a('object'); + expect(parsedRequestBody.imp[0]).to.not.have.deep.nested.property('ext.context.data.pbadslot'); + }); + + it('should not send \"imp.ext.context.data.pbadslot\" if \"fpd.context.pbAdSlot\" is empty string', function () { + const ortb2Config = utils.deepClone(CONFIG); + ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; + const consentConfig = { s2sConfig: ortb2Config }; + config.setConfig(consentConfig); + const bidRequest = utils.deepClone(REQUEST); + bidRequest.ad_units[0].fpd = { + context: { + pbAdSlot: '' + } + }; + + adapter.callBids(bidRequest, BID_REQUESTS, addBidResponse, done, ajax); + const parsedRequestBody = JSON.parse(server.requests[0].requestBody); + + expect(parsedRequestBody.imp).to.be.a('array'); + expect(parsedRequestBody.imp[0]).to.be.a('object'); + expect(parsedRequestBody.imp[0]).to.not.have.deep.nested.property('ext.context.data.pbadslot'); + }); + + it('should send \"imp.ext.context.data.pbadslot\" if \"fpd.context.pbAdSlot\" value is a non-empty string', function () { + const ortb2Config = utils.deepClone(CONFIG); + ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; + const consentConfig = { s2sConfig: ortb2Config }; + config.setConfig(consentConfig); + const bidRequest = utils.deepClone(REQUEST); + bidRequest.ad_units[0].fpd = { + context: { + pbAdSlot: '/a/b/c' + } + }; + + adapter.callBids(bidRequest, BID_REQUESTS, addBidResponse, done, ajax); + const parsedRequestBody = JSON.parse(server.requests[0].requestBody); + + expect(parsedRequestBody.imp).to.be.a('array'); + expect(parsedRequestBody.imp[0]).to.be.a('object'); + expect(parsedRequestBody.imp[0]).to.have.deep.nested.property('ext.context.data.pbadslot'); + expect(parsedRequestBody.imp[0].ext.context.data.pbadslot).to.equal('/a/b/c'); + }); + }); + + describe('GAM ad unit config', function () { + it('should not send \"imp.ext.context.data.adserver.adslot\" if \"fpd.context\" is undefined', function () { const ortb2Config = utils.deepClone(CONFIG); ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; const consentConfig = { s2sConfig: ortb2Config }; @@ -1399,7 +1556,7 @@ describe('S2S Adapter', function () { expect(parsedRequestBody.imp[0]).to.not.have.deep.nested.property('ext.context.data.adslot'); }); - it('should not send \"imp.ext.context.data.adslot\" if \"fpd.context.pbAdSlot\" is undefined', function () { + it('should not send \"imp.ext.context.data.adserver.adslot\" if \"fpd.context.adserver.adSlot\" is undefined', function () { const ortb2Config = utils.deepClone(CONFIG); ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; const consentConfig = { s2sConfig: ortb2Config }; @@ -1415,7 +1572,7 @@ describe('S2S Adapter', function () { expect(parsedRequestBody.imp[0]).to.not.have.deep.nested.property('ext.context.data.adslot'); }); - it('should not send \"imp.ext.context.data.adslot\" if \"fpd.context.pbAdSlot\" is empty string', function () { + it('should not send \"imp.ext.context.data.adserver.adslot\" if \"fpd.context.adserver.adSlot\" is empty string', function () { const ortb2Config = utils.deepClone(CONFIG); ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; const consentConfig = { s2sConfig: ortb2Config }; @@ -1423,7 +1580,9 @@ describe('S2S Adapter', function () { const bidRequest = utils.deepClone(REQUEST); bidRequest.ad_units[0].fpd = { context: { - pbAdSlot: '' + adServer: { + adSlot: '' + } } }; @@ -1435,7 +1594,7 @@ describe('S2S Adapter', function () { expect(parsedRequestBody.imp[0]).to.not.have.deep.nested.property('ext.context.data.adslot'); }); - it('should send \"imp.ext.context.data.adslot\" if \"fpd.context.pbAdSlot\" value is a non-empty string', function () { + it('should send both \"adslot\" and \"name\" from \"imp.ext.context.data.adserver\" if \"fpd.context.adserver.adSlot\" and \"fpd.context.adserver.name\" values are non-empty strings', function () { const ortb2Config = utils.deepClone(CONFIG); ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; const consentConfig = { s2sConfig: ortb2Config }; @@ -1443,7 +1602,10 @@ describe('S2S Adapter', function () { const bidRequest = utils.deepClone(REQUEST); bidRequest.ad_units[0].fpd = { context: { - pbAdSlot: '/a/b/c' + adserver: { + adSlot: '/a/b/c', + name: 'adserverName1' + } } }; @@ -1452,74 +1614,61 @@ describe('S2S Adapter', function () { expect(parsedRequestBody.imp).to.be.a('array'); expect(parsedRequestBody.imp[0]).to.be.a('object'); - expect(parsedRequestBody.imp[0]).to.have.deep.nested.property('ext.context.data.adslot'); - expect(parsedRequestBody.imp[0].ext.context.data.adslot).to.equal('/a/b/c'); + expect(parsedRequestBody.imp[0]).to.have.deep.nested.property('ext.context.data.adserver.adslot'); + expect(parsedRequestBody.imp[0]).to.have.deep.nested.property('ext.context.data.adserver.name'); + expect(parsedRequestBody.imp[0].ext.context.data.adserver.adslot).to.equal('/a/b/c'); + expect(parsedRequestBody.imp[0].ext.context.data.adserver.name).to.equal('adserverName1'); }); }); }); describe('response handler', function () { - let server; - let logWarnSpy; - beforeEach(function () { - server = sinon.fakeServer.create(); sinon.stub(utils, 'triggerPixel'); sinon.stub(utils, 'insertUserSyncIframe'); sinon.stub(utils, 'logError'); sinon.stub(events, 'emit'); - logWarnSpy = sinon.spy(utils, 'logWarn'); }); afterEach(function () { - server.restore(); utils.triggerPixel.restore(); utils.insertUserSyncIframe.restore(); utils.logError.restore(); events.emit.restore(); - logWarnSpy.restore(); }); // TODO: test dependent on pbjs_api_spec. Needs to be isolated it('does not call addBidResponse and calls done when ad unit not set', function () { - server.respondWith(JSON.stringify(RESPONSE_NO_BID_NO_UNIT)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_NO_BID_NO_UNIT)); sinon.assert.notCalled(addBidResponse); sinon.assert.calledOnce(done); }); it('does not call addBidResponse and calls done when server requests cookie sync', function () { - server.respondWith(JSON.stringify(RESPONSE_NO_COOKIE)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_NO_COOKIE)); sinon.assert.notCalled(addBidResponse); sinon.assert.calledOnce(done); }); it('does not call addBidResponse and calls done when ad unit is set', function () { - server.respondWith(JSON.stringify(RESPONSE_NO_BID_UNIT_SET)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_NO_BID_UNIT_SET)); sinon.assert.notCalled(addBidResponse); sinon.assert.calledOnce(done); }); it('registers successful bids and calls done when there are less bids than requests', function () { - server.respondWith(JSON.stringify(RESPONSE_OPENRTB)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); sinon.assert.calledOnce(addBidResponse); sinon.assert.calledOnce(done); @@ -1533,11 +1682,9 @@ describe('S2S Adapter', function () { }); it('should have dealId in bidObject', function () { - server.respondWith(JSON.stringify(RESPONSE_OPENRTB)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); const response = addBidResponse.firstCall.args[1]; expect(response).to.have.property('dealId', 'test-dealid'); }); @@ -1553,9 +1700,8 @@ describe('S2S Adapter', function () { cacheResponse.seatbid.forEach(item => { item.bid[0].ext.prebid.targeting = targetingTestData }); - server.respondWith(JSON.stringify(cacheResponse)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1567,9 +1713,8 @@ describe('S2S Adapter', function () { }); it('should set the bidResponse currency to whats in the PBS response', function() { - server.respondWith(JSON.stringify(RESPONSE_OPENRTB)); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); sinon.assert.calledOnce(addBidResponse); const pbjsResponse = addBidResponse.firstCall.args[1]; expect(pbjsResponse).to.have.property('currency', 'EUR'); @@ -1578,9 +1723,8 @@ describe('S2S Adapter', function () { it('should set the default bidResponse currency when not specified in OpenRTB', function() { let modifiedResponse = utils.deepClone(RESPONSE_OPENRTB); modifiedResponse.cur = ''; - server.respondWith(JSON.stringify(modifiedResponse)); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(modifiedResponse)); sinon.assert.calledOnce(addBidResponse); const pbjsResponse = addBidResponse.firstCall.args[1]; expect(pbjsResponse).to.have.property('currency', 'USD'); @@ -1597,11 +1741,9 @@ describe('S2S Adapter', function () { item.bid[0].ext.prebid.targeting = targetingTestData }); - server.respondWith(JSON.stringify(cacheResponse)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; expect(response).to.have.property('adserverTargeting').that.deep.equals({ 'foo': 'bar' }); @@ -1613,11 +1755,9 @@ describe('S2S Adapter', function () { }; sinon.stub(adapterManager, 'getBidAdapter').callsFake(() => rubiconAdapter); - server.respondWith(JSON.stringify(RESPONSE_NO_PBS_COOKIE)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_NO_PBS_COOKIE)); sinon.assert.calledOnce(rubiconAdapter.registerSyncs); @@ -1635,9 +1775,8 @@ describe('S2S Adapter', function () { }); config.setConfig({ s2sConfig }); - server.respondWith(JSON.stringify(RESPONSE_OPENRTB)); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); sinon.assert.calledOnce(rubiconAdapter.registerSyncs); @@ -1650,9 +1789,8 @@ describe('S2S Adapter', function () { }); config.setConfig({ s2sConfig }); - server.respondWith(JSON.stringify(RESPONSE_OPENRTB)); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); sinon.assert.calledOnce(events.emit); const event = events.emit.firstCall.args; @@ -1665,8 +1803,29 @@ describe('S2S Adapter', function () { expect(response).to.have.property('bidderCode', 'appnexus'); expect(response).to.have.property('requestId', '123'); expect(response).to.have.property('cpm', 0.5); + expect(response).to.have.property('meta'); + expect(response.meta).to.have.property('advertiserDomains'); + expect(response.meta.advertiserDomains[0]).to.equal('appnexus.com'); expect(response).to.not.have.property('vastUrl'); expect(response).to.not.have.property('videoCacheKey'); + expect(response).to.have.property('ttl', 60); + }); + + it('respects defaultTtl', function () { + const s2sConfig = Object.assign({}, CONFIG, { + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction', + defaultTtl: 30 + }); + config.setConfig({ s2sConfig }); + + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); + + sinon.assert.calledOnce(events.emit); + const event = events.emit.firstCall.args; + sinon.assert.calledOnce(addBidResponse); + const response = addBidResponse.firstCall.args[1]; + expect(response).to.have.property('ttl', 30); }); it('handles OpenRTB video responses', function () { @@ -1675,9 +1834,8 @@ describe('S2S Adapter', function () { }); config.setConfig({ s2sConfig }); - server.respondWith(JSON.stringify(RESPONSE_OPENRTB_VIDEO)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB_VIDEO)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1703,9 +1861,9 @@ describe('S2S Adapter', function () { } } }); - server.respondWith(JSON.stringify(cacheResponse)); + adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1729,9 +1887,8 @@ describe('S2S Adapter', function () { cacheResponse.seatbid.forEach(item => { item.bid[0].ext.prebid.targeting = targetingTestData }); - server.respondWith(JSON.stringify(cacheResponse)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1756,9 +1913,8 @@ describe('S2S Adapter', function () { hb_cache_path: '/cache' } }); - server.respondWith(JSON.stringify(cacheResponse)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1768,6 +1924,77 @@ describe('S2S Adapter', function () { expect(response).to.have.property('vastUrl', 'https://prebid-cache.net/cache?uuid=a5ad3993'); }); + it('handles response cache from ext.prebid.targeting with wurl', function () { + const s2sConfig = Object.assign({}, CONFIG, { + endpoint: 'https://prebidserverurl/openrtb2/auction?querystring=param' + }); + config.setConfig({ s2sConfig }); + const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO); + cacheResponse.seatbid.forEach(item => { + item.bid[0].ext.prebid.events = { + win: 'https://wurl.com?a=1&b=2' + }; + item.bid[0].ext.prebid.targeting = { + hb_uuid: 'a5ad3993', + hb_cache_host: 'prebid-cache.net', + hb_cache_path: '/cache' + } + }); + adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); + + sinon.assert.calledOnce(addBidResponse); + const response = addBidResponse.firstCall.args[1]; + expect(response).to.have.property('pbsBidId', '654321'); + }); + + it('handles response cache from ext.prebid.targeting with wurl and removes invalid targeting', function () { + const s2sConfig = Object.assign({}, CONFIG, { + endpoint: 'https://prebidserverurl/openrtb2/auction?querystring=param' + }); + config.setConfig({ s2sConfig }); + const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO); + cacheResponse.seatbid.forEach(item => { + item.bid[0].ext.prebid.events = { + win: 'https://wurl.com?a=1&b=2' + }; + item.bid[0].ext.prebid.targeting = { + hb_uuid: 'a5ad3993', + hb_cache_host: 'prebid-cache.net', + hb_cache_path: '/cache', + hb_winurl: 'https://hbwinurl.com?a=1&b=2', + hb_bidid: '1234567890', + } + }); + adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); + + sinon.assert.calledOnce(addBidResponse); + const response = addBidResponse.firstCall.args[1]; + + expect(response.adserverTargeting).to.deep.equal({ + hb_uuid: 'a5ad3993', + hb_cache_host: 'prebid-cache.net', + hb_cache_path: '/cache' + }); + }); + + it('add request property pbsBidId with ext.prebid.bidid value', function () { + const s2sConfig = Object.assign({}, CONFIG, { + endpoint: 'https://prebidserverurl/openrtb2/auction?querystring=param' + }); + config.setConfig({ s2sConfig }); + const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO); + + adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); + + sinon.assert.calledOnce(addBidResponse); + const response = addBidResponse.firstCall.args[1]; + + expect(response).to.have.property('pbsBidId', '654321'); + }); + it('handles OpenRTB native responses', function () { sinon.stub(utils, 'getBidRequest').returns({ adUnitCode: 'div-gpt-ad-1460505748561-0', @@ -1779,9 +2006,8 @@ describe('S2S Adapter', function () { }); config.setConfig({ s2sConfig }); - server.respondWith(JSON.stringify(RESPONSE_OPENRTB_NATIVE)); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB_NATIVE)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1796,6 +2022,98 @@ describe('S2S Adapter', function () { }); }); + describe('bid won events', function () { + let uniqueIdCount = 0; + let triggerPixelStub; + const staticUniqueIds = ['1000', '1001', '1002', '1003']; + + before(function () { + triggerPixelStub = sinon.stub(utils, 'triggerPixel'); + }); + + beforeEach(function () { + resetWurlMap(); + sinon.stub(utils, 'insertUserSyncIframe'); + sinon.stub(utils, 'logError'); + sinon.stub(utils, 'getUniqueIdentifierStr').callsFake(() => { + uniqueIdCount++; + return staticUniqueIds[uniqueIdCount - 1]; + }); + triggerPixelStub.resetHistory(); + + config.setConfig({ + s2sConfig: Object.assign({}, CONFIG, { + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' + }) + }); + }); + + afterEach(function () { + utils.triggerPixel.resetHistory(); + utils.insertUserSyncIframe.restore(); + utils.logError.restore(); + utils.getUniqueIdentifierStr.restore(); + uniqueIdCount = 0; + }); + + after(function () { + triggerPixelStub.restore(); + }); + + it('should call triggerPixel if wurl is defined', function () { + const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); + clonedResponse.seatbid[0].bid[0].ext.prebid.events = { + win: 'https://wurl.org' + }; + + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); + + events.emit(CONSTANTS.EVENTS.BID_WON, { + auctionId: '173afb6d132ba3', + adId: '1000' + }); + + sinon.assert.calledOnce(addBidResponse); + expect(utils.triggerPixel.called).to.be.true; + expect(utils.triggerPixel.getCall(0).args[0]).to.include('https://wurl.org'); + }); + + it('should not call triggerPixel if the wurl cache does not contain the winning bid', function () { + const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); + clonedResponse.seatbid[0].bid[0].ext.prebid.events = { + win: 'https://wurl.org' + }; + + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); + + events.emit(CONSTANTS.EVENTS.BID_WON, { + auctionId: '173afb6d132ba3', + adId: 'missingAdId' + }); + + sinon.assert.calledOnce(addBidResponse) + expect(utils.triggerPixel.called).to.be.false; + }); + + it('should not call triggerPixel if wurl is undefined', function () { + const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); + clonedResponse.seatbid[0].bid[0].ext.prebid.events = {}; + + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); + + events.emit(CONSTANTS.EVENTS.BID_WON, { + auctionId: '173afb6d132ba3', + adId: '1060' + }); + + sinon.assert.calledOnce(addBidResponse) + expect(utils.triggerPixel.called).to.be.false; + }); + }) + describe('s2sConfig', function () { let logErrorSpy; @@ -1901,6 +2219,14 @@ describe('S2S Adapter', function () { }); it('should return proper defaults', function () { + const options = { + accountId: 'abc', + bidders: ['rubicon'], + defaultVendor: 'rubicon', + timeout: 750 + }; + + config.setConfig({ s2sConfig: options }); expect(config.getConfig('s2sConfig')).to.deep.equal({ 'accountId': 'abc', 'adapter': 'prebidServer', @@ -1953,6 +2279,15 @@ describe('S2S Adapter', function () { }) }); + it('should set default s2s ttl', function () { + config.setConfig({ + s2sConfig: { + defaultTtl: 30 + } + }); + expect(config.getConfig('s2sConfig').defaultTtl).to.deep.equal(30); + }); + it('should set syncUrlModifier', function () { config.setConfig({ s2sConfig: { diff --git a/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js b/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js index e87be40314c..ce97789fe3e 100644 --- a/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js +++ b/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js @@ -98,7 +98,7 @@ describe('Prebid Manager Analytics Adapter', function () { events.emit(constants.EVENTS.AUCTION_END, {}); events.emit(constants.EVENTS.BID_TIMEOUT, {}); - sinon.assert.callCount(prebidmanagerAnalytics.track, 6); + sinon.assert.callCount(prebidmanagerAnalytics.track, 7); }); }); diff --git a/test/spec/modules/priceFloors_spec.js b/test/spec/modules/priceFloors_spec.js index 55aa7900252..ae45244f03d 100644 --- a/test/spec/modules/priceFloors_spec.js +++ b/test/spec/modules/priceFloors_spec.js @@ -14,11 +14,13 @@ import { fieldMatchingFunctions, allowedFields } from 'modules/priceFloors.js'; +import events from 'src/events.js'; describe('the price floors module', function () { let logErrorSpy; let logWarnSpy; let sandbox; + let clock; const basicFloorData = { modelVersion: 'basic model', currency: 'USD', @@ -58,12 +60,14 @@ describe('the price floors module', function () { }; } beforeEach(function() { + clock = sinon.useFakeTimers(); sandbox = sinon.sandbox.create(); logErrorSpy = sinon.spy(utils, 'logError'); logWarnSpy = sinon.spy(utils, 'logWarn'); }); afterEach(function() { + clock.restore(); handleSetFloorsConfig({enabled: false}); sandbox.restore(); utils.logError.restore(); @@ -178,6 +182,20 @@ describe('the price floors module', function () { matchingRule: '*' }); }); + it('does not alter cached matched input if conversion occurs', function () { + let inputData = {...basicFloorData}; + [0.2, 0.4, 0.6, 0.8].forEach(modifier => { + let result = getFirstMatchingFloor(inputData, basicBidRequest, {mediaType: 'banner', size: '*'}); + // result should always be the same + expect(result).to.deep.equal({ + matchingFloor: 1.0, + matchingData: 'banner', + matchingRule: 'banner' + }); + // make sure a post retrieval adjustment does not alter the cached floor + result.matchingFloor = result.matchingFloor * modifier; + }); + }); it('selects the right floor for different sizes', function () { let inputFloorData = { currency: 'USD', @@ -288,17 +306,10 @@ describe('the price floors module', function () { }); }; let fakeFloorProvider; - let clock; let actualAllowedFields = allowedFields; let actualFieldMatchingFunctions = fieldMatchingFunctions; const defaultAllowedFields = [...allowedFields]; const defaultMatchingFunctions = {...fieldMatchingFunctions}; - before(function () { - clock = sinon.useFakeTimers(); - }); - after(function () { - clock.restore(); - }); beforeEach(function() { fakeFloorProvider = sinon.fakeServer.create(); }); @@ -314,7 +325,14 @@ describe('the price floors module', function () { data: undefined }); runStandardAuction(); - validateBidRequests(false, undefined); + validateBidRequests(false, { + skipped: true, + modelVersion: undefined, + location: 'noData', + skipRate: 0, + fetchStatus: undefined, + floorProvider: undefined + }); }); it('should use adUnit level data if not setConfig or fetch has occured', function () { handleSetFloorsConfig({ @@ -344,15 +362,202 @@ describe('the price floors module', function () { skipped: false, modelVersion: 'adUnit Model Version', location: 'adUnit', + skipRate: 0, + fetchStatus: undefined, + floorProvider: undefined }); }); it('bidRequests should have getFloor function and flooring meta data when setConfig occurs', function () { - handleSetFloorsConfig({...basicFloorConfig}); + handleSetFloorsConfig({...basicFloorConfig, floorProvider: 'floorprovider'}); + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'basic model', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined, + floorProvider: 'floorprovider' + }); + }); + it('should pick the right floorProvider', function () { + let inputFloors = { + ...basicFloorConfig, + floorProvider: 'providerA', + data: { + ...basicFloorData, + floorProvider: 'providerB', + } + }; + handleSetFloorsConfig(inputFloors); + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'basic model', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined, + floorProvider: 'providerB' + }); + + // if not at data level take top level + delete inputFloors.data.floorProvider; + handleSetFloorsConfig(inputFloors); + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'basic model', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined, + floorProvider: 'providerA' + }); + + // if none should be undefined + delete inputFloors.floorProvider; + handleSetFloorsConfig(inputFloors); + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'basic model', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined, + floorProvider: undefined + }); + }); + it('should take the right skipRate depending on input', function () { + // first priority is data object + sandbox.stub(Math, 'random').callsFake(() => 0.99); + let inputFloors = { + ...basicFloorConfig, + skipRate: 10, + data: { + ...basicFloorData, + skipRate: 50 + } + }; + handleSetFloorsConfig(inputFloors); + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'basic model', + location: 'setConfig', + skipRate: 50, + fetchStatus: undefined, + floorProvider: undefined + }); + + // if that does not exist uses topLevel skipRate setting + delete inputFloors.data.skipRate; + handleSetFloorsConfig(inputFloors); runStandardAuction(); validateBidRequests(true, { skipped: false, modelVersion: 'basic model', location: 'setConfig', + skipRate: 10, + fetchStatus: undefined, + floorProvider: undefined + }); + + // if that is not there defaults to zero + delete inputFloors.skipRate; + handleSetFloorsConfig(inputFloors); + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'basic model', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined, + floorProvider: undefined + }); + }); + it('should randomly pick a model if floorsSchemaVersion is 2', function () { + let inputFloors = { + ...basicFloorConfig, + floorProvider: 'floorprovider', + data: { + floorsSchemaVersion: 2, + currency: 'USD', + modelGroups: [ + { + modelVersion: 'model-1', + modelWeight: 10, + schema: { + delimiter: '|', + fields: ['mediaType'] + }, + values: { + 'banner': 1.0, + '*': 2.5 + } + }, { + modelVersion: 'model-2', + modelWeight: 40, + schema: { + delimiter: '|', + fields: ['size'] + }, + values: { + '300x250': 1.0, + '*': 2.5 + } + }, { + modelVersion: 'model-3', + modelWeight: 50, + schema: { + delimiter: '|', + fields: ['domain'] + }, + values: { + 'www.prebid.org': 1.0, + '*': 2.5 + } + } + ] + } + }; + handleSetFloorsConfig(inputFloors); + + // stub random to give us wanted vals + let randValue; + sandbox.stub(Math, 'random').callsFake(() => randValue); + + // 0 - 10 should use first model + randValue = 0.05; + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'model-1', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined, + floorProvider: 'floorprovider' + }); + + // 11 - 50 should use second model + randValue = 0.40; + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'model-2', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined, + floorProvider: 'floorprovider' + }); + + // 51 - 100 should use third model + randValue = 0.75; + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'model-3', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined, + floorProvider: 'floorprovider' }); }); it('should not overwrite previous data object if the new one is bad', function () { @@ -378,6 +583,9 @@ describe('the price floors module', function () { skipped: false, modelVersion: 'basic model', location: 'setConfig', + skipRate: 0, + fetchStatus: undefined, + floorProvider: undefined }); }); it('should dynamically add new schema fileds and functions if added via setConfig', function () { @@ -453,6 +661,9 @@ describe('the price floors module', function () { skipped: false, modelVersion: 'basic model', location: 'setConfig', + skipRate: 0, + fetchStatus: 'timeout', + floorProvider: undefined }); fakeFloorProvider.respond(); }); @@ -465,7 +676,7 @@ describe('the price floors module', function () { fakeFloorProvider.respondWith(JSON.stringify(fetchFloorData)); // run setConfig indicating fetch - handleSetFloorsConfig({...basicFloorConfig, auctionDelay: 250, endpoint: {url: 'http://www.fakeFloorProvider.json'}}); + handleSetFloorsConfig({...basicFloorConfig, floorProvider: 'floorprovider', auctionDelay: 250, endpoint: {url: 'http://www.fakeFloorProvider.json'}}); // floor provider should be called expect(fakeFloorProvider.requests.length).to.equal(1); @@ -482,10 +693,110 @@ describe('the price floors module', function () { expect(exposedAdUnits).to.not.be.undefined; // the exposedAdUnits should be from the fetch not setConfig level data + // and fetchStatus is success since fetch worked validateBidRequests(true, { skipped: false, modelVersion: 'fetch model name', location: 'fetch', + skipRate: 0, + fetchStatus: 'success', + floorProvider: 'floorprovider' + }); + }); + it('it should correctly overwrite floorProvider with fetch provider', function () { + // init the fake server with response stuff + let fetchFloorData = { + ...basicFloorData, + floorProvider: 'floorProviderD', // change the floor provider + modelVersion: 'fetch model name', // change the model name + }; + fakeFloorProvider.respondWith(JSON.stringify(fetchFloorData)); + + // run setConfig indicating fetch + handleSetFloorsConfig({...basicFloorConfig, floorProvider: 'floorproviderC', auctionDelay: 250, endpoint: {url: 'http://www.fakeFloorProvider.json'}}); + + // floor provider should be called + expect(fakeFloorProvider.requests.length).to.equal(1); + expect(fakeFloorProvider.requests[0].url).to.equal('http://www.fakeFloorProvider.json'); + + // start the auction it should delay and not immediately call `continueAuction` + runStandardAuction(); + + // exposedAdUnits should be undefined if the auction has not continued + expect(exposedAdUnits).to.be.undefined; + + // make the fetch respond + fakeFloorProvider.respond(); + + // the exposedAdUnits should be from the fetch not setConfig level data + // and fetchStatus is success since fetch worked + validateBidRequests(true, { + skipped: false, + modelVersion: 'fetch model name', + location: 'fetch', + skipRate: 0, + fetchStatus: 'success', + floorProvider: 'floorProviderD' + }); + }); + it('it should correctly overwrite skipRate with fetch skipRate', function () { + // so floors does not skip + sandbox.stub(Math, 'random').callsFake(() => 0.99); + // init the fake server with response stuff + let fetchFloorData = { + ...basicFloorData, + modelVersion: 'fetch model name', // change the model name + }; + fetchFloorData.skipRate = 95; + fakeFloorProvider.respondWith(JSON.stringify(fetchFloorData)); + + // run setConfig indicating fetch + handleSetFloorsConfig({...basicFloorConfig, floorProvider: 'floorprovider', auctionDelay: 250, endpoint: {url: 'http://www.fakeFloorProvider.json'}}); + + // floor provider should be called + expect(fakeFloorProvider.requests.length).to.equal(1); + expect(fakeFloorProvider.requests[0].url).to.equal('http://www.fakeFloorProvider.json'); + + // start the auction it should delay and not immediately call `continueAuction` + runStandardAuction(); + + // exposedAdUnits should be undefined if the auction has not continued + expect(exposedAdUnits).to.be.undefined; + + // make the fetch respond + fakeFloorProvider.respond(); + expect(exposedAdUnits).to.not.be.undefined; + + // the exposedAdUnits should be from the fetch not setConfig level data + // and fetchStatus is success since fetch worked + validateBidRequests(true, { + skipped: false, + modelVersion: 'fetch model name', + location: 'fetch', + skipRate: 95, + fetchStatus: 'success', + floorProvider: 'floorprovider' + }); + }); + it('Should not break if floor provider returns 404', function () { + // run setConfig indicating fetch + handleSetFloorsConfig({...basicFloorConfig, auctionDelay: 250, endpoint: {url: 'http://www.fakeFloorProvider.json'}}); + + // run the auction and make server respond with 404 + fakeFloorProvider.respond(); + runStandardAuction(); + + // error should have been called for fetch error + expect(logErrorSpy.calledOnce).to.equal(true); + // should have caught the response error and still used setConfig data + // and fetch failed is true + validateBidRequests(true, { + skipped: false, + modelVersion: 'basic model', + location: 'setConfig', + skipRate: 0, + fetchStatus: 'error', + floorProvider: undefined }); }); it('Should not break if floor provider returns non json', function () { @@ -498,11 +809,17 @@ describe('the price floors module', function () { fakeFloorProvider.respond(); runStandardAuction(); + // error should have been called for response floor data not being valid + expect(logErrorSpy.calledOnce).to.equal(true); // should have caught the response error and still used setConfig data + // and fetchStatus is 'success' but location is setConfig since it had bad data validateBidRequests(true, { skipped: false, modelVersion: 'basic model', location: 'setConfig', + skipRate: 0, + fetchStatus: 'success', + floorProvider: undefined }); }); it('should handle not using fetch correctly', function () { @@ -531,6 +848,11 @@ describe('the price floors module', function () { expect(logErrorSpy.calledOnce).to.equal(true); }); describe('isFloorsDataValid', function () { + it('should return false if unknown floorsSchemaVersion', function () { + let inputFloorData = utils.deepClone(basicFloorData); + inputFloorData.floorsSchemaVersion = 3; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + }); it('should work correctly for fields array', function () { let inputFloorData = utils.deepClone(basicFloorData); expect(isFloorsDataValid(inputFloorData)).to.to.equal(true); @@ -586,6 +908,66 @@ describe('the price floors module', function () { expect(isFloorsDataValid(inputFloorData)).to.to.equal(true); expect(inputFloorData.values).to.deep.equal({ 'test-div-1|native': 1.0 }); }); + it('should work correctly for floorsSchemaVersion 2', function () { + let inputFloorData = { + floorsSchemaVersion: 2, + currency: 'USD', + modelGroups: [ + { + modelVersion: 'model-1', + modelWeight: 10, + schema: { + delimiter: '|', + fields: ['mediaType'] + }, + values: { + 'banner': 1.0, + '*': 2.5 + } + }, { + modelVersion: 'model-2', + modelWeight: 40, + schema: { + delimiter: '|', + fields: ['size'] + }, + values: { + '300x250': 1.0, + '*': 2.5 + } + }, { + modelVersion: 'model-3', + modelWeight: 50, + schema: { + delimiter: '|', + fields: ['domain'] + }, + values: { + 'www.prebid.org': 1.0, + '*': 2.5 + } + } + ] + }; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(true); + + // remove one of the modelWeight's and it should be false + delete inputFloorData.modelGroups[1].modelWeight; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + inputFloorData.modelGroups[1].modelWeight = 40; + + // remove values from a model and it should not validate + const tempValues = {...inputFloorData.modelGroups[0].values}; + delete inputFloorData.modelGroups[0].values; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + inputFloorData.modelGroups[0].values = tempValues; + + // modelGroups should be an array and have at least one entry + delete inputFloorData.modelGroups; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + inputFloorData.modelGroups = []; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + }); }); describe('getFloor', function () { let bidRequest = { @@ -733,6 +1115,39 @@ describe('the price floors module', function () { floor: 1.3334 // 1.3334 * 0.75 = 1.000005 which is the floor (we cut off getFloor at 4 decimal points) }); }); + it('should work when cpmAdjust function uses bid object', function () { + getGlobal().bidderSettings = { + rubicon: { + bidCpmAdjustment: function (bidCpm, bidResponse) { + return bidResponse.cpm * 0.5; + }, + }, + appnexus: { + bidCpmAdjustment: function (bidCpm, bidResponse) { + return bidResponse.cpm * 0.75; + }, + } + }; + _floorDataForAuction[bidRequest.auctionId] = utils.deepClone(basicFloorConfig); + _floorDataForAuction[bidRequest.auctionId].data.values = { '*': 1.0 }; + let appnexusBid = { + ...bidRequest, + bidder: 'appnexus' + }; + + // the conversion should be what the bidder would need to return in order to match the actual floor + // rubicon + expect(bidRequest.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 2.0 // a 2.0 bid after rubicons cpm adjustment would be 1.0 and thus is the floor after adjust + }); + + // appnexus + expect(appnexusBid.getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.3334 // 1.3334 * 0.75 = 1.000005 which is the floor (we cut off getFloor at 4 decimal points) + }); + }); it('should correctly pick the right attributes if * is passed in and context can be assumed', function () { let inputBidReq = { bidder: 'rubicon', @@ -969,4 +1384,24 @@ describe('the price floors module', function () { expect(returnedBidResponse.cpm).to.equal(7.5); }); }); + + describe('Post Auction Tests', function () { + let AUCTION_END_EVENT; + beforeEach(function () { + AUCTION_END_EVENT = { + auctionId: '123-45-6789' + }; + }); + it('should wait 3 seconds before deleting auction floor data', function () { + handleSetFloorsConfig({enabled: true}); + _floorDataForAuction[AUCTION_END_EVENT.auctionId] = utils.deepClone(basicFloorConfig); + events.emit(CONSTANTS.EVENTS.AUCTION_END, AUCTION_END_EVENT); + // should still be here + expect(_floorDataForAuction[AUCTION_END_EVENT.auctionId]).to.not.be.undefined; + // tick for 4 seconds + clock.tick(4000); + // should be undefined now + expect(_floorDataForAuction[AUCTION_END_EVENT.auctionId]).to.be.undefined; + }); + }); }); diff --git a/test/spec/modules/projectLimeLightBidAdapter_spec.js b/test/spec/modules/projectLimeLightBidAdapter_spec.js index 3ffc017f177..778d8eedf7b 100644 --- a/test/spec/modules/projectLimeLightBidAdapter_spec.js +++ b/test/spec/modules/projectLimeLightBidAdapter_spec.js @@ -2,11 +2,12 @@ import {expect} from 'chai'; import {spec} from '../../../modules/projectLimeLightBidAdapter.js'; describe('ProjectLimeLightAdapter', function () { - let bid = { + const bid1 = { bidId: '2dd581a2b6281d', bidder: 'project-limelight', bidderRequestId: '145e1d6a7837c9', params: { + host: 'ads.project-limelight.com', adUnitId: 123, adUnitType: 'banner' }, @@ -14,46 +15,83 @@ describe('ProjectLimeLightAdapter', function () { auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', sizes: [[300, 250]], transactionId: '3bb2f6da-87a6-4029-aeb0-bfe951372e62' - }; + } + const bid2 = { + bidId: '58ee9870c3164a', + bidder: 'project-limelight', + bidderRequestId: '209fdaf1c81649', + params: { + host: 'cpm.project-limelight.com', + adUnitId: 456, + adUnitType: 'banner' + }, + placementCode: 'placement_1', + auctionId: '482f88de-29ab-45c8-981a-d25e39454a34', + sizes: [[350, 200]], + transactionId: '068867d1-46ec-40bb-9fa0-e24611786fb4' + } + const bid3 = { + bidId: '019645c7d69460', + bidder: 'project-limelight', + bidderRequestId: 'f2b15f89e77ba6', + params: { + host: 'ads.project-limelight.com', + adUnitId: 789, + adUnitType: 'video' + }, + placementCode: 'placement_2', + auctionId: 'e4771143-6aa7-41ec-8824-ced4342c96c8', + sizes: [[800, 600]], + transactionId: '738d5915-6651-43b9-9b6b-d50517350917' + } describe('buildRequests', function () { - let serverRequest = spec.buildRequests([bid]); - it('Creates a ServerRequest object with method, URL and data', function () { - expect(serverRequest).to.exist; - expect(serverRequest.method).to.exist; - expect(serverRequest.url).to.exist; - expect(serverRequest.data).to.exist; - }); - it('Returns POST method', function () { - expect(serverRequest.method).to.equal('POST'); - }); + const serverRequests = spec.buildRequests([bid1, bid2, bid3]) + it('Creates two ServerRequests', function() { + expect(serverRequests).to.exist + expect(serverRequests).to.have.lengthOf(2) + }) + serverRequests.forEach(serverRequest => { + it('Creates a ServerRequest object with method, URL and data', function () { + expect(serverRequest).to.exist + expect(serverRequest.method).to.exist + expect(serverRequest.url).to.exist + expect(serverRequest.data).to.exist + }) + it('Returns POST method', function () { + expect(serverRequest.method).to.equal('POST') + }) + it('Returns valid data if array of bids is valid', function () { + let data = serverRequest.data + expect(data).to.be.an('object') + expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'secure', 'adUnits') + expect(data.deviceWidth).to.be.a('number') + expect(data.deviceHeight).to.be.a('number') + expect(data.secure).to.be.a('boolean') + data.adUnits.forEach(adUnit => { + expect(adUnit).to.have.all.keys('id', 'bidId', 'type', 'sizes', 'transactionId') + expect(adUnit.id).to.be.a('number') + expect(adUnit.bidId).to.be.a('string') + expect(adUnit.type).to.be.a('string') + expect(adUnit.transactionId).to.be.a('string') + expect(adUnit.sizes).to.be.an('array') + }) + }) + }) it('Returns valid URL', function () { - expect(serverRequest.url).to.equal('https://ads.project-limelight.com/hb'); - }); - it('Returns valid data if array of bids is valid', function () { - let data = serverRequest.data; - expect(data).to.be.an('object'); - expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'secure', 'adUnits'); - expect(data.deviceWidth).to.be.a('number'); - expect(data.deviceHeight).to.be.a('number'); - expect(data.secure).to.be.a('boolean'); - let adUnits = data['adUnits']; - for (let i = 0; i < adUnits.length; i++) { - let adUnit = adUnits[i]; - expect(adUnit).to.have.all.keys('id', 'bidId', 'type', 'sizes', 'transactionId'); - expect(adUnit.id).to.be.a('number'); - expect(adUnit.bidId).to.be.a('string'); - expect(adUnit.type).to.be.a('string'); - expect(adUnit.transactionId).to.be.a('string'); - expect(adUnit.sizes).to.be.an('array'); - } - }); + expect(serverRequests[0].url).to.equal('https://ads.project-limelight.com/hb') + expect(serverRequests[1].url).to.equal('https://cpm.project-limelight.com/hb') + }) + it('Returns valid adUnits', function () { + validateAdUnit(serverRequests[0].data.adUnits[0], bid1) + validateAdUnit(serverRequests[1].data.adUnits[0], bid2) + validateAdUnit(serverRequests[0].data.adUnits[1], bid3) + }) it('Returns empty data if no valid requests are passed', function () { - serverRequest = spec.buildRequests([]); - let data = serverRequest.data; - expect(data.adUnits).to.be.an('array').that.is.empty; - }); - }); + const serverRequests = spec.buildRequests([]) + expect(serverRequests).to.be.an('array').that.is.empty + }) + }) describe('interpretBannerResponse', function () { let resObject = { body: [ { @@ -167,4 +205,55 @@ describe('ProjectLimeLightAdapter', function () { expect(spec.isBidRequestValid(bidFailed)).to.equal(false); }); }); + describe('interpretResponse', function() { + let resObject = { + requestId: '123', + mediaType: 'banner', + cpm: 0.3, + width: 320, + height: 50, + ad: '

Hello ad

', + ttl: 1000, + creativeId: '123asd', + netRevenue: true, + currency: 'USD' + }; + it('should skip responses which do not contain required params', function() { + let bidResponses = { + body: [ { + mediaType: 'banner', + cpm: 0.3, + ttl: 1000, + currency: 'USD' + }, resObject ] + } + expect(spec.interpretResponse(bidResponses)).to.deep.equal([ resObject ]); + }); + it('should skip responses which do not contain expected mediaType', function() { + let bidResponses = { + body: [ { + requestId: '123', + mediaType: 'native', + cpm: 0.3, + creativeId: '123asd', + ttl: 1000, + currency: 'USD' + }, resObject ] + } + expect(spec.interpretResponse(bidResponses)).to.deep.equal([ resObject ]); + }); + }); }); + +function validateAdUnit(adUnit, bid) { + expect(adUnit.id).to.equal(bid.params.adUnitId) + expect(adUnit.bidId).to.equal(bid.bidId) + expect(adUnit.type).to.equal(bid.params.adUnitType.toUpperCase()) + expect(adUnit.transactionId).to.equal(bid.transactionId) + expect(adUnit.sizes).to.deep.equal(bid.sizes.map(size => { + return { + width: size[0], + height: size[1] + } + })) +} diff --git a/test/spec/modules/proxistoreBidAdapter_spec.js b/test/spec/modules/proxistoreBidAdapter_spec.js index e18262ae797..410c3c59fb6 100644 --- a/test/spec/modules/proxistoreBidAdapter_spec.js +++ b/test/spec/modules/proxistoreBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -let spec = require('modules/proxistoreBidAdapter'); +let { spec } = require('modules/proxistoreBidAdapter'); const BIDDER_CODE = 'proxistore'; describe('ProxistoreBidAdapter', function () { @@ -28,7 +28,21 @@ describe('ProxistoreBidAdapter', function () { transactionId: 511916005 }; describe('isBidRequestValid', function () { - it('it should be true if required params are presents', function () { + it('it should be true if required params are presents and there is no info in the local storage', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('it should be false if the value in the localstorage is less than 5minutes of the actual time', function() { + const date = new Date(); + date.setMinutes(date.getMinutes() - 1) + localStorage.setItem(`PX_NoAds_${bid.params.website}`, date) + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('it should be true if the value in the localstorage is more than 5minutes of the actual time', function() { + const date = new Date(); + date.setMinutes(date.getMinutes() - 10) + localStorage.setItem(`PX_NoAds_${bid.params.website}`, date) expect(spec.isBidRequestValid(bid)).to.equal(true); }); }); @@ -97,7 +111,11 @@ describe('ProxistoreBidAdapter', function () { expect(interpretedResponse.requestId).equal('923756713'); expect(interpretedResponse.netRevenue).to.be.true; expect(interpretedResponse.netRevenue).to.be.true; - }) + }); + it('should have a value in the local storage if the response is empty', function() { + spec.interpretResponse(badResponse, bid); + expect(localStorage.getItem(`PX_NoAds_${bid.params.website}`)).to.be.string; + }); }); describe('interpretResponse', function () { diff --git a/test/spec/modules/pubCommonId_spec.js b/test/spec/modules/pubCommonId_spec.js index ab0ef2adc51..a46ff26c4b8 100644 --- a/test/spec/modules/pubCommonId_spec.js +++ b/test/spec/modules/pubCommonId_spec.js @@ -234,7 +234,7 @@ describe('Publisher Common ID', function () { }); }); - it('disable auto create', function() { + it.skip('disable auto create', function() { setConfig({ create: false }); diff --git a/test/spec/modules/pubgeniusBidAdapter_spec.js b/test/spec/modules/pubgeniusBidAdapter_spec.js new file mode 100644 index 00000000000..52f2e3aeefe --- /dev/null +++ b/test/spec/modules/pubgeniusBidAdapter_spec.js @@ -0,0 +1,447 @@ +import { expect } from 'chai'; + +import { spec } from 'modules/pubgeniusBidAdapter.js'; +import { deepClone, parseQueryStringParameters } from 'src/utils.js'; +import { config } from 'src/config.js'; +import { server } from 'test/mocks/xhr.js'; + +const { + code, + supportedMediaTypes, + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs, + onTimeout, +} = spec; + +describe('pubGENIUS adapter', () => { + describe('code', () => { + it('should be pubgenius', () => { + expect(code).to.equal('pubgenius'); + }); + }); + + describe('supportedMediaTypes', () => { + it('should contain only banner', () => { + expect(supportedMediaTypes).to.deep.equal(['banner']); + }); + }); + + describe('isBidRequestValid', () => { + let bid = null; + + beforeEach(() => { + bid = { + mediaTypes: { + banner: { + sizes: [[300, 600], [300, 250]], + }, + }, + params: { + adUnitId: 1112, + }, + }; + }); + + it('should return true with numeric adUnitId ', () => { + expect(isBidRequestValid(bid)).to.be.true; + }); + + it('should return true with string adUnitId ', () => { + bid.params.adUnitId = '1112'; + + expect(isBidRequestValid(bid)).to.be.true; + }); + + it('should return false without adUnitId', () => { + delete bid.params.adUnitId; + + expect(isBidRequestValid(bid)).to.be.false; + }); + + it('should return false with adUnitId of invalid type', () => { + bid.params.adUnitId = [1112]; + + expect(isBidRequestValid(bid)).to.be.false; + }); + + it('should return false with empty sizes', () => { + bid.mediaTypes.banner.sizes = []; + + expect(isBidRequestValid(bid)).to.be.false; + }); + + it('should return false with invalid size', () => { + bid.mediaTypes.banner.sizes = [[300, 600, 250]]; + + expect(isBidRequestValid(bid)).to.be.false; + }); + }); + + describe('buildRequests', () => { + const origBidderTimeout = config.getConfig('bidderTimeout'); + const origPageUrl = config.getConfig('pageUrl'); + const origCoppa = config.getConfig('coppa'); + + after(() => { + config.setConfig({ + bidderTimeout: origBidderTimeout, + pageUrl: origPageUrl, + coppa: origCoppa, + }); + }); + + let bidRequest = null; + let bidderRequest = null; + let expectedRequest = null; + + beforeEach(() => { + bidRequest = { + adUnitCode: 'test-div', + auctionId: 'fake-auction-id', + bidId: 'fakebidid', + bidder: 'pubgenius', + bidderRequestId: 'fakebidderrequestid', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + mediaTypes: { + banner: { + sizes: [[300, 600], [300, 250]], + }, + }, + params: { + adUnitId: 1112, + }, + transactionId: 'fake-transaction-id', + }; + + bidderRequest = { + auctionId: 'fake-auction-id', + bidderCode: 'pubgenius', + bidderRequestId: 'fakebidderrequestid', + refererInfo: {}, + }; + + expectedRequest = { + method: 'POST', + url: 'https://ortb.adpearl.io/prebid/auction', + data: { + id: 'fake-auction-id', + imp: [ + { + id: 'fakebidid', + banner: { + format: [{ w: 300, h: 600 }, { w: 300, h: 250 }], + topframe: 0, + }, + tagid: '1112', + }, + ], + tmax: 1200, + ext: { + pbadapter: { + version: '1.0.0', + }, + }, + }, + }; + + config.setConfig({ + bidderTimeout: 1200, + pageUrl: undefined, + coppa: undefined, + }); + }); + + it('should build basic requests correctly', () => { + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should build requests with multiple ad units', () => { + const bidRequest1 = deepClone(bidRequest); + bidRequest1.adUnitCode = 'test-div-1'; + bidRequest1.bidId = 'fakebidid1'; + bidRequest1.mediaTypes.banner.sizes = [[728, 90]]; + bidRequest1.params.adUnitId = '1111'; + + expectedRequest.data.imp.push({ + id: 'fakebidid1', + banner: { + format: [{ w: 728, h: 90 }], + topframe: 0, + }, + tagid: '1111', + }); + + expect(buildRequests([bidRequest, bidRequest1], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should take bid floor in bidder params', () => { + bidRequest.params.bidFloor = 0.5; + expectedRequest.data.imp[0].bidfloor = 0.5; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should take position in bidder params', () => { + bidRequest.params.position = 3; + expectedRequest.data.imp[0].banner.pos = 3; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should take pageUrl in config over referer in refererInfo', () => { + config.setConfig({ pageUrl: 'http://pageurl.org' }); + bidderRequest.refererInfo.referer = 'http://referer.org'; + expectedRequest.data.site = { page: 'http://pageurl.org' }; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should use canonical URL over referer in refererInfo', () => { + bidderRequest.refererInfo.canonicalUrl = 'http://pageurl.org'; + bidderRequest.refererInfo.referer = 'http://referer.org'; + expectedRequest.data.site = { page: 'http://pageurl.org' }; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should take gdprConsent when GDPR does not apply', () => { + bidderRequest.gdprConsent = { + gdprApplies: false, + consentString: 'fakeconsent', + }; + expectedRequest.data.regs = { + ext: { gdpr: 0 }, + }; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should take gdprConsent when GDPR applies', () => { + bidderRequest.gdprConsent = { + gdprApplies: true, + consentString: 'fakeconsent', + }; + expectedRequest.data.regs = { + ext: { gdpr: 1 }, + }; + expectedRequest.data.user = { + ext: { consent: 'fakeconsent' }, + }; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should take uspConsent', () => { + bidderRequest.uspConsent = '1---'; + expectedRequest.data.regs = { + ext: { us_privacy: '1---' }, + }; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should take schain', () => { + const schain = { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '0001', + hp: 1 + } + ] + }; + bidRequest.schain = deepClone(schain); + expectedRequest.data.source = { + ext: { schain: deepClone(schain) }, + }; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should take coppa', () => { + config.setConfig({ coppa: true }); + expectedRequest.data.regs = { coppa: 1 }; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should take user IDs', () => { + const eid = { + source: 'adserver.org', + uids: [ + { + id: 'fake-user-id', + atype: 1, + ext: { rtiPartner: 'TDID' }, + }, + ], + }; + bidRequest.userIdAsEids = [deepClone(eid)]; + expectedRequest.data.user = { + ext: { + eids: [deepClone(eid)], + }, + }; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should not take unsupported user IDs', () => { + bidRequest.userIdAsEids = [ + { + source: 'pubcid.org', + uids: [ + { + id: 'fake-user-id', + atype: 1, + }, + ], + }, + ]; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + + it('should not take empty user IDs', () => { + bidRequest.userIdAsEids = []; + + expect(buildRequests([bidRequest], bidderRequest)).to.deep.equal(expectedRequest); + }); + }); + + describe('interpretResponse', () => { + let serverResponse = null; + let expectedBidResponse = null; + + beforeEach(() => { + serverResponse = { + body: { + seatbid: [ + { + seat: 'pubgenius', + bid: [ + { + impid: 'fakebidid', + price: 0.3, + w: 300, + h: 250, + adm: 'fake_creative', + exp: 60, + crid: 'fakecreativeid', + }, + ], + }, + ], + }, + }; + expectedBidResponse = { + requestId: 'fakebidid', + cpm: 0.3, + currency: 'USD', + width: 300, + height: 250, + ad: 'fake_creative', + ttl: 60, + creativeId: 'fakecreativeid', + netRevenue: true, + }; + }); + + it('should interpret response correctly', () => { + expect(interpretResponse(serverResponse)).to.deep.equal([expectedBidResponse]); + }); + + it('should interpret response with adomain', () => { + serverResponse.body.seatbid[0].bid[0].adomain = ['fakeaddomain']; + expectedBidResponse.meta = { + advertiserDomains: ['fakeaddomain'], + }; + + expect(interpretResponse(serverResponse)).to.deep.equal([expectedBidResponse]); + }); + + it('should interpret no bids', () => { + expect(interpretResponse({ body: {} })).to.deep.equal([]); + }); + }); + + describe('getUserSyncs', () => { + let syncOptions = null; + let expectedSync = null; + + beforeEach(() => { + syncOptions = { + iframeEnabled: true, + pixelEnabled: true, + }; + expectedSync = { + type: 'iframe', + url: 'https://ortb.adpearl.io/usersync/pixels.html?', + }; + }); + + it('should return iframe pixels', () => { + expect(getUserSyncs(syncOptions)).to.deep.equal([expectedSync]); + }); + + it('should return empty when iframe is not enabled', () => { + syncOptions.iframeEnabled = false; + + expect(getUserSyncs(syncOptions)).to.deep.equal([]); + }); + + it('should return sync when GDPR applies', () => { + const gdprConsent = { + gdprApplies: true, + consentString: 'fake-gdpr-consent', + }; + expectedSync.url = expectedSync.url + parseQueryStringParameters({ + gdpr: 1, + consent: 'fake-gdpr-consent', + }); + + expect(getUserSyncs(syncOptions, [], gdprConsent)).to.deep.equal([expectedSync]); + }); + + it('should return sync when GDPR does not apply', () => { + const gdprConsent = { + gdprApplies: false, + }; + expectedSync.url = expectedSync.url + parseQueryStringParameters({ gdpr: 0 }); + + expect(getUserSyncs(syncOptions, [], gdprConsent)).to.deep.equal([expectedSync]); + }); + + it('should return sync with US privacy', () => { + expectedSync.url = expectedSync.url + parseQueryStringParameters({ us_privacy: '1---' }); + + expect(getUserSyncs(syncOptions, [], undefined, '1---')).to.deep.equal([expectedSync]); + }); + }); + + describe('onTimeout', () => { + it('should send timeout data', () => { + const timeoutData = { + bidder: 'pubgenius', + bidId: 'fakebidid', + params: { + adUnitId: 1234, + }, + adUnitCode: 'fake-ad-unit-code', + timeout: 3000, + auctionId: 'fake-auction-id', + }; + onTimeout(timeoutData); + + expect(server.requests[0].method).to.equal('POST'); + expect(server.requests[0].url).to.equal('https://ortb.adpearl.io/prebid/events?type=timeout'); + expect(JSON.parse(server.requests[0].requestBody)).to.deep.equal(timeoutData); + }); + }); +}); diff --git a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js index e9d23692d23..d38037f40a1 100755 --- a/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js @@ -31,6 +31,7 @@ const BID = { 'mediaType': 'video', 'statusMessage': 'Bid available', 'bidId': '2ecff0db240757', + 'partnerImpId': 'partnerImpressionID-1', 'adId': 'fake_ad_id', 'source': 's2s', 'requestId': '2ecff0db240757', @@ -69,6 +70,7 @@ const BID = { const BID2 = Object.assign({}, BID, { adUnitCode: '/19968336/header-bid-tag-1', bidId: '3bd4ebb1c900e2', + partnerImpId: 'partnerImpressionID-2', adId: 'fake_ad_id_2', requestId: '3bd4ebb1c900e2', width: 728, @@ -293,6 +295,14 @@ describe('pubmatic analytics adapter', function () { }); it('Logger: best case + win tracker', function() { + sandbox.stub($$PREBID_GLOBAL$$, 'getHighestCpmBids').callsFake((key) => { + return [MOCK.BID_RESPONSE[0], MOCK.BID_RESPONSE[1]] + }); + + config.setConfig({ + testGroupId: 15 + }); + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[0]); @@ -306,7 +316,7 @@ describe('pubmatic analytics adapter', function () { clock.tick(2000 + 1000); expect(requests.length).to.equal(3); // 1 logger and 2 win-tracker let request = requests[2]; // logger is executed late, trackers execute first - expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999&gdEn=1'); + expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999'); let data = getLoggerJsonFromRequest(request.requestBody); expect(data.pubid).to.equal('9999'); expect(data.pid).to.equal('1111'); @@ -316,8 +326,7 @@ describe('pubmatic analytics adapter', function () { expect(data.purl).to.equal('http://www.test.com/page.html'); expect(data.orig).to.equal('www.test.com'); expect(data.tst).to.equal(1519767016); - expect(data.cns).to.equal('here-goes-gdpr-consent-string'); - expect(data.gdpr).to.equal(1); + expect(data.tgid).to.equal(15); expect(data.s).to.be.an('array'); expect(data.s.length).to.equal(2); // slot 1 @@ -327,6 +336,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[0].ps.length).to.equal(1); expect(data.s[0].ps[0].pn).to.equal('pubmatic'); expect(data.s[0].ps[0].bidid).to.equal('2ecff0db240757'); + expect(data.s[0].ps[0].piid).to.equal('partnerImpressionID-1'); expect(data.s[0].ps[0].db).to.equal(0); expect(data.s[0].ps[0].kgpv).to.equal('/19968336/header-bid-tag-0'); expect(data.s[0].ps[0].kgpsv).to.equal('/19968336/header-bid-tag-0'); @@ -350,6 +360,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps.length).to.equal(1); expect(data.s[1].ps[0].pn).to.equal('pubmatic'); expect(data.s[1].ps[0].bidid).to.equal('3bd4ebb1c900e2'); + expect(data.s[1].ps[0].piid).to.equal('partnerImpressionID-2'); expect(data.s[1].ps[0].db).to.equal(0); expect(data.s[1].ps[0].kgpv).to.equal('this-is-a-kgpv'); expect(data.s[1].ps[0].kgpsv).to.equal('this-is-a-kgpv'); @@ -385,9 +396,136 @@ describe('pubmatic analytics adapter', function () { expect(data.pn).to.equal('pubmatic'); expect(data.eg).to.equal('1.23'); expect(data.en).to.equal('1.23'); + expect(data.piid).to.equal('partnerImpressionID-1'); + }); + + it('bidCpmAdjustment: USD: Logger: best case + win tracker', function() { + const bidCopy = utils.deepClone(BID); + bidCopy.cpm = bidCopy.originalCpm * 2; // bidCpmAdjustment => bidCpm * 2 + + sandbox.stub($$PREBID_GLOBAL$$, 'getHighestCpmBids').callsFake((key) => { + return [bidCopy, MOCK.BID_RESPONSE[1]] + }); + + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BID_RESPONSE, bidCopy); + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[1]); + events.emit(BID_RESPONSE, bidCopy); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(BID_WON, MOCK.BID_WON[0]); + events.emit(BID_WON, MOCK.BID_WON[1]); + + clock.tick(2000 + 1000); + expect(requests.length).to.equal(3); // 1 logger and 2 win-tracker + let request = requests[2]; // logger is executed late, trackers execute first + expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999'); + let data = getLoggerJsonFromRequest(request.requestBody); + expect(data.pubid).to.equal('9999'); + expect(data.pid).to.equal('1111'); + expect(data.s).to.be.an('array'); + expect(data.s.length).to.equal(2); + expect(data.tgid).to.equal(0); + // slot 1 + expect(data.s[0].sn).to.equal('/19968336/header-bid-tag-0'); + expect(data.s[0].sz).to.deep.equal(['640x480']); + expect(data.s[0].ps).to.be.an('array'); + expect(data.s[0].ps.length).to.equal(1); + expect(data.s[0].ps[0].pn).to.equal('pubmatic'); + expect(data.s[0].ps[0].bidid).to.equal('2ecff0db240757'); + expect(data.s[0].ps[0].kgpv).to.equal('/19968336/header-bid-tag-0'); + expect(data.s[0].ps[0].eg).to.equal(1.23); + expect(data.s[0].ps[0].en).to.equal(2.46); + expect(data.s[0].ps[0].wb).to.equal(1); + expect(data.s[0].ps[0].af).to.equal('video'); + expect(data.s[0].ps[0].ocpm).to.equal(1.23); + expect(data.s[0].ps[0].ocry).to.equal('USD'); + // tracker slot1 + let firstTracker = requests[0].url; + expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt'); + data = {}; + firstTracker.split('?')[1].split('&').map(e => e.split('=')).forEach(e => data[e[0]] = e[1]); + expect(data.pubid).to.equal('9999'); + expect(data.tst).to.equal('1519767014'); + expect(data.iid).to.equal('25c6d7f5-699a-4bfc-87c9-996f915341fa'); + expect(data.eg).to.equal('1.23'); + expect(data.en).to.equal('2.46'); + }); + + it('bidCpmAdjustment: JPY: Logger: best case + win tracker', function() { + config.setConfig({ + testGroupId: 25 + }); + + setConfig({ + adServerCurrency: 'JPY', + rates: { + USD: { + JPY: 100 + } + } + }); + const bidCopy = utils.deepClone(BID); + bidCopy.originalCpm = 100; + bidCopy.originalCurrency = 'JPY'; + bidCopy.currency = 'JPY'; + bidCopy.cpm = bidCopy.originalCpm * 2; // bidCpmAdjustment => bidCpm * 2 + + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + // events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[0]); + events.emit(BID_RESPONSE, bidCopy); + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[1]); + events.emit(BID_RESPONSE, bidCopy); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(BID_WON, MOCK.BID_WON[0]); + events.emit(BID_WON, MOCK.BID_WON[1]); + + clock.tick(2000 + 1000); + expect(requests.length).to.equal(3); // 1 logger and 2 win-tracker + let request = requests[2]; // logger is executed late, trackers execute first + expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999'); + let data = getLoggerJsonFromRequest(request.requestBody); + expect(data.pubid).to.equal('9999'); + expect(data.pid).to.equal('1111'); + expect(data.tgid).to.equal(0);// test group id should be between 0-15 else set to 0 + expect(data.s).to.be.an('array'); + expect(data.s.length).to.equal(2); + // slot 1 + expect(data.s[0].sn).to.equal('/19968336/header-bid-tag-0'); + expect(data.s[0].sz).to.deep.equal(['640x480']); + expect(data.s[0].ps).to.be.an('array'); + expect(data.s[0].ps.length).to.equal(1); + expect(data.s[0].ps[0].pn).to.equal('pubmatic'); + expect(data.s[0].ps[0].bidid).to.equal('2ecff0db240757'); + expect(data.s[0].ps[0].kgpv).to.equal('/19968336/header-bid-tag-0'); + expect(data.s[0].ps[0].eg).to.equal(1); + expect(data.s[0].ps[0].en).to.equal(200); + expect(data.s[0].ps[0].wb).to.equal(0); // bidPriceUSD is not getting set as currency module is not added, so unable to set wb to 1 + expect(data.s[0].ps[0].af).to.equal('video'); + expect(data.s[0].ps[0].ocpm).to.equal(100); + expect(data.s[0].ps[0].ocry).to.equal('JPY'); + // tracker slot1 + let firstTracker = requests[0].url; + expect(firstTracker.split('?')[0]).to.equal('https://t.pubmatic.com/wt'); + data = {}; + firstTracker.split('?')[1].split('&').map(e => e.split('=')).forEach(e => data[e[0]] = e[1]); + expect(data.pubid).to.equal('9999'); + expect(data.tst).to.equal('1519767014'); + expect(data.iid).to.equal('25c6d7f5-699a-4bfc-87c9-996f915341fa'); + expect(data.eg).to.equal('1'); + expect(data.en).to.equal('200'); // bidPriceUSD is not getting set as currency module is not added }); it('Logger: when bid is not submitted, default bid status 1 check: pubmatic set as s2s', function() { + config.setConfig({ + testGroupId: '25' + }); + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[0]); @@ -400,6 +538,7 @@ describe('pubmatic analytics adapter', function () { expect(requests.length).to.equal(2); // 1 logger and 1 win-tracker let request = requests[1]; // logger is executed late, trackers execute first let data = getLoggerJsonFromRequest(request.requestBody); + expect(data.tgid).to.equal(0);// test group id should be an INT between 0-15 else set to 0 expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']); expect(data.s[1].ps).to.be.an('array'); @@ -463,6 +602,11 @@ describe('pubmatic analytics adapter', function () { it('Logger: post-timeout check with bid response', function() { // db = 1 and t = 1 means bidder did NOT respond with a bid but we got a timeout notification + + sandbox.stub($$PREBID_GLOBAL$$, 'getHighestCpmBids').callsFake((key) => { + return [MOCK.BID_RESPONSE[1]] + }); + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[1]); @@ -492,7 +636,7 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].l2).to.equal(0); expect(data.s[1].ps[0].ss).to.equal(1); expect(data.s[1].ps[0].t).to.equal(1); - expect(data.s[1].ps[0].wb).to.equal(1); + expect(data.s[1].ps[0].wb).to.equal(1); // todo expect(data.s[1].ps[0].af).to.equal('banner'); expect(data.s[1].ps[0].ocpm).to.equal(1.52); expect(data.s[1].ps[0].ocry).to.equal('USD'); @@ -526,7 +670,7 @@ describe('pubmatic analytics adapter', function () { clock.tick(2000 + 1000); expect(requests.length).to.equal(3); // 1 logger and 2 win-tracker let request = requests[2]; // logger is executed late, trackers execute first - expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999&gdEn=1'); + expect(request.url).to.equal('https://t.pubmatic.com/wl?pubid=9999'); let data = getLoggerJsonFromRequest(request.requestBody); expect(data.s[1].sn).to.equal('/19968336/header-bid-tag-1'); expect(data.s[1].sz).to.deep.equal(['1000x300', '970x250', '728x90']); @@ -538,8 +682,8 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].kgpv).to.equal('this-is-a-kgpv'); expect(data.s[1].ps[0].kgpsv).to.equal('this-is-a-kgpv'); expect(data.s[1].ps[0].psz).to.equal('728x90'); - expect(data.s[1].ps[0].eg).to.equal(undefined); // bidPriceUSD is not getting set as currency module is not added - expect(data.s[1].ps[0].en).to.equal(undefined); // bidPriceUSD is not getting set as currency module is not added + expect(data.s[1].ps[0].eg).to.equal(1); + expect(data.s[1].ps[0].en).to.equal(100); expect(data.s[1].ps[0].di).to.equal('the-deal-id'); expect(data.s[1].ps[0].dc).to.equal('PMP'); expect(data.s[1].ps[0].mi).to.equal('matched-impression'); @@ -552,5 +696,5 @@ describe('pubmatic analytics adapter', function () { expect(data.s[1].ps[0].ocpm).to.equal(100); expect(data.s[1].ps[0].ocry).to.equal('JPY'); }); - }) + }); }); diff --git a/test/spec/modules/pubmaticBidAdapter_spec.js b/test/spec/modules/pubmaticBidAdapter_spec.js index 817661ef51f..37deb0bca9c 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -2,6 +2,7 @@ import {expect} from 'chai'; import {spec} from 'modules/pubmaticBidAdapter.js'; import * as utils from 'src/utils.js'; import {config} from 'src/config.js'; +import { createEidsArray } from 'modules/userId/eids.js'; const constants = require('src/constants.json'); describe('PubMatic adapter', function () { @@ -25,6 +26,9 @@ describe('PubMatic adapter', function () { let bannerBidResponse; let videoBidResponse; let schainConfig; + let outstreamBidRequest; + let validOutstreamBidRequest; + let outstreamVideoBidResponse; beforeEach(function () { schainConfig = { @@ -54,7 +58,7 @@ describe('PubMatic adapter', function () { } }, params: { - publisherId: '301', + publisherId: '5670', adSlot: '/15671365/DMDemo@300x250:0', kadfloor: '1.2', pmzoneid: 'aabc, ddef', @@ -655,7 +659,89 @@ describe('PubMatic adapter', function () { }] }] } - } + }; + outstreamBidRequest = + [ + { + code: 'video1', + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'outstream' + } + }, + bidder: 'pubmatic', + bidId: '47acc48ad47af5', + requestId: '0fb4905b-1234-4152-86be-c6f6d259ba99', + bidderRequestId: '1c56ad30b9b8ca8', + transactionId: '92489f71-1bf2-49a0-adf9-000cea934729', + params: { + publisherId: '5670', + outstreamAU: 'pubmatic-test', + adSlot: 'Div1@0x0', // ad_id or tagid + video: { + mimes: ['video/mp4', 'video/x-flv'], + skippable: true, + minduration: 5, + maxduration: 30 + } + } + } + ]; + + validOutstreamBidRequest = { + auctionId: '92489f71-1bf2-49a0-adf9-000cea934729', + auctionStart: 1585918458868, + bidderCode: 'pubmatic', + bidderRequestId: '47acc48ad47af5', + bids: [{ + adUnitCode: 'video1', + auctionId: '92489f71-1bf2-49a0-adf9-000cea934729', + bidId: '47acc48ad47af5', + bidRequestsCount: 1, + bidder: 'pubmatic', + bidderRequestId: '47acc48ad47af5', + mediaTypes: { + video: { + context: 'outstream' + } + }, + params: { + publisherId: '5670', + outstreamAU: 'pubmatic-test', + adSlot: 'Div1@0x0', // ad_id or tagid + video: { + mimes: ['video/mp4', 'video/x-flv'], + skippable: true, + minduration: 5, + maxduration: 30 + } + }, + sizes: [[768, 432], [640, 480], [630, 360]], + transactionId: '92489f71-1bf2-49a0-adf9-000cea934729' + }], + start: 11585918458869, + timeout: 3000 + }; + + outstreamVideoBidResponse = { + 'body': { + 'id': '93D3BAD6-E2E2-49FB-9D89-920B1761C865', + 'seatbid': [{ + 'bid': [{ + 'id': '0fb4905b-1234-4152-86be-c6f6d259ba99', + 'impid': '47acc48ad47af5', + 'price': 1.3, + 'adm': 'Acudeo CompatibleVAST 2.0 Instream Test 1VAST 2.0 Instream Test 1https://dsptracker.com/{PSPM}00:00:04https://www.pubmatic.com', + 'h': 250, + 'w': 300, + 'ext': { + 'deal_channel': 6 + } + }] + }] + } + }; }); describe('implementation', function () { @@ -710,24 +796,42 @@ describe('PubMatic adapter', function () { describe('Request formation', function () { it('buildRequests function should not modify original bidRequests object', function () { let originalBidRequests = utils.deepClone(bidRequests); - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); expect(bidRequests).to.deep.equal(originalBidRequests); }); it('buildRequests function should not modify original nativebidRequests object', function () { let originalBidRequests = utils.deepClone(nativeBidRequests); - let request = spec.buildRequests(nativeBidRequests); + let request = spec.buildRequests(nativeBidRequests, { + auctionId: 'new-auction-id' + }); expect(nativeBidRequests).to.deep.equal(originalBidRequests); }); it('Endpoint checking', function () { - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); expect(request.url).to.equal('https://hbopenbid.pubmatic.com/translator?source=prebid-client'); expect(request.method).to.equal('POST'); - }); + }); - it('test flag not sent when pubmaticTest=true is absent in page url', function() { + it('should return bidderRequest property', function() { + let request = spec.buildRequests(bidRequests, validOutstreamBidRequest); + expect(request.bidderRequest).to.equal(validOutstreamBidRequest); + }); + + it('bidderRequest should be undefined if bidderRequest is not present', function() { let request = spec.buildRequests(bidRequests); + expect(request.bidderRequest).to.be.undefined; + }); + + it('test flag not sent when pubmaticTest=true is absent in page url', function() { + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.test).to.equal(undefined); }); @@ -737,13 +841,17 @@ describe('PubMatic adapter', function () { xit('test flag set to 1 when pubmaticTest=true is present in page url', function() { window.location.href += '#pubmaticTest=true'; // now all the test cases below will have window.location.href with #pubmaticTest=true - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.test).to.equal(1); }); it('Request params check', function () { - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.at).to.equal(1); // auction type expect(data.cur[0]).to.equal('USD'); // currency @@ -775,6 +883,25 @@ describe('PubMatic adapter', function () { expect(data.source.ext.schain).to.deep.equal(bidRequests[0].schain); }); + it('Set content from config, set site.content', function() { + let sandbox = sinon.sandbox.create(); + const content = { + 'id': 'alpha-numeric-id' + }; + sandbox.stub(config, 'getConfig').callsFake((key) => { + var config = { + content: content + }; + return config[key]; + }); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); + let data = JSON.parse(request.data); + expect(data.site.content).to.deep.equal(content); + sandbox.restore(); + }); + it('Merge the device info from config', function() { let sandbox = sinon.sandbox.create(); sandbox.stub(config, 'getConfig').callsFake((key) => { @@ -785,7 +912,9 @@ describe('PubMatic adapter', function () { }; return config[key]; }); - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.device.js).to.equal(1); expect(data.device.dnt).to.equal((navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0); @@ -807,7 +936,9 @@ describe('PubMatic adapter', function () { }; return config[key]; }); - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.device.js).to.equal(1); expect(data.device.dnt).to.equal((navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0); @@ -829,19 +960,83 @@ describe('PubMatic adapter', function () { }; return config[key]; }); - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); + let data = JSON.parse(request.data); + expect(data.app.bundle).to.equal('org.prebid.mobile.demoapp'); + expect(data.app.domain).to.equal('prebid.org'); + expect(data.app.publisher.id).to.equal(bidRequests[0].params.publisherId); + expect(data.app.ext.key_val).to.exist.and.to.equal(bidRequests[0].params.dctr); + expect(data.site).to.not.exist; + sandbox.restore(); + }); + + it('Set app, content from config, copy publisher and ext from site, unset site, config.content in app.content', function() { + let sandbox = sinon.sandbox.create(); + const content = { + 'id': 'alpha-numeric-id' + }; + sandbox.stub(config, 'getConfig').callsFake((key) => { + var config = { + content: content, + app: { + bundle: 'org.prebid.mobile.demoapp', + domain: 'prebid.org' + } + }; + return config[key]; + }); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); + let data = JSON.parse(request.data); + expect(data.app.bundle).to.equal('org.prebid.mobile.demoapp'); + expect(data.app.domain).to.equal('prebid.org'); + expect(data.app.publisher.id).to.equal(bidRequests[0].params.publisherId); + expect(data.app.ext.key_val).to.exist.and.to.equal(bidRequests[0].params.dctr); + expect(data.app.content).to.deep.equal(content); + expect(data.site).to.not.exist; + sandbox.restore(); + }); + + it('Set app.content, content from config, copy publisher and ext from site, unset site, config.app.content in app.content', function() { + let sandbox = sinon.sandbox.create(); + const content = { + 'id': 'alpha-numeric-id' + }; + const appContent = { + id: 'app-content-id-2' + }; + sandbox.stub(config, 'getConfig').callsFake((key) => { + var config = { + content: content, + app: { + bundle: 'org.prebid.mobile.demoapp', + domain: 'prebid.org', + content: appContent + } + }; + return config[key]; + }); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.app.bundle).to.equal('org.prebid.mobile.demoapp'); expect(data.app.domain).to.equal('prebid.org'); expect(data.app.publisher.id).to.equal(bidRequests[0].params.publisherId); expect(data.app.ext.key_val).to.exist.and.to.equal(bidRequests[0].params.dctr); + expect(data.app.content).to.deep.equal(appContent); expect(data.site).to.not.exist; sandbox.restore(); }); it('Request params check: without adSlot', function () { delete bidRequests[0].params.adSlot; - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.at).to.equal(1); // auction type expect(data.cur[0]).to.equal('USD'); // currency @@ -899,7 +1094,9 @@ describe('PubMatic adapter', function () { } ]; /* case 1 - size passed in adslot */ - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.imp[0].banner.w).to.equal(300); // width @@ -912,7 +1109,9 @@ describe('PubMatic adapter', function () { sizes: [[300, 600], [300, 250]] } }; - request = spec.buildRequests(bidRequests); + request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); expect(data.imp[0].banner.w).to.equal(300); // width @@ -926,7 +1125,9 @@ describe('PubMatic adapter', function () { sizes: [[300, 250], [300, 600]] } }; - request = spec.buildRequests(bidRequests); + request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); expect(data.imp[0].banner.w).to.equal(300); // width @@ -994,7 +1195,9 @@ describe('PubMatic adapter', function () { output: imp[0] and imp[1] both use currency specified in bidRequests[0].params.currency */ - let request = spec.buildRequests(multipleBidRequests); + let request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.imp[0].bidfloorcur).to.equal(bidRequests[0].params.currency); @@ -1006,7 +1209,9 @@ describe('PubMatic adapter', function () { */ delete multipleBidRequests[1].params.currency; - request = spec.buildRequests(multipleBidRequests); + request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); expect(data.imp[0].bidfloorcur).to.equal(bidRequests[0].params.currency); expect(data.imp[1].bidfloorcur).to.equal(bidRequests[0].params.currency); @@ -1017,7 +1222,9 @@ describe('PubMatic adapter', function () { */ delete multipleBidRequests[0].params.currency; - request = spec.buildRequests(multipleBidRequests); + request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); expect(data.imp[0].bidfloorcur).to.equal('USD'); expect(data.imp[1].bidfloorcur).to.equal('USD'); @@ -1028,12 +1235,46 @@ describe('PubMatic adapter', function () { */ multipleBidRequests[1].params.currency = 'AUD'; - request = spec.buildRequests(multipleBidRequests); + request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); expect(data.imp[0].bidfloorcur).to.equal('USD'); expect(data.imp[1].bidfloorcur).to.equal('USD'); }); + it('Pass auctiondId as wiid if wiid is not passed in params', function () { + let bidRequest = { + auctionId: 'new-auction-id' + }; + delete bidRequests[0].params.wiid; + let request = spec.buildRequests(bidRequests, bidRequest); + let data = JSON.parse(request.data); + expect(data.at).to.equal(1); // auction type + expect(data.cur[0]).to.equal('USD'); // currency + expect(data.site.domain).to.be.a('string'); // domain should be set + expect(data.site.page).to.equal(bidRequests[0].params.kadpageurl); // forced pageURL + expect(data.site.publisher.id).to.equal(bidRequests[0].params.publisherId); // publisher Id + expect(data.user.yob).to.equal(parseInt(bidRequests[0].params.yob)); // YOB + expect(data.user.gender).to.equal(bidRequests[0].params.gender); // Gender + expect(data.device.geo.lat).to.equal(parseFloat(bidRequests[0].params.lat)); // Latitude + expect(data.device.geo.lon).to.equal(parseFloat(bidRequests[0].params.lon)); // Lognitude + expect(data.user.geo.lat).to.equal(parseFloat(bidRequests[0].params.lat)); // Latitude + expect(data.user.geo.lon).to.equal(parseFloat(bidRequests[0].params.lon)); // Lognitude + expect(data.ext.wrapper.wv).to.equal($$REPO_AND_VERSION$$); // Wrapper Version + expect(data.ext.wrapper.transactionId).to.equal(bidRequests[0].transactionId); // Prebid TransactionId + expect(data.ext.wrapper.wiid).to.equal('new-auction-id'); // OpenWrap: Wrapper Impression ID + expect(data.ext.wrapper.profile).to.equal(parseInt(bidRequests[0].params.profId)); // OpenWrap: Wrapper Profile ID + expect(data.ext.wrapper.version).to.equal(parseInt(bidRequests[0].params.verId)); // OpenWrap: Wrapper Profile Version ID + + expect(data.imp[0].id).to.equal(bidRequests[0].bidId); // Prebid bid id is passed as id + expect(data.imp[0].bidfloor).to.equal(parseFloat(bidRequests[0].params.kadfloor)); // kadfloor + expect(data.imp[0].tagid).to.equal('/15671365/DMDemo'); // tagid + expect(data.imp[0].banner.w).to.equal(300); // width + expect(data.imp[0].banner.h).to.equal(250); // height + expect(data.imp[0].ext.pmZoneId).to.equal(bidRequests[0].params.pmzoneid.split(',').slice(0, 50).map(id => id.trim()).join()); // pmzoneid + }); + it('Request params check with GDPR Consent', function () { let bidRequest = { gdprConsent: { @@ -1107,318 +1348,144 @@ describe('PubMatic adapter', function () { expect(data2.regs).to.equal(undefined);// USP/CCPAs }); - it('Request should have digitrust params', function() { - window.DigiTrust = { - getUser: function () { - } - }; - var bidRequest = {}; - let sandbox = sinon.sandbox.create(); - sandbox.stub(window.DigiTrust, 'getUser').callsFake(() => - ({ - success: true, - identity: { - privacy: {optout: false}, - id: 'testId', - keyv: 4 - } - }) - ); - - let request = spec.buildRequests(bidRequests, bidRequest); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal([{ - 'source': 'digitru.st', - 'uids': [{ - 'id': 'testId', - 'atype': 1, - 'ext': { - 'keyv': 4 - } - }] - }]); - sandbox.restore(); - delete window.DigiTrust; - }); - - it('Request should not have digitrust params when DigiTrust not loaded', function() { - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); - }); - - it('Request should not have digitrust params due to optout', function() { - window.DigiTrust = { - getUser: function () { - } - }; - let sandbox = sinon.sandbox.create(); - sandbox.stub(window.DigiTrust, 'getUser').callsFake(() => - ({ - success: true, - identity: { - privacy: {optout: true}, - id: 'testId', - keyv: 4 - } - }) - ); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); - sandbox.restore(); - delete window.DigiTrust; - }); + describe('setting imp.floor using floorModule', function() { + /* + Use the minimum value among floor from floorModule per mediaType + If params.adfloor is set then take max(kadfloor, min(floors from floorModule)) + set imp.bidfloor only if it is more than 0 + */ - it('Request should not have digitrust params due to failure', function() { - window.DigiTrust = { - getUser: function () { - } + let newRequest; + let floorModuleTestData; + let getFloor = function(req) { + return floorModuleTestData[req.mediaType]; }; - let sandbox = sinon.sandbox.create(); - sandbox.stub(window.DigiTrust, 'getUser').callsFake(() => - ({ - success: false, - identity: { - privacy: {optout: false}, - id: 'testId', - keyv: 4 - } - }) - ); - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); - sandbox.restore(); - delete window.DigiTrust; - }); - - describe('DigiTrustId from config', function() { - var origGetConfig; - let sandbox; beforeEach(() => { - sandbox = sinon.sandbox.create(); - window.DigiTrust = { - getUser: sandbox.spy() - }; - }); - - afterEach(() => { - sandbox.restore(); - delete window.DigiTrust; - }); - - it('Request should have digiTrustId config params', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - digiTrustId: { - success: true, - identity: { - privacy: {optout: false}, - id: 'testId', - keyv: 4 - } - } - }; - return config[key]; - }); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal([{ - 'source': 'digitru.st', - 'uids': [{ - 'id': 'testId', - 'atype': 1, - 'ext': { - 'keyv': 4 - } - }] - }]); - // should not have called DigiTrust.getUser() - expect(window.DigiTrust.getUser.notCalled).to.equal(true); - }); - - it('Request should not have digiTrustId config params due to optout', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - digiTrustId: { - success: true, - identity: { - privacy: {optout: true}, - id: 'testId', - keyv: 4 - } - } - } - return config[key]; - }); - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); - // should not have called DigiTrust.getUser() - expect(window.DigiTrust.getUser.notCalled).to.equal(true); - }); - - it('Request should not have digiTrustId config params due to failure', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - digiTrustId: { - success: false, - identity: { - privacy: {optout: false}, - id: 'testId', - keyv: 4 - } - } - } - return config[key]; - }); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); - // should not have called DigiTrust.getUser() - expect(window.DigiTrust.getUser.notCalled).to.equal(true); - }); - - it('Request should not have digiTrustId config params if they do not exist', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = {}; - return config[key]; - }); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); - // should have called DigiTrust.getUser() once - expect(window.DigiTrust.getUser.calledOnce).to.equal(true); - }); - - it('should NOT include coppa flag in bid request if coppa config is not present', () => { - const request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - if (data.regs) { - // in case GDPR is set then data.regs will exist - expect(data.regs.coppa).to.equal(undefined); - } else { - expect(data.regs).to.equal(undefined); - } - }); - - it('should include coppa flag in bid request if coppa is set to true', () => { - sandbox.stub(config, 'getConfig').callsFake(key => { - const config = { - 'coppa': true - }; - return config[key]; - }); - const request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.regs.coppa).to.equal(1); - }); - - it('should NOT include coppa flag in bid request if coppa is set to false', () => { - sandbox.stub(config, 'getConfig').callsFake(key => { - const config = { - 'coppa': false - }; - return config[key]; - }); - const request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - if (data.regs) { - // in case GDPR is set then data.regs will exist - expect(data.regs.coppa).to.equal(undefined); - } else { - expect(data.regs).to.equal(undefined); - } - }); - }); - - describe('AdsrvrOrgId from config', function() { - let sandbox; - beforeEach(() => { - sandbox = sinon.sandbox.create(); - }); - - afterEach(() => { - sandbox.restore(); - }); - - it('Request should have adsrvrOrgId config params', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - adsrvrOrgId: { - 'TDID': '5e740345-c25e-436d-b466-5f2f9fa95c17', - 'TDID_LOOKUP': 'TRUE', - 'TDID_CREATED_AT': '2018-10-01T07:05:40' - } - }; - return config[key]; - }); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal([{ - 'source': 'adserver.org', - 'uids': [{ - 'id': '5e740345-c25e-436d-b466-5f2f9fa95c17', - 'atype': 1, - 'ext': { - 'rtiPartner': 'TDID' - } - }] - }]); + floorModuleTestData = { + 'banner': { + 'currency': 'USD', + 'floor': 1.50 + }, + 'video': { + 'currency': 'USD', + 'floor': 2.50 + }, + 'native': { + 'currency': 'USD', + 'floor': 3.50 + } + }; + newRequest = utils.deepClone(bannerVideoAndNativeBidRequests); + newRequest[0].getFloor = getFloor; }); - it('Request should NOT have adsrvrOrgId config params if id in adsrvrOrgId is NOT string', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - adsrvrOrgId: { - 'TDID': 1, - 'TDID_LOOKUP': 'TRUE', - 'TDID_CREATED_AT': '2018-10-01T07:05:40' - } - }; - return config[key]; + it('bidfloor should be undefined if calculation is <= 0', function() { + floorModuleTestData.banner.floor = 0; // lowest of them all + newRequest[0].params.kadfloor = undefined; + let request = spec.buildRequests(newRequest, { + auctionId: 'new-auction-id' }); + let data = JSON.parse(request.data); + data = data.imp[0]; + expect(data.bidfloor).to.equal(undefined); + }); - let request = spec.buildRequests(bidRequests, {}); + it('ignore floormodule o/p if floor is not number', function() { + floorModuleTestData.banner.floor = 'INR'; + newRequest[0].params.kadfloor = undefined; + let request = spec.buildRequests(newRequest, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); + data = data.imp[0]; + expect(data.bidfloor).to.equal(2.5); // video will be lowest now }); - it('Request should NOT have adsrvrOrgId config params if adsrvrOrgId is NOT object', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - adsrvrOrgId: null - }; - return config[key]; + it('ignore floormodule o/p if currency is not matched', function() { + floorModuleTestData.banner.currency = 'INR'; + newRequest[0].params.kadfloor = undefined; + let request = spec.buildRequests(newRequest, { + auctionId: 'new-auction-id' }); + let data = JSON.parse(request.data); + data = data.imp[0]; + expect(data.bidfloor).to.equal(2.5); // video will be lowest now + }); - let request = spec.buildRequests(bidRequests, {}); + it('kadfloor is not passed, use minimum from floorModule', function() { + newRequest[0].params.kadfloor = undefined; + let request = spec.buildRequests(newRequest, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); + data = data.imp[0]; + expect(data.bidfloor).to.equal(1.5); }); - it('Request should NOT have adsrvrOrgId config params if id in adsrvrOrgId is NOT set', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - adsrvrOrgId: { - 'TDID_LOOKUP': 'TRUE', - 'TDID_CREATED_AT': '2018-10-01T07:05:40' - } - }; - return config[key]; + it('kadfloor is passed as 3, use kadfloor as it is highest', function() { + newRequest[0].params.kadfloor = '3.0';// yes, we want it as a string + let request = spec.buildRequests(newRequest, { + auctionId: 'new-auction-id' }); + let data = JSON.parse(request.data); + data = data.imp[0]; + expect(data.bidfloor).to.equal(3); + }); - let request = spec.buildRequests(bidRequests, {}); + it('kadfloor is passed as 1, use min of fllorModule as it is highest', function() { + newRequest[0].params.kadfloor = '1.0';// yes, we want it as a string + let request = spec.buildRequests(newRequest, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); + data = data.imp[0]; + expect(data.bidfloor).to.equal(1.5); + }); + }); + + it('should NOT include coppa flag in bid request if coppa config is not present', () => { + const request = spec.buildRequests(bidRequests, {}); + let data = JSON.parse(request.data); + if (data.regs) { + // in case GDPR is set then data.regs will exist + expect(data.regs.coppa).to.equal(undefined); + } else { + expect(data.regs).to.equal(undefined); + } + }); + + it('should include coppa flag in bid request if coppa is set to true', () => { + let sandbox = sinon.sandbox.create(); + sandbox.stub(config, 'getConfig').callsFake(key => { + const config = { + 'coppa': true + }; + return config[key]; + }); + const request = spec.buildRequests(bidRequests, {}); + let data = JSON.parse(request.data); + expect(data.regs.coppa).to.equal(1); + sandbox.restore(); + }); + + it('should NOT include coppa flag in bid request if coppa is set to false', () => { + let sandbox = sinon.sandbox.create(); + sandbox.stub(config, 'getConfig').callsFake(key => { + const config = { + 'coppa': false + }; + return config[key]; }); + const request = spec.buildRequests(bidRequests, {}); + let data = JSON.parse(request.data); + if (data.regs) { + // in case GDPR is set then data.regs will exist + expect(data.regs.coppa).to.equal(undefined); + } else { + expect(data.regs).to.equal(undefined); + } + sandbox.restore(); }); describe('AdsrvrOrgId from userId module', function() { @@ -1434,6 +1501,7 @@ describe('PubMatic adapter', function () { it('Request should have AdsrvrOrgId config params', function() { bidRequests[0].userId = {}; bidRequests[0].userId.tdid = 'TTD_ID_FROM_USER_ID_MODULE'; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.deep.equal([{ @@ -1461,6 +1529,7 @@ describe('PubMatic adapter', function () { }); bidRequests[0].userId = {}; bidRequests[0].userId.tdid = 'TTD_ID_FROM_USER_ID_MODULE'; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.deep.equal([{ @@ -1491,161 +1560,12 @@ describe('PubMatic adapter', function () { }); }); - describe('AdsrvrOrgId and Digitrust', function() { - // here we are considering cases only of accepting DigiTrustId from config - let sandbox; - beforeEach(() => { - sandbox = sinon.sandbox.create(); - window.DigiTrust = { - getUser: sandbox.spy() - }; - }); - - afterEach(() => { - sandbox.restore(); - delete window.DigiTrust; - }); - - it('Request should have id of both AdsrvrOrgId and Digitrust if both have returned valid ids', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - adsrvrOrgId: { - 'TDID': '5e740345-c25e-436d-b466-5f2f9fa95c17', - 'TDID_LOOKUP': 'TRUE', - 'TDID_CREATED_AT': '2018-10-01T07:05:40' - }, - digiTrustId: { - success: true, - identity: { - privacy: {optout: false}, - id: 'testId', - keyv: 4 - } - } - }; - return config[key]; - }); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal([{ - 'source': 'digitru.st', - 'uids': [{ - 'id': 'testId', - 'atype': 1, - 'ext': { - 'keyv': 4 - } - }] - }, { - 'source': 'adserver.org', - 'uids': [{ - 'id': '5e740345-c25e-436d-b466-5f2f9fa95c17', - 'atype': 1, - 'ext': { - 'rtiPartner': 'TDID' - } - }] - }]); - }); - - it('Request should have id of only AdsrvrOrgId and NOT Digitrust if only AdsrvrOrgId have returned valid id', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - adsrvrOrgId: { - 'TDID': '5e740345-c25e-436d-b466-5f2f9fa95c17', - 'TDID_LOOKUP': 'TRUE', - 'TDID_CREATED_AT': '2018-10-01T07:05:40' - }, - digiTrustId: { - success: true, - identity: { - privacy: {optout: true}, - id: 'testId', - keyv: 4 - } - } - }; - return config[key]; - }); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal([{ - 'source': 'adserver.org', - 'uids': [{ - 'id': '5e740345-c25e-436d-b466-5f2f9fa95c17', - 'atype': 1, - 'ext': { - 'rtiPartner': 'TDID' - } - }] - }]); - }); - - it('Request should have id of only Digitrust and NOT AdsrvrOrgId if only Digitrust have returned valid id', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - adsrvrOrgId: { - 'TDID_LOOKUP': 'TRUE', - 'TDID_CREATED_AT': '2018-10-01T07:05:40' - }, - digiTrustId: { - success: true, - identity: { - privacy: {optout: false}, - id: 'testId', - keyv: 4 - } - } - }; - return config[key]; - }); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal([{ - 'source': 'digitru.st', - 'uids': [{ - 'id': 'testId', - 'atype': 1, - 'ext': { - 'keyv': 4 - } - }] - }]); - }); - - it('Request should NOT have id of Digitrust and NOT AdsrvrOrgId if only both have NOT returned valid ids', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - var config = { - adsrvrOrgId: { - 'TDID_LOOKUP': 'TRUE', - 'TDID_CREATED_AT': '2018-10-01T07:05:40' - }, - digiTrustId: { - success: true, - identity: { - privacy: {optout: true}, - id: 'testId', - keyv: 4 - } - } - }; - return config[key]; - }); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); - }); - }); - describe('UserIds from request', function() { describe('pubcommon Id', function() { it('send the pubcommon id if it is present', function() { bidRequests[0].userId = {}; bidRequests[0].userId.pubcid = 'pub_common_user_id'; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.deep.equal([{ @@ -1660,54 +1580,22 @@ describe('PubMatic adapter', function () { it('do not pass if not string', function() { bidRequests[0].userId = {}; bidRequests[0].userId.pubcid = 1; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.pubcid = []; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.pubcid = null; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.pubcid = {}; - request = spec.buildRequests(bidRequests, {}); - data = JSON.parse(request.data); - expect(data.user.eids).to.equal(undefined); - }); - }); - - describe('Digitrust Id', function() { - it('send the digitrust id if it is present', function() { - bidRequests[0].userId = {}; - bidRequests[0].userId.digitrustid = {data: {id: 'digitrust_user_id'}}; - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal([{ - 'source': 'digitru.st', - 'uids': [{ - 'id': 'digitrust_user_id', - 'atype': 1 - }] - }]); - }); - - it('do not pass if not string', function() { - bidRequests[0].userId = {}; - bidRequests[0].userId.digitrustid = {data: {id: 1}}; - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.equal(undefined); - bidRequests[0].userId.digitrustid = {data: {id: []}}; - request = spec.buildRequests(bidRequests, {}); - data = JSON.parse(request.data); - expect(data.user.eids).to.equal(undefined); - bidRequests[0].userId.digitrustid = {data: {id: null}}; - request = spec.buildRequests(bidRequests, {}); - data = JSON.parse(request.data); - expect(data.user.eids).to.equal(undefined); - bidRequests[0].userId.digitrustid = {data: {id: {}}}; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); @@ -1717,7 +1605,8 @@ describe('PubMatic adapter', function () { describe('ID5 Id', function() { it('send the id5 id if it is present', function() { bidRequests[0].userId = {}; - bidRequests[0].userId.id5id = 'id5-user-id'; + bidRequests[0].userId.id5id = { uid: 'id5-user-id' }; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.deep.equal([{ @@ -1731,19 +1620,23 @@ describe('PubMatic adapter', function () { it('do not pass if not string', function() { bidRequests[0].userId = {}; - bidRequests[0].userId.id5id = 1; + bidRequests[0].userId.id5id = { uid: 1 }; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); - bidRequests[0].userId.id5id = []; + bidRequests[0].userId.id5id = { uid: [] }; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); - bidRequests[0].userId.id5id = null; + bidRequests[0].userId.id5id = { uid: null }; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); - bidRequests[0].userId.id5id = {}; + bidRequests[0].userId.id5id = { uid: {} }; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); @@ -1754,6 +1647,7 @@ describe('PubMatic adapter', function () { it('send the criteo id if it is present', function() { bidRequests[0].userId = {}; bidRequests[0].userId.criteoId = 'criteo-user-id'; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.deep.equal([{ @@ -1768,18 +1662,22 @@ describe('PubMatic adapter', function () { it('do not pass if not string', function() { bidRequests[0].userId = {}; bidRequests[0].userId.criteoId = 1; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.criteoId = []; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.criteoId = null; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.criteoId = {}; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); @@ -1790,6 +1688,7 @@ describe('PubMatic adapter', function () { it('send the identity-link id if it is present', function() { bidRequests[0].userId = {}; bidRequests[0].userId.idl_env = 'identity-link-user-id'; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.deep.equal([{ @@ -1804,18 +1703,22 @@ describe('PubMatic adapter', function () { it('do not pass if not string', function() { bidRequests[0].userId = {}; bidRequests[0].userId.idl_env = 1; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.idl_env = []; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.idl_env = null; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.idl_env = {}; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); @@ -1826,6 +1729,7 @@ describe('PubMatic adapter', function () { it('send the LiveIntent id if it is present', function() { bidRequests[0].userId = {}; bidRequests[0].userId.lipb = { lipbid: 'live-intent-user-id' }; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.deep.equal([{ @@ -1840,18 +1744,22 @@ describe('PubMatic adapter', function () { it('do not pass if not string', function() { bidRequests[0].userId = {}; bidRequests[0].userId.lipb = { lipbid: 1 }; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.lipb.lipbid = []; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.lipb.lipbid = null; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.lipb.lipbid = {}; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); @@ -1861,7 +1769,8 @@ describe('PubMatic adapter', function () { describe('Parrable Id', function() { it('send the Parrable id if it is present', function() { bidRequests[0].userId = {}; - bidRequests[0].userId.parrableid = 'parrable-user-id'; + bidRequests[0].userId.parrableId = { eid: 'parrable-user-id' }; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.deep.equal([{ @@ -1873,21 +1782,25 @@ describe('PubMatic adapter', function () { }]); }); - it('do not pass if not string', function() { + it('do not pass if not object with eid key', function() { bidRequests[0].userId = {}; bidRequests[0].userId.parrableid = 1; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.parrableid = []; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.parrableid = null; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.parrableid = {}; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); @@ -1898,6 +1811,7 @@ describe('PubMatic adapter', function () { it('send the Britepool id if it is present', function() { bidRequests[0].userId = {}; bidRequests[0].userId.britepoolid = 'britepool-user-id'; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.deep.equal([{ @@ -1912,18 +1826,22 @@ describe('PubMatic adapter', function () { it('do not pass if not string', function() { bidRequests[0].userId = {}; bidRequests[0].userId.britepoolid = 1; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.britepoolid = []; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.britepoolid = null; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.britepoolid = {}; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); @@ -1934,6 +1852,7 @@ describe('PubMatic adapter', function () { it('send the NetId if it is present', function() { bidRequests[0].userId = {}; bidRequests[0].userId.netId = 'netid-user-id'; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.deep.equal([{ @@ -1948,18 +1867,22 @@ describe('PubMatic adapter', function () { it('do not pass if not string', function() { bidRequests[0].userId = {}; bidRequests[0].userId.netId = 1; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); let request = spec.buildRequests(bidRequests, {}); let data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.netId = []; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.netId = null; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); bidRequests[0].userId.netId = {}; + bidRequests[0].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); @@ -1968,7 +1891,9 @@ describe('PubMatic adapter', function () { }); it('Request params check for video ad', function () { - let request = spec.buildRequests(videoBidRequests); + let request = spec.buildRequests(videoBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.imp[0].video).to.exist; expect(data.imp[0].tagid).to.equal('Div1'); @@ -2006,7 +1931,9 @@ describe('PubMatic adapter', function () { }); it('Request params check for 1 banner and 1 video ad', function () { - let request = spec.buildRequests(multipleMediaRequests); + let request = spec.buildRequests(multipleMediaRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.imp).to.be.an('array') @@ -2074,7 +2001,9 @@ describe('PubMatic adapter', function () { }); it('Request params should have valid native bid request for all valid params', function () { - let request = spec.buildRequests(nativeBidRequests); + let request = spec.buildRequests(nativeBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.imp[0].native).to.exist; expect(data.imp[0].native['request']).to.exist; @@ -2084,13 +2013,17 @@ describe('PubMatic adapter', function () { }); it('Request params should not have valid native bid request for non native request', function () { - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.imp[0].native).to.not.exist; }); it('Request params should have valid native bid request with valid required param values for all valid params', function () { - let request = spec.buildRequests(nativeBidRequestsWithRequiredParam); + let request = spec.buildRequests(nativeBidRequestsWithRequiredParam, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.imp[0].native).to.exist; expect(data.imp[0].native['request']).to.exist; @@ -2100,12 +2033,16 @@ describe('PubMatic adapter', function () { }); it('should not have valid native request if assets are not defined with minimum required params and only native is the slot', function () { - let request = spec.buildRequests(nativeBidRequestsWithoutAsset); + let request = spec.buildRequests(nativeBidRequestsWithoutAsset, { + auctionId: 'new-auction-id' + }); expect(request).to.deep.equal(undefined); }); it('Request params should have valid native bid request for all native params', function () { - let request = spec.buildRequests(nativeBidRequestsWithAllParams); + let request = spec.buildRequests(nativeBidRequestsWithAllParams, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.imp[0].native).to.exist; expect(data.imp[0].native['request']).to.exist; @@ -2115,7 +2052,9 @@ describe('PubMatic adapter', function () { }); it('Request params - should handle banner and video format in single adunit', function() { - let request = spec.buildRequests(bannerAndVideoBidRequests); + let request = spec.buildRequests(bannerAndVideoBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); data = data.imp[0]; expect(data.banner).to.exist; @@ -2126,7 +2065,9 @@ describe('PubMatic adapter', function () { // Case: when size is not present in adslo bannerAndVideoBidRequests[0].params.adSlot = '/15671365/DMDemo'; - request = spec.buildRequests(bannerAndVideoBidRequests); + request = spec.buildRequests(bannerAndVideoBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); data = data.imp[0]; expect(data.banner).to.exist; @@ -2148,7 +2089,9 @@ describe('PubMatic adapter', function () { */ bannerAndVideoBidRequests[0].mediaTypes.banner.sizes = [['fluid'], [160, 600]]; - let request = spec.buildRequests(bannerAndVideoBidRequests); + let request = spec.buildRequests(bannerAndVideoBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); data = data.imp[0]; @@ -2167,7 +2110,9 @@ describe('PubMatic adapter', function () { bannerAndVideoBidRequests[0].mediaTypes.banner.sizes = [['fluid'], [160, 600]]; bannerAndVideoBidRequests[0].params.adSlot = '/15671365/DMDemo'; - request = spec.buildRequests(bannerAndVideoBidRequests); + request = spec.buildRequests(bannerAndVideoBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); data = data.imp[0]; @@ -2185,7 +2130,9 @@ describe('PubMatic adapter', function () { */ bannerAndVideoBidRequests[0].mediaTypes.banner.sizes = [[728, 90], ['fluid'], [300, 250]]; - request = spec.buildRequests(bannerAndVideoBidRequests); + request = spec.buildRequests(bannerAndVideoBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); data = data.imp[0]; @@ -2203,7 +2150,9 @@ describe('PubMatic adapter', function () { */ bannerAndVideoBidRequests[0].mediaTypes.banner.sizes = [['fluid']]; - request = spec.buildRequests(bannerAndVideoBidRequests); + request = spec.buildRequests(bannerAndVideoBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); data = data.imp[0]; @@ -2215,14 +2164,18 @@ describe('PubMatic adapter', function () { delete bannerAndVideoBidRequests[0].mediaTypes.banner; bannerAndVideoBidRequests[0].params.sizes = [300, 250]; - let request = spec.buildRequests(bannerAndVideoBidRequests); + let request = spec.buildRequests(bannerAndVideoBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); data = data.imp[0]; expect(data.banner).to.not.exist; }); it('Request params - should handle banner and native format in single adunit', function() { - let request = spec.buildRequests(bannerAndNativeBidRequests); + let request = spec.buildRequests(bannerAndNativeBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); data = data.imp[0]; @@ -2237,7 +2190,9 @@ describe('PubMatic adapter', function () { }); it('Request params - should handle video and native format in single adunit', function() { - let request = spec.buildRequests(videoAndNativeBidRequests); + let request = spec.buildRequests(videoAndNativeBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); data = data.imp[0]; @@ -2250,7 +2205,9 @@ describe('PubMatic adapter', function () { }); it('Request params - should handle banner, video and native format in single adunit', function() { - let request = spec.buildRequests(bannerVideoAndNativeBidRequests); + let request = spec.buildRequests(bannerVideoAndNativeBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); data = data.imp[0]; @@ -2272,7 +2229,9 @@ describe('PubMatic adapter', function () { delete bannerAndNativeBidRequests[0].mediaTypes.banner; bannerAndNativeBidRequests[0].sizes = [729, 90]; - let request = spec.buildRequests(bannerAndNativeBidRequests); + let request = spec.buildRequests(bannerAndNativeBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); data = data.imp[0]; @@ -2295,7 +2254,9 @@ describe('PubMatic adapter', function () { sponsoredBy: { required: true }, clickUrl: { required: true } } - let request = spec.buildRequests(bannerAndNativeBidRequests); + let request = spec.buildRequests(bannerAndNativeBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); data = data.imp[0]; @@ -2316,7 +2277,9 @@ describe('PubMatic adapter', function () { sponsoredBy: { required: true }, clickUrl: { required: true } } - let request = spec.buildRequests(videoAndNativeBidRequests); + let request = spec.buildRequests(videoAndNativeBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); data = data.imp[0]; @@ -2379,7 +2342,9 @@ describe('PubMatic adapter', function () { } ]; - let request = spec.buildRequests(multipleBidRequests); + let request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); /* case 1 - @@ -2393,7 +2358,9 @@ describe('PubMatic adapter', function () { dctr not present in adunit[0] */ delete multipleBidRequests[0].params.dctr; - request = spec.buildRequests(multipleBidRequests); + request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); expect(data.site.ext).to.not.exist; @@ -2402,7 +2369,9 @@ describe('PubMatic adapter', function () { dctr is present in adunit[0], but is not a string value */ multipleBidRequests[0].params.dctr = 123; - request = spec.buildRequests(multipleBidRequests); + request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); expect(data.site.ext).to.not.exist; @@ -2462,7 +2431,9 @@ describe('PubMatic adapter', function () { } ]; - let request = spec.buildRequests(multipleBidRequests); + let request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); // case 1 - deals are passed as expected, ['', ''] , in both adUnits expect(data.imp[0].pmp).to.deep.equal({ @@ -2490,19 +2461,25 @@ describe('PubMatic adapter', function () { // case 2 - deals not present in adunit[0] delete multipleBidRequests[0].params.deals; - request = spec.buildRequests(multipleBidRequests); + request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); expect(data.imp[0].pmp).to.not.exist; // case 3 - deals is present in adunit[0], but is not an array multipleBidRequests[0].params.deals = 123; - request = spec.buildRequests(multipleBidRequests); + request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); expect(data.imp[0].pmp).to.not.exist; // case 4 - deals is present in adunit[0] as an array but one of the value is not a string multipleBidRequests[0].params.deals = [123, 'deal-id-1']; - request = spec.buildRequests(multipleBidRequests); + request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); data = JSON.parse(request.data); expect(data.imp[0].pmp).to.deep.equal({ 'private_auction': 0, @@ -2570,21 +2547,27 @@ describe('PubMatic adapter', function () { it('bcat: pass only strings', function() { multipleBidRequests[0].params.bcat = [1, 2, 3, 'IAB1', 'IAB2']; - let request = spec.buildRequests(multipleBidRequests); + let request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.bcat).to.exist.and.to.deep.equal(['IAB1', 'IAB2']); }); it('bcat: pass strings with length greater than 3', function() { multipleBidRequests[0].params.bcat = ['AB', 'CD', 'IAB1', 'IAB2']; - let request = spec.buildRequests(multipleBidRequests); + let request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.bcat).to.exist.and.to.deep.equal(['IAB1', 'IAB2']); }); it('bcat: trim the strings', function() { multipleBidRequests[0].params.bcat = [' IAB1 ', ' IAB2 ']; - let request = spec.buildRequests(multipleBidRequests); + let request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.bcat).to.exist.and.to.deep.equal(['IAB1', 'IAB2']); }); @@ -2593,7 +2576,9 @@ describe('PubMatic adapter', function () { // multi slot multipleBidRequests[0].params.bcat = ['IAB1', 'IAB2', 'IAB1', 'IAB2', 'IAB1', 'IAB2']; multipleBidRequests[1].params.bcat = ['IAB1', 'IAB2', 'IAB1', 'IAB2', 'IAB1', 'IAB3']; - let request = spec.buildRequests(multipleBidRequests); + let request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.bcat).to.exist.and.to.deep.equal(['IAB1', 'IAB2', 'IAB3']); }); @@ -2602,7 +2587,9 @@ describe('PubMatic adapter', function () { // multi slot multipleBidRequests[0].params.bcat = ['', 'IAB', 'IAB']; multipleBidRequests[1].params.bcat = [' ', 22, 99999, 'IA']; - let request = spec.buildRequests(multipleBidRequests); + let request = spec.buildRequests(multipleBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); expect(data.bcat).to.deep.equal(undefined); }); @@ -2610,7 +2597,9 @@ describe('PubMatic adapter', function () { describe('Response checking', function () { it('should check for valid response values', function () { - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); let response = spec.interpretResponse(bidResponses, request); expect(response).to.be.an('array').with.length.above(0); @@ -2631,10 +2620,12 @@ describe('PubMatic adapter', function () { expect(response[0].adserverTargeting.hb_buyid_pubmatic).to.equal('BUYER-ID-987'); expect(response[0].meta.buyerId).to.equal(976); expect(response[0].meta.clickUrl).to.equal('blackrock.com'); + expect(response[0].meta.advertiserDomains[0]).to.equal('blackrock.com'); expect(response[0].referrer).to.include(data.site.ref); expect(response[0].ad).to.equal(bidResponses.body.seatbid[0].bid[0].adm); expect(response[0].pm_seat).to.equal(bidResponses.body.seatbid[0].seat); expect(response[0].pm_dspid).to.equal(bidResponses.body.seatbid[0].bid[0].ext.dspid); + expect(response[0].partnerImpId).to.equal(bidResponses.body.seatbid[0].bid[0].id); expect(response[1].requestId).to.equal(bidResponses.body.seatbid[1].bid[0].impid); expect(response[1].cpm).to.equal((bidResponses.body.seatbid[1].bid[0].price).toFixed(2)); @@ -2653,14 +2644,18 @@ describe('PubMatic adapter', function () { expect(response[1].adserverTargeting.hb_buyid_pubmatic).to.equal('BUYER-ID-789'); expect(response[1].meta.buyerId).to.equal(832); expect(response[1].meta.clickUrl).to.equal('hivehome.com'); + expect(response[1].meta.advertiserDomains[0]).to.equal('hivehome.com'); expect(response[1].referrer).to.include(data.site.ref); expect(response[1].ad).to.equal(bidResponses.body.seatbid[1].bid[0].adm); expect(response[1].pm_seat).to.equal(bidResponses.body.seatbid[1].seat || null); expect(response[1].pm_dspid).to.equal(bidResponses.body.seatbid[1].bid[0].ext.dspid); + expect(response[0].partnerImpId).to.equal(bidResponses.body.seatbid[0].bid[0].id); }); it('should check for dealChannel value selection', function () { - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let response = spec.interpretResponse(bidResponses, request); expect(response).to.be.an('array').with.length.above(0); expect(response[0].dealChannel).to.equal('PMPG'); @@ -2668,7 +2663,9 @@ describe('PubMatic adapter', function () { }); it('should check for unexpected dealChannel value selection', function () { - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let updateBiResponse = bidResponses; updateBiResponse.body.seatbid[0].bid[0].ext.deal_channel = 11; @@ -2679,7 +2676,9 @@ describe('PubMatic adapter', function () { }); it('should have a valid native bid response', function() { - let request = spec.buildRequests(nativeBidRequests); + let request = spec.buildRequests(nativeBidRequests, { + auctionId: 'new-auction-id' + }); let data = JSON.parse(request.data); data.imp[0].id = '2a5571261281d4'; request.data = JSON.stringify(data); @@ -2697,25 +2696,68 @@ describe('PubMatic adapter', function () { }); it('should check for valid banner mediaType in case of multiformat request', function() { - let request = spec.buildRequests(bidRequests); + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); let response = spec.interpretResponse(bannerBidResponse, request); expect(response[0].mediaType).to.equal('banner'); }); it('should check for valid video mediaType in case of multiformat request', function() { - let request = spec.buildRequests(videoBidRequests); + let request = spec.buildRequests(videoBidRequests, { + auctionId: 'new-auction-id' + }); let response = spec.interpretResponse(videoBidResponse, request); - expect(response[0].mediaType).to.equal('video'); }); it('should check for valid native mediaType in case of multiformat request', function() { - let request = spec.buildRequests(nativeBidRequests); + let request = spec.buildRequests(nativeBidRequests, { + auctionId: 'new-auction-id' + }); let response = spec.interpretResponse(nativeBidResponse, request); expect(response[0].mediaType).to.equal('native'); }); + + it('should assign renderer if bid is video and request is for outstream', function() { + let request = spec.buildRequests(outstreamBidRequest, validOutstreamBidRequest); + let response = spec.interpretResponse(outstreamVideoBidResponse, request); + expect(response[0].renderer).to.exist; + }); + + it('should not assign renderer if bidderRequest is not present', function() { + let request = spec.buildRequests(outstreamBidRequest, { + auctionId: 'new-auction-id' + }); + let response = spec.interpretResponse(outstreamVideoBidResponse, request); + expect(response[0].renderer).to.not.exist; + }); + + it('should not assign renderer if bid is video and request is for instream', function() { + let request = spec.buildRequests(videoBidRequests, { + auctionId: 'new-auction-id' + }); + let response = spec.interpretResponse(videoBidResponse, request); + expect(response[0].renderer).to.not.exist; + }); + + it('should not assign renderer if bid is native', function() { + let request = spec.buildRequests(nativeBidRequests, { + auctionId: 'new-auction-id' + }); + let response = spec.interpretResponse(nativeBidResponse, request); + expect(response[0].renderer).to.not.exist; + }); + + it('should not assign renderer if bid is of banner', function() { + let request = spec.buildRequests(bidRequests, { + auctionId: 'new-auction-id' + }); + let response = spec.interpretResponse(bidResponses, request); + expect(response[0].renderer).to.not.exist; + }); }); describe('getUserSyncs', function() { diff --git a/test/spec/modules/pubperfAnalyticsAdapter_spec.js b/test/spec/modules/pubperfAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..b316b44617a --- /dev/null +++ b/test/spec/modules/pubperfAnalyticsAdapter_spec.js @@ -0,0 +1,55 @@ +import pubperfAnalytics from 'modules/pubperfAnalyticsAdapter.js'; +import { expect } from 'chai'; +import { server } from 'test/mocks/xhr.js'; +let events = require('src/events'); +let utils = require('src/utils.js'); +let constants = require('src/constants.json'); + +describe('Pubperf Analytics Adapter', function() { + describe('Prebid Manager Analytic tests', function() { + beforeEach(function() { + sinon.stub(events, 'getEvents').returns([]); + sinon.stub(utils, 'logError'); + }); + + afterEach(function() { + events.getEvents.restore(); + utils.logError.restore(); + }); + + it('should throw error, when pubperf_pbjs is not defined', function() { + pubperfAnalytics.enableAnalytics({ + provider: 'pubperf' + }); + + events.emit(constants.EVENTS.AUCTION_INIT, {}); + events.emit(constants.EVENTS.BID_REQUESTED, {}); + events.emit(constants.EVENTS.BID_RESPONSE, {}); + events.emit(constants.EVENTS.BID_WON, {}); + events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(constants.EVENTS.BID_TIMEOUT, {}); + + expect(server.requests.length).to.equal(0); + expect(utils.logError.called).to.equal(true); + }); + + it('track event without errors', function() { + sinon.spy(pubperfAnalytics, 'track'); + + window['pubperf_pbjs'] = function() {}; + + pubperfAnalytics.enableAnalytics({ + provider: 'pubperf' + }); + + events.emit(constants.EVENTS.AUCTION_INIT, {}); + events.emit(constants.EVENTS.BID_REQUESTED, {}); + events.emit(constants.EVENTS.BID_RESPONSE, {}); + events.emit(constants.EVENTS.BID_WON, {}); + events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(constants.EVENTS.BID_TIMEOUT, {}); + + sinon.assert.callCount(pubperfAnalytics.track, 6); + }); + }); +}); diff --git a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js index 5e4b2be894e..3be4ea3d69c 100644 --- a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js @@ -1,47 +1,164 @@ +import { expect } from 'chai'; import pubwiseAnalytics from 'modules/pubwiseAnalyticsAdapter.js'; +import {server} from 'test/mocks/xhr.js'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; let constants = require('src/constants.json'); describe('PubWise Prebid Analytics', function () { - after(function () { + let requests; + let sandbox; + let xhr; + let clock; + let mock = {}; + + mock.DEFAULT_PW_CONFIG = { + provider: 'pubwiseanalytics', + options: { + site: ['b1ccf317-a6fc-428d-ba69-0c9c208aa61c'], + custom: {'c_script_type': 'test-script-type', 'c_host': 'test-host', 'c_slot1': 'test-slot1', 'c_slot2': 'test-slot2', 'c_slot3': 'test-slot3', 'c_slot4': 'test-slot4'} + } + }; + mock.AUCTION_INIT = {auctionId: '53c35d77-bd62-41e7-b920-244140e30c77'}; + mock.AUCTION_INIT_EXTRAS = { + auctionId: '53c35d77-bd62-41e7-b920-244140e30c77', + adUnitCodes: 'not empty', + adUnits: '', + bidderRequests: ['0'], + bidsReceived: '0', + config: {test: 'config'}, + noBids: 'no bids today', + winningBids: 'winning bids', + extraProp: 'extraProp retained' + }; + + beforeEach(function() { + sandbox = sinon.sandbox.create(); + clock = sandbox.useFakeTimers(); + sandbox.stub(events, 'getEvents').returns([]); + + xhr = sandbox.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = request => requests.push(request); + }); + + afterEach(function () { + sandbox.restore(); + clock.restore(); pubwiseAnalytics.disableAnalytics(); }); describe('enableAnalytics', function () { beforeEach(function () { - sinon.stub(events, 'getEvents').returns([]); - }); - - afterEach(function () { - events.getEvents.restore(); + requests = []; }); it('should catch all events', function () { - sinon.spy(pubwiseAnalytics, 'track'); + pubwiseAnalytics.enableAnalytics(mock.DEFAULT_PW_CONFIG); - adapterManager.registerAnalyticsAdapter({ - code: 'pubwiseanalytics', - adapter: pubwiseAnalytics - }); + sandbox.spy(pubwiseAnalytics, 'track'); - adapterManager.enableAnalytics({ - provider: 'pubwiseanalytics', - options: { - site: ['test-test-test-test'] - } - }); - - events.emit(constants.EVENTS.AUCTION_INIT, {}); + // sent + events.emit(constants.EVENTS.AUCTION_INIT, mock.AUCTION_INIT); events.emit(constants.EVENTS.BID_REQUESTED, {}); events.emit(constants.EVENTS.BID_RESPONSE, {}); events.emit(constants.EVENTS.BID_WON, {}); + events.emit(constants.EVENTS.AD_RENDER_FAILED, {}); + events.emit(constants.EVENTS.TCF2_ENFORCEMENT, {}); + events.emit(constants.EVENTS.BID_TIMEOUT, {}); + // forces flush events.emit(constants.EVENTS.AUCTION_END, {}); - events.emit(constants.EVENTS.BID_TIMEOUT, {}); + + // eslint-disable-next-line + //console.log(requests); /* testing for 6 calls, including the 2 we're not currently tracking */ - sinon.assert.callCount(pubwiseAnalytics.track, 6); + sandbox.assert.callCount(pubwiseAnalytics.track, 7); + }); + + it('should initialize the auction properly', function () { + pubwiseAnalytics.enableAnalytics(mock.DEFAULT_PW_CONFIG); + + // sent + events.emit(constants.EVENTS.AUCTION_INIT, mock.AUCTION_INIT); + events.emit(constants.EVENTS.BID_REQUESTED, {}); + events.emit(constants.EVENTS.BID_RESPONSE, {}); + events.emit(constants.EVENTS.BID_WON, {}); + // force flush + clock.tick(500); + + /* check for critical values */ + let request = requests[0]; + let data = JSON.parse(request.requestBody); + // eslint-disable-next-line + // console.log(data.metaData); + expect(data.metaData, 'metaData property').to.exist; + expect(data.metaData.pbjs_version, 'pbjs version').to.equal('$prebid.version$') + expect(data.metaData.session_id, 'session id').not.to.be.empty + expect(data.metaData.activation_id, 'activation id').not.to.be.empty + + // check custom metadata slots + expect(data.metaData.c_script_type, 'c_script_type property').to.exist; + expect(data.metaData.c_script_type, 'c_script_type').not.to.be.empty + expect(data.metaData.c_script_type).to.equal('test-script-type'); + + expect(data.metaData.c_host, 'c_host property').to.exist; + expect(data.metaData.c_host, 'c_host').not.to.be.empty + expect(data.metaData.c_host).to.equal('test-host'); + + expect(data.metaData.c_slot1, 'c_slot1 property').to.exist; + expect(data.metaData.c_slot1, 'c_slot1').not.to.be.empty + expect(data.metaData.c_slot1).to.equal('test-slot1'); + + expect(data.metaData.c_slot2, 'c_slot1 property').to.exist; + expect(data.metaData.c_slot2, 'c_slot1').not.to.be.empty + expect(data.metaData.c_slot2).to.equal('test-slot2'); + + expect(data.metaData.c_slot3, 'c_slot1 property').to.exist; + expect(data.metaData.c_slot3, 'c_slot1').not.to.be.empty + expect(data.metaData.c_slot3).to.equal('test-slot3'); + + expect(data.metaData.c_slot4, 'c_slot1 property').to.exist; + expect(data.metaData.c_slot4, 'c_slot1').not.to.be.empty + expect(data.metaData.c_slot4).to.equal('test-slot4'); + + // check for version info too + expect(data.metaData.pw_version, 'pw_version property').to.exist; + expect(data.metaData.pbjs_version, 'pbjs_version property').to.exist; + }); + + it('should remove extra data on init', function () { + pubwiseAnalytics.enableAnalytics(mock.DEFAULT_PW_CONFIG); + + // sent + events.emit(constants.EVENTS.AUCTION_INIT, mock.AUCTION_INIT_EXTRAS); + // force flush + clock.tick(500); + + /* check for critical values */ + let request = requests[0]; + let data = JSON.parse(request.requestBody); + + // check the basics + expect(data.eventList, 'eventList property').to.exist; + expect(data.eventList[0], 'eventList property').to.exist; + expect(data.eventList[0].args, 'eventList property').to.exist; + + // eslint-disable-next-line + // console.log(data.eventList[0].args); + + let eventArgs = data.eventList[0].args; + // the props we want removed should go away + expect(eventArgs.adUnitCodes, 'adUnitCodes property').not.to.exist; + expect(eventArgs.bidderRequests, 'adUnitCodes property').not.to.exist; + expect(eventArgs.bidsReceived, 'adUnitCodes property').not.to.exist; + expect(eventArgs.config, 'adUnitCodes property').not.to.exist; + expect(eventArgs.noBids, 'adUnitCodes property').not.to.exist; + expect(eventArgs.winningBids, 'adUnitCodes property').not.to.exist; + + // the extra prop should still exist + expect(eventArgs.extraProp, 'adUnitCodes property').to.exist; }); }); }); diff --git a/test/spec/modules/pubxBidAdapter_spec.js b/test/spec/modules/pubxBidAdapter_spec.js new file mode 100644 index 00000000000..d5f1a0f5da3 --- /dev/null +++ b/test/spec/modules/pubxBidAdapter_spec.js @@ -0,0 +1,125 @@ +import {expect} from 'chai'; +import {spec} from 'modules/pubxBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; + +describe('pubxAdapter', function () { + const adapter = newBidder(spec); + const ENDPOINT = 'https://api.primecaster.net/adlogue/api/slot/bid'; + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + const bid = { + bidder: 'pubx', + params: { + sid: '12345abc' + } + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', function () { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + const bidRequests = [ + { + id: '26c1ee0038ac11', + params: { + sid: '12345abc' + } + } + ]; + + const data = { + banner: { + sid: '12345abc' + } + }; + + it('sends bid request to ENDPOINT via GET', function () { + const request = spec.buildRequests(bidRequests)[0]; + expect(request.url).to.equal(ENDPOINT); + expect(request.method).to.equal('GET'); + }); + + it('should attach params to the banner request', function () { + const request = spec.buildRequests(bidRequests)[0]; + expect(request.data).to.deep.equal(data.banner); + }); + }); + + describe('interpretResponse', function () { + const serverResponse = { + body: { + TTL: 300, + adm: '
some creative
', + cid: 'TKmB', + cpm: 500, + currency: 'JPY', + height: 250, + width: 300, + } + } + + const bidRequests = [ + { + id: '26c1ee0038ac11', + params: { + sid: '12345abc' + } + } + ]; + + const bidResponses = [ + { + requestId: '26c1ee0038ac11', + cpm: 500, + currency: 'JPY', + width: 300, + height: 250, + creativeId: 'TKmB', + netRevenue: true, + ttl: 300, + ad: '
some creative
' + } + ]; + it('should return empty array when required param is empty', function () { + const serverResponseWithCidEmpty = { + body: { + TTL: 300, + adm: '
some creative
', + cid: '', + cpm: '', + currency: 'JPY', + height: 250, + width: 300, + } + } + const result = spec.interpretResponse(serverResponseWithCidEmpty, bidRequests[0]); + expect(result).to.be.empty; + }); + it('handles banner responses', function () { + const result = spec.interpretResponse(serverResponse, bidRequests[0])[0]; + expect(result.requestId).to.equal(bidResponses[0].requestId); + expect(result.width).to.equal(bidResponses[0].width); + expect(result.height).to.equal(bidResponses[0].height); + expect(result.creativeId).to.equal(bidResponses[0].creativeId); + expect(result.currency).to.equal(bidResponses[0].currency); + expect(result.netRevenue).to.equal(bidResponses[0].netRevenue); + expect(result.ttl).to.equal(bidResponses[0].ttl); + expect(result.ad).to.equal(bidResponses[0].ad); + }); + }); +}); diff --git a/test/spec/modules/pulsepointBidAdapter_spec.js b/test/spec/modules/pulsepointBidAdapter_spec.js index 4b21856b68e..a6f5ff2a0dc 100644 --- a/test/spec/modules/pulsepointBidAdapter_spec.js +++ b/test/spec/modules/pulsepointBidAdapter_spec.js @@ -630,8 +630,8 @@ describe('PulsePoint Adapter Tests', function () { britepoolid: 'britepool_id123', criteoId: 'criteo_id234', idl_env: 'idl_id123', - id5id: 'id5id_234', - parrableid: 'parrable_id234', + id5id: { uid: 'id5id_234' }, + parrableId: { eid: 'parrable_id234' }, lipb: { lipbid: 'liveintent_id123' } diff --git a/test/spec/modules/quantcastBidAdapter_spec.js b/test/spec/modules/quantcastBidAdapter_spec.js index cd168ec61e6..caa554c8cd8 100644 --- a/test/spec/modules/quantcastBidAdapter_spec.js +++ b/test/spec/modules/quantcastBidAdapter_spec.js @@ -430,26 +430,6 @@ describe('Quantcast adapter', function () { expect(requests).to.equal(undefined); }); - it('allows TCF v2 request from Germany for purpose 1', function () { - const bidderRequest = { - gdprConsent: { - gdprApplies: true, - consentString: 'consentString', - vendorData: { - publisherCC: 'DE', - purposeOneTreatment: true - }, - apiVersion: 2 - } - }; - - const requests = qcSpec.buildRequests([bidRequest], bidderRequest); - const parsed = JSON.parse(requests[0].data); - - expect(parsed.gdprSignal).to.equal(1); - expect(parsed.gdprConsent).to.equal('consentString'); - }); - it('allows TCF v2 request when Quantcast has consent for purpose 1', function() { const bidderRequest = { gdprConsent: { diff --git a/test/spec/modules/quantcastIdSystem_spec.js b/test/spec/modules/quantcastIdSystem_spec.js new file mode 100644 index 00000000000..12c8689fd3f --- /dev/null +++ b/test/spec/modules/quantcastIdSystem_spec.js @@ -0,0 +1,19 @@ +import { quantcastIdSubmodule, storage } from 'modules/quantcastIdSystem.js'; + +describe('QuantcastId module', function () { + beforeEach(function() { + storage.setCookie('__qca', '', 'Thu, 01 Jan 1970 00:00:00 GMT'); + }); + + it('getId() should return a quantcast id when the Quantcast first party cookie exists', function () { + storage.setCookie('__qca', 'P0-TestFPA'); + + const id = quantcastIdSubmodule.getId(); + expect(id).to.be.deep.equal({id: {quantcastId: 'P0-TestFPA'}}); + }); + + it('getId() should return an empty id when the Quantcast first party cookie is missing', function () { + const id = quantcastIdSubmodule.getId(); + expect(id).to.be.deep.equal({id: undefined}); + }); +}); diff --git a/test/spec/modules/quantumBidAdapter_spec.js b/test/spec/modules/quantumBidAdapter_spec.js deleted file mode 100644 index c03d74ea52e..00000000000 --- a/test/spec/modules/quantumBidAdapter_spec.js +++ /dev/null @@ -1,325 +0,0 @@ -import { expect } from 'chai' -import { spec } from 'modules/quantumBidAdapter.js' -import { newBidder } from 'src/adapters/bidderFactory.js' - -const ENDPOINT = 'https://s.sspqns.com/hb' -const REQUEST = { - 'bidder': 'quantum', - 'sizes': [[300, 250]], - 'renderMode': 'banner', - 'params': { - placementId: 21546 - } -} - -const NATIVE_REQUEST = { - 'bidder': 'quantum', - 'mediaType': 'native', - 'sizes': [[0, 0]], - 'params': { - placementId: 21546 - } -} - -const serverResponse = { - 'price': 0.3, - 'debug': [ - '' - ], - 'is_fallback': false, - 'nurl': 'https://s.sspqns.com/imp/KpQ1WNMHV-9a3HqWL_0JnujJFGo1Hnx9RS3FT_Yy8jW-Z6t_PJYmP2otidJsxE3qcY2EozzcBjRzGM7HEQcxVnjOzq0Th1cxb6A5bSp5BizTwY5SRaxx_0PgF6--8LqaF4LMUgMmhfF5k3gOOzzK6gKdavia4_w3LJ1CRWkMEwABr8bPzeovy1y4MOZsOXv7vXjPGMKJSTgphuZR57fL4u4ZFF4XY70K_TaH5bfXHMRAzE0Q38tfpTvbdFV_u2g-FoF0gjzKjiS88VnetT-Jo3qtrMphWzr52jsg5tH3L7hbymUOm1YkuJP9xrXLoZNVgC5sTMYolKLMSu6dqhS2FXcdfaGAcHweaaAAwJq-pB7DuiVcdnZQphUymhIia_KG2AYweWp6TYEpJbJjf2BcLpm_-KGw4gLh6L3DtEvUZwXZe-JpUJ4/', - 'native': { - 'link': { - 'url': 'https://s.sspqns.com/click/KpQ1WNMHV-9a3HqWL_0JnujJFGo1Hnx9RS3FT_Yy8jW-Z6t_PJYmP2otidJsxE3qcY2EozzcBjRzGM7HEQcxVnjOzq0Th1cxb6A5bSp5BizTwY5SRaxx_0PgF6--8LqaF4LMUgMmhfF5k3gOOzzK6gKdavia4_w3LJ1CRWkMEwABr8bPzeovy1y4MOZsOXv7vXjPGMKJSTgphuZR57fL4u4ZFF4XY70K_TaH5bfXHMRAzE0Q38tfpTvbdFV_u2g-FoF0gjzKjiS88VnetT-Jo3qtrMphWzr52jsg5tH3L7hbymUOm1YkuJP9xrXLoZNVgC5sTMYolKLMSu6dqhS2FXcdfaGAcHweaaAAwJq-pB7DuiVcdnZQphUymhIia_KG2AYweWp6TYEpJbJjf2BcLpm_-KGw4gLh6L3DtEvUZwXZe-JpUJ4///', - 'clicktrackers': ['https://elasticad.net'] - }, - 'assets': [ - { - 'id': 1, - 'title': { - 'text': 'ad.SSP.1x1' - }, - 'required': 1 - }, - { - 'id': 2, - 'img': { - 'w': 15, - 'h': 15, - 'url': 'https://files.ssp.theadtech.com.s3.amazonaws.com/media/image/sxjermpz/scalecrop-15x15' - } - }, - { - 'id': 3, - 'data': { - 'value': 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.Lorem Ipsum is simply dummy text of the printing and typesetting industry.' - }, - 'required': 1 - }, - { - 'id': 4, - 'img': { - 'w': 500, - 'h': 500, - 'url': 'https://files.ssp.theadtech.com.s3.amazonaws.com/media/image/sxjermpz/scalecrop-500x500' - } - }, - { - 'id': 6, - 'video': { - 'vasttag': 'https://elasticad.net/vast.xml' - } - }, - { - 'id': 2001, - 'data': { - 'value': 'https://elasticad.net' - } - }, - { - 'id': 2002, - 'data': { - 'value': 'vast' - } - }, - { - 'id': 2007, - 'data': { - 'value': 'click' - } - }, - { - 'id': 10, - 'data': { - 'value': 'ad.SSP.1x1 sponsor' - } - }, - { - 'id': 2003, - 'data': { - 'value': 'https://elasticad.net' - } - }, - { - 'id': 2004, - 'data': { - 'value': 'prism' - } - }, - { - 'id': 2005, - 'data': { - 'value': '/home' - } - }, - { - 'id': 2006, - 'data': { - 'value': 'https://elasticad.net/vast.xml' - } - }, - { - 'id': 2022, - 'data': { - 'value': 'Lorem ipsum....' - } - } - ], - 'imptrackers': [], - 'ver': '1.1' - }, - 'sync': [ - 'https://match.adsrvr.org/track/cmb/generic?ttd_pid=s6e8ued&ttd_tpi=1' - ] -} - -const nativeServerResponse = { - 'price': 0.3, - 'debug': [ - '' - ], - 'is_fallback': false, - 'nurl': 'https://s.sspqns.com/imp/KpQ1WNMHV-9a3HqWL_0JnujJFGo1Hnx9RS3FT_Yy8jW-Z6t_PJYmP2otidJsxE3qcY2EozzcBjRzGM7HEQcxVnjOzq0Th1cxb6A5bSp5BizTwY5SRaxx_0PgF6--8LqaF4LMUgMmhfF5k3gOOzzK6gKdavia4_w3LJ1CRWkMEwABr8bPzeovy1y4MOZsOXv7vXjPGMKJSTgphuZR57fL4u4ZFF4XY70K_TaH5bfXHMRAzE0Q38tfpTvbdFV_u2g-FoF0gjzKjiS88VnetT-Jo3qtrMphWzr52jsg5tH3L7hbymUOm1YkuJP9xrXLoZNVgC5sTMYolKLMSu6dqhS2FXcdfaGAcHweaaAAwJq-pB7DuiVcdnZQphUymhIia_KG2AYweWp6TYEpJbJjf2BcLpm_-KGw4gLh6L3DtEvUZwXZe-JpUJ4/', - 'native': { - 'link': { - 'url': 'https://s.sspqns.com/click/KpQ1WNMHV-9a3HqWL_0JnujJFGo1Hnx9RS3FT_Yy8jW-Z6t_PJYmP2otidJsxE3qcY2EozzcBjRzGM7HEQcxVnjOzq0Th1cxb6A5bSp5BizTwY5SRaxx_0PgF6--8LqaF4LMUgMmhfF5k3gOOzzK6gKdavia4_w3LJ1CRWkMEwABr8bPzeovy1y4MOZsOXv7vXjPGMKJSTgphuZR57fL4u4ZFF4XY70K_TaH5bfXHMRAzE0Q38tfpTvbdFV_u2g-FoF0gjzKjiS88VnetT-Jo3qtrMphWzr52jsg5tH3L7hbymUOm1YkuJP9xrXLoZNVgC5sTMYolKLMSu6dqhS2FXcdfaGAcHweaaAAwJq-pB7DuiVcdnZQphUymhIia_KG2AYweWp6TYEpJbJjf2BcLpm_-KGw4gLh6L3DtEvUZwXZe-JpUJ4///' - }, - 'assets': [ - { - 'id': 1, - 'title': { - 'text': 'ad.SSP.1x1' - }, - 'required': 1 - }, - { - 'id': 2, - 'img': { - 'w': 15, - 'h': 15, - 'url': 'https://files.ssp.theadtech.com.s3.amazonaws.com/media/image/sxjermpz/scalecrop-15x15' - } - }, - { - 'id': 3, - 'data': { - 'value': 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.Lorem Ipsum is simply dummy text of the printing and typesetting industry.' - }, - 'required': 1 - }, - { - 'id': 4, - 'img': { - 'w': 500, - 'h': 500, - 'url': 'https://files.ssp.theadtech.com.s3.amazonaws.com/media/image/sxjermpz/scalecrop-500x500' - } - }, - { - 'id': 2007, - 'data': { - 'value': 'click' - } - }, - { - 'id': 10, - 'data': { - 'value': 'ad.SSP.1x1 sponsor' - } - }, - - { - 'id': 2003, - 'data': { - 'value': 'https://elasticad.net' - } - } - ], - 'imptrackers': [], - 'ver': '1.1' - }, - 'sync': [ - 'https://match.adsrvr.org/track/cmb/generic?ttd_pid=s6e8ued&ttd_tpi=1' - ] -} - -describe('quantumBidAdapter', function () { - const adapter = newBidder(spec) - - describe('inherited functions', function () { - it('exists and is a function', function () { - expect(adapter.callBids).to.exist.and.to.be.a('function') - }) - }) - - describe('isBidRequestValid', function () { - it('should return true when required params found', function () { - expect(spec.isBidRequestValid(REQUEST)).to.equal(true) - }) - - it('should return false when required params are not passed', function () { - let bid = Object.assign({}, REQUEST) - delete bid.params - expect(spec.isBidRequestValid(bid)).to.equal(false) - }) - }) - - describe('buildRequests', function () { - let bidRequests = [REQUEST] - - const request = spec.buildRequests(bidRequests, {}) - - it('sends bid request to ENDPOINT via GET', function () { - expect(request[0].method).to.equal('GET') - }) - }) - - describe('GDPR conformity', function () { - const bidRequests = [{ - 'bidder': 'quantum', - 'mediaType': 'native', - 'params': { - placementId: 21546 - }, - adUnitCode: 'aaa', - transactionId: '2b8389fe-615c-482d-9f1a-376fb8f7d6b0', - sizes: [[0, 0]], - bidId: '1abgs362e0x48a8', - bidderRequestId: '70deaff71c281d', - auctionId: '5c66da22-426a-4bac-b153-77360bef5337' - }]; - - const bidderRequest = { - gdprConsent: { - consentString: 'awefasdfwefasdfasd', - gdprApplies: true - } - }; - - it('should transmit correct data', function () { - const requests = spec.buildRequests(bidRequests, bidderRequest); - expect(requests.length).to.equal(1); - expect(requests[0].data.quantx_gdpr).to.equal(1); - expect(requests[0].data.quantx_user_consent_string).to.equal('awefasdfwefasdfasd'); - }); - }); - - describe('GDPR absence conformity', function () { - const bidRequests = [{ - 'bidder': 'quantum', - 'mediaType': 'native', - 'params': { - placementId: 21546 - }, - adUnitCode: 'aaa', - transactionId: '2b8389fe-615c-482d-9f1a-376fb8f7d6b0', - sizes: [[0, 0]], - bidId: '1abgs362e0x48a8', - bidderRequestId: '70deaff71c281d', - auctionId: '5c66da22-426a-4bac-b153-77360bef5337' - }]; - - const bidderRequest = { - gdprConsent: undefined - }; - - it('should transmit correct data', function () { - const requests = spec.buildRequests(bidRequests, bidderRequest); - expect(requests.length).to.equal(1); - expect(requests[0].data.quantx_gdpr).to.be.undefined; - expect(requests[0].data.quantx_user_consent_string).to.be.undefined; - }); - }); - - describe('interpretResponse', function () { - let bidderRequest = { - bidderCode: 'bidderCode', - bids: [] - } - - it('handles native request : should get correct bid response', function () { - const result = spec.interpretResponse({body: nativeServerResponse}, NATIVE_REQUEST) - expect(result[0]).to.have.property('cpm').equal(0.3) - expect(result[0]).to.have.property('width').to.be.below(2) - expect(result[0]).to.have.property('height').to.be.below(2) - expect(result[0]).to.have.property('mediaType').equal('native') - expect(result[0]).to.have.property('native') - }) - - it('should get correct bid response', function () { - const result = spec.interpretResponse({body: serverResponse}, REQUEST) - expect(result[0]).to.have.property('cpm').equal(0.3) - expect(result[0]).to.have.property('width').equal(300) - expect(result[0]).to.have.property('height').equal(250) - expect(result[0]).to.have.property('mediaType').equal('banner') - expect(result[0]).to.have.property('ad') - }) - - it('handles nobid responses', function () { - const nobidServerResponse = {bids: []} - const nobidResult = spec.interpretResponse({body: nobidServerResponse}, bidderRequest) - // console.log(nobidResult) - expect(nobidResult.length).to.equal(0) - }) - }) -}) diff --git a/test/spec/modules/quantumdexBidAdapter_spec.js b/test/spec/modules/quantumdexBidAdapter_spec.js index ef8791cca57..d1817493b36 100644 --- a/test/spec/modules/quantumdexBidAdapter_spec.js +++ b/test/spec/modules/quantumdexBidAdapter_spec.js @@ -235,25 +235,25 @@ describe('QuantumdexBidAdapter', function () { it('should return a properly formatted request', function () { const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.url).to.equal('https://useast.quantumdex.io/auction/adapter') + expect(bidRequests.url).to.equal('https://useast.quantumdex.io/auction/quantumdex') expect(bidRequests.method).to.equal('POST') expect(bidRequests.bidderRequests).to.eql(bidRequest); }) it('should return a properly formatted request with GDPR applies set to true', function () { const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.url).to.equal('https://useast.quantumdex.io/auction/adapter') + expect(bidRequests.url).to.equal('https://useast.quantumdex.io/auction/quantumdex') expect(bidRequests.method).to.equal('POST') - expect(bidRequests.data.gdpr.gdprApplies).to.equal('true') + expect(bidRequests.data.gdpr.gdprApplies).to.equal(true) expect(bidRequests.data.gdpr.consentString).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A==') }) it('should return a properly formatted request with GDPR applies set to false', function () { bidderRequests.gdprConsent.gdprApplies = false; const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.url).to.equal('https://useast.quantumdex.io/auction/adapter') + expect(bidRequests.url).to.equal('https://useast.quantumdex.io/auction/quantumdex') expect(bidRequests.method).to.equal('POST') - expect(bidRequests.data.gdpr.gdprApplies).to.equal('false') + expect(bidRequests.data.gdpr.gdprApplies).to.equal(false) expect(bidRequests.data.gdpr.consentString).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A==') }) it('should return a properly formatted request with GDPR applies set to false with no consent_string param', function () { @@ -271,9 +271,9 @@ describe('QuantumdexBidAdapter', function () { } }; const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.url).to.equal('https://useast.quantumdex.io/auction/adapter') + expect(bidRequests.url).to.equal('https://useast.quantumdex.io/auction/quantumdex') expect(bidRequests.method).to.equal('POST') - expect(bidRequests.data.gdpr.gdprApplies).to.equal('false') + expect(bidRequests.data.gdpr.gdprApplies).to.equal(false) expect(bidRequests.data.gdpr).to.not.include.keys('consentString') }) it('should return a properly formatted request with GDPR applies set to true with no consentString param', function () { @@ -291,14 +291,14 @@ describe('QuantumdexBidAdapter', function () { } }; const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.url).to.equal('https://useast.quantumdex.io/auction/adapter') + expect(bidRequests.url).to.equal('https://useast.quantumdex.io/auction/quantumdex') expect(bidRequests.method).to.equal('POST') - expect(bidRequests.data.gdpr.gdprApplies).to.equal('true') + expect(bidRequests.data.gdpr.gdprApplies).to.equal(true) expect(bidRequests.data.gdpr).to.not.include.keys('consentString') }) it('should return a properly formatted request with schain defined', function () { const bidRequests = spec.buildRequests(bidRequest, bidderRequests); - expect(JSON.parse(bidRequests.data.schain)).to.deep.equal(bidRequest[0].schain) + expect(bidRequests.data.schain).to.deep.equal(bidRequest[0].schain) }); it('should return a properly formatted request with us_privacy included', function () { const bidRequests = spec.buildRequests(bidRequest, bidderRequests); @@ -309,7 +309,7 @@ describe('QuantumdexBidAdapter', function () { describe('.interpretResponse', function () { const bidRequests = { 'method': 'POST', - 'url': 'https://useast.quantumdex.io/auction/adapter', + 'url': 'https://useast.quantumdex.io/auction/quantumdex', 'withCredentials': true, 'data': { 'device': { diff --git a/test/spec/modules/qwarryBidAdapter_spec.js b/test/spec/modules/qwarryBidAdapter_spec.js new file mode 100644 index 00000000000..a5bb438f384 --- /dev/null +++ b/test/spec/modules/qwarryBidAdapter_spec.js @@ -0,0 +1,122 @@ +import { expect } from 'chai' +import { ENDPOINT, spec } from 'modules/qwarryBidAdapter.js' +import { newBidder } from 'src/adapters/bidderFactory.js' + +const REQUEST = { + 'bidId': '456', + 'bidder': 'qwarry', + 'params': { + zoneToken: 'e64782a4-8e68-4c38-965b-80ccf115d46f' + } +} + +const BIDDER_BANNER_RESPONSE = {'prebidResponse': [{ + 'ad': '
test
', + 'requestId': 'e64782a4-8e68-4c38-965b-80ccf115d46d', + 'cpm': 900.5, + 'currency': 'USD', + 'width': 640, + 'height': 480, + 'ttl': 300, + 'creativeId': 1, + 'netRevenue': true, + 'winUrl': 'http://test.com', + 'format': 'banner' +}]} + +const BIDDER_VIDEO_RESPONSE = {'prebidResponse': [{ + 'ad': 'vast', + 'requestId': 'e64782a4-8e68-4c38-965b-80ccf115d46z', + 'cpm': 800.4, + 'currency': 'USD', + 'width': 1024, + 'height': 768, + 'ttl': 200, + 'creativeId': 2, + 'netRevenue': true, + 'winUrl': 'http://test.com', + 'format': 'video' +}]} + +const BIDDER_NO_BID_RESPONSE = '' + +describe('qwarryBidAdapter', function () { + const adapter = newBidder(spec) + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function') + }) + }) + + describe('isBidRequestValid', function () { + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(REQUEST)).to.equal(true) + }) + + it('should return false when required params are not passed', function () { + let bid = Object.assign({}, REQUEST) + delete bid.params.zoneToken + expect(spec.isBidRequestValid(bid)).to.equal(false) + delete bid.params + expect(spec.isBidRequestValid(bid)).to.equal(false) + }) + }) + + describe('buildRequests', function () { + let bidRequests = [REQUEST] + const bidderRequest = spec.buildRequests(bidRequests, { bidderRequestId: '123' }) + + it('sends bid request to ENDPOINT via POST', function () { + expect(bidderRequest.method).to.equal('POST') + expect(bidderRequest.data.requestId).to.equal('123') + expect(bidderRequest.data.bids).to.deep.contains({ bidId: '456', zoneToken: 'e64782a4-8e68-4c38-965b-80ccf115d46f' }) + expect(bidderRequest.options.customHeaders).to.deep.equal({ 'Rtb-Direct': true }) + expect(bidderRequest.options.contentType).to.equal('application/json') + expect(bidderRequest.url).to.equal(ENDPOINT) + }) + }) + + describe('interpretResponse', function () { + it('handles banner request : should get correct bid response', function () { + const result = spec.interpretResponse({ body: BIDDER_BANNER_RESPONSE }, {}) + + expect(result[0]).to.have.property('ad').equal('
test
') + expect(result[0]).to.have.property('requestId').equal('e64782a4-8e68-4c38-965b-80ccf115d46d') + expect(result[0]).to.have.property('cpm').equal(900.5) + expect(result[0]).to.have.property('currency').equal('USD') + expect(result[0]).to.have.property('width').equal(640) + expect(result[0]).to.have.property('height').equal(480) + expect(result[0]).to.have.property('ttl').equal(300) + expect(result[0]).to.have.property('creativeId').equal(1) + expect(result[0]).to.have.property('netRevenue').equal(true) + expect(result[0]).to.have.property('winUrl').equal('http://test.com') + expect(result[0]).to.have.property('format').equal('banner') + }) + + it('handles video request : should get correct bid response', function () { + const result = spec.interpretResponse({ body: BIDDER_VIDEO_RESPONSE }, {}) + + expect(result[0]).to.have.property('ad').equal('vast') + expect(result[0]).to.have.property('requestId').equal('e64782a4-8e68-4c38-965b-80ccf115d46z') + expect(result[0]).to.have.property('cpm').equal(800.4) + expect(result[0]).to.have.property('currency').equal('USD') + expect(result[0]).to.have.property('width').equal(1024) + expect(result[0]).to.have.property('height').equal(768) + expect(result[0]).to.have.property('ttl').equal(200) + expect(result[0]).to.have.property('creativeId').equal(2) + expect(result[0]).to.have.property('netRevenue').equal(true) + expect(result[0]).to.have.property('winUrl').equal('http://test.com') + expect(result[0]).to.have.property('format').equal('video') + expect(result[0]).to.have.property('vastXml').equal('vast') + }) + + it('handles no bid response : should get empty array', function () { + let result = spec.interpretResponse({ body: undefined }, {}) + expect(result).to.deep.equal([]) + + result = spec.interpretResponse({ body: BIDDER_NO_BID_RESPONSE }, {}) + expect(result).to.deep.equal([]) + }) + }) +}) diff --git a/test/spec/modules/readpeakBidAdapter_spec.js b/test/spec/modules/readpeakBidAdapter_spec.js index eb9077fac39..0c6f942e724 100644 --- a/test/spec/modules/readpeakBidAdapter_spec.js +++ b/test/spec/modules/readpeakBidAdapter_spec.js @@ -177,15 +177,10 @@ describe('ReadPeakAdapter', function() { expect(data.id).to.equal(bidRequest.bidderRequestId); expect(data.imp[0].bidfloor).to.equal(bidRequest.params.bidfloor); expect(data.imp[0].bidfloorcur).to.equal('USD'); - expect(data.site).to.deep.equal({ - publisher: { - id: bidRequest.params.publisherId, - domain: 'http://localhost:9876' - }, - id: bidRequest.params.siteId, - page: bidderRequest.refererInfo.referer, - domain: parseUrl(bidderRequest.refererInfo.referer).hostname - }); + expect(data.site.publisher.id).to.equal(bidRequest.params.publisherId); + expect(data.site.id).to.equal(bidRequest.params.siteId); + expect(data.site.page).to.equal(bidderRequest.refererInfo.referer); + expect(data.site.domain).to.equal(parseUrl(bidderRequest.refererInfo.referer).hostname); expect(data.device).to.deep.contain({ ua: navigator.userAgent, language: navigator.language diff --git a/test/spec/modules/realTimeModule_spec.js b/test/spec/modules/realTimeModule_spec.js index 27440a3ec23..f47068724d1 100644 --- a/test/spec/modules/realTimeModule_spec.js +++ b/test/spec/modules/realTimeModule_spec.js @@ -1,25 +1,176 @@ -import { - init, - requestBidsHook, - setTargetsAfterRequestBids, - deepMerge -} from 'modules/rtdModule/index.js'; -import { - init as browsiInit, - addBrowsiTag, - isIdMatchingAdUnit, - setData -} from 'modules/browsiRtdProvider.js'; -import { - init as audigentInit, - setData as setAudigentData -} from 'modules/audigentRtdProvider.js'; +import * as rtdModule from 'modules/rtdModule/index.js'; import { config } from 'src/config.js'; -import { makeSlot } from '../integration/faker/googletag.js'; +import {makeSlot} from '../integration/faker/googletag.js'; +import * as browsiRTD from '../../../modules/browsiRtdProvider.js'; -let expect = require('chai').expect; +const validSM = { + name: 'validSM', + init: () => { return true }, + getData: (adUnits, onDone) => { + setTimeout(() => { + return onDone({'key': 'validSM'}) + }, 500) + } +}; + +const validSMWait = { + name: 'validSMWait', + init: () => { return true }, + getData: (adUnits, onDone) => { + setTimeout(() => { + return onDone({'ad1': {'key': 'validSMWait'}}) + }, 50) + } +}; + +const invalidSM = { + name: 'invalidSM' +}; + +const failureSM = { + name: 'failureSM', + init: () => { return false } +}; + +const nonConfSM = { + name: 'nonConfSM', + init: () => { return true } +}; + +const conf = { + 'realTimeData': { + 'auctionDelay': 250, + dataProviders: [ + { + 'name': 'validSMWait', + 'waitForIt': true, + }, + { + 'name': 'validSM', + 'waitForIt': false, + }, + { + 'name': 'invalidSM' + }, + { + 'name': 'failureSM' + }] + } +}; + +function getAdUnitMock(code = 'adUnit-code') { + return { + code, + mediaTypes: { banner: {}, native: {} }, + sizes: [[300, 200], [300, 600]], + bids: [{ bidder: 'sampleBidder', params: { placementId: 'banner-only-bidder' } }] + }; +} describe('Real time module', function () { + after(function () { + config.resetConfig(); + }); + + beforeEach(function () { + config.setConfig(conf); + }); + + it('should use only valid modules', function (done) { + rtdModule.attachRealTimeDataProvider(validSM); + rtdModule.attachRealTimeDataProvider(invalidSM); + rtdModule.attachRealTimeDataProvider(failureSM); + rtdModule.attachRealTimeDataProvider(nonConfSM); + rtdModule.attachRealTimeDataProvider(validSMWait); + rtdModule.initSubModules(afterInitSubModules); + function afterInitSubModules() { + expect(rtdModule.subModules).to.eql([validSMWait, validSM]); + done(); + } + rtdModule.init(config); + }); + + it('should only wait for must have sub modules', function (done) { + rtdModule.getProviderData([], (data) => { + expect(data).to.eql({validSMWait: {'ad1': {'key': 'validSMWait'}}}); + done(); + }) + }); + + it('deep merge object', function () { + const obj1 = { + id1: { + key: 'value', + key2: 'value2' + }, + id2: { + k: 'v' + } + }; + const obj2 = { + id1: { + key3: 'value3' + } + }; + const obj3 = { + id3: { + key: 'value' + } + }; + const expected = { + id1: { + key: 'value', + key2: 'value2', + key3: 'value3' + }, + id2: { + k: 'v' + }, + id3: { + key: 'value' + } + }; + + const merged = rtdModule.deepMerge([obj1, obj2, obj3]); + assert.deepEqual(expected, merged); + }); + + it('check module using bidsBackCallback', function (done) { + // set slot + const slot = makeSlot({ code: '/code1', divId: 'ad1' }); + window.googletag.pubads().setSlots([slot]); + + function afterBidHook() { + expect(slot.getTargeting().length).to.equal(1); + expect(slot.getTargeting()[0].key).to.equal('validSMWait'); + done(); + } + rtdModule.setTargetsAfterRequestBids(afterBidHook, []); + }); + + it('check module using requestBidsHook', function (done) { + // set slot + const slotsB = makeSlot({ code: '/code1', divId: 'ad1' }); + window.googletag.pubads().setSlots([slotsB]); + let adUnits = [getAdUnitMock('ad1')]; + + function afterBidHook(data) { + expect(slotsB.getTargeting().length).to.equal(1); + expect(slotsB.getTargeting()[0].key).to.equal('validSMWait'); + + data.adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid.realTimeData).to.have.property('key'); + expect(bid.realTimeData.key).to.equal('validSMWait'); + }); + }); + done(); + } + rtdModule.requestBidsHook(afterBidHook, { adUnits: adUnits }); + }); +}); + +describe('browsi Real time data sub module', function () { const conf = { 'realTimeData': { 'auctionDelay': 250, @@ -31,215 +182,93 @@ describe('Real time module', function () { 'pubKey': 'testPub', 'keyName': 'bv' } - }, { - 'name': 'audigent' }] } }; - const predictions = { - p: { - 'browsiAd_2': { - 'w': [ - '/57778053/Browsi_Demo_Low', - '/57778053/Browsi_Demo_300x250' - ], - 'p': 0.07 - }, - 'browsiAd_1': { - 'w': [], - 'p': 0.06 - }, - 'browsiAd_3': { - 'w': [], - 'p': 0.53 - }, - 'browsiAd_4': { - 'w': [ - '/57778053/Browsi_Demo' - ], - 'p': 0.85 - } - } - }; + beforeEach(function () { + config.setConfig(conf); + }); - const audigentSegments = { - audigent_segments: { 'a': 1, 'b': 2 } - } + after(function () { + config.resetConfig(); + }); - function getAdUnitMock(code = 'adUnit-code') { - return { - code, - mediaTypes: { banner: {}, native: {} }, - sizes: [[300, 200], [300, 600]], - bids: [{ bidder: 'sampleBidder', params: { placementId: 'banner-only-bidder' } }] - }; - } + it('should init and return true', function () { + browsiRTD.beforeInit(config); + expect(browsiRTD.browsiSubmodule.init()).to.equal(true) + }); - function createSlots() { - const slot1 = makeSlot({ code: '/57778053/Browsi_Demo_300x250', divId: 'browsiAd_1' }); - return [slot1]; - } + it('should create browsi script', function () { + const script = browsiRTD.addBrowsiTag('scriptUrl.com'); + expect(script.getAttribute('data-sitekey')).to.equal('testKey'); + expect(script.getAttribute('data-pubkey')).to.equal('testPub'); + expect(script.async).to.equal(true); + expect(script.prebidData.kn).to.equal(conf.realTimeData.dataProviders[0].params.keyName); + }); - describe('Real time module with browsi provider', function () { - afterEach(function () { - $$PREBID_GLOBAL$$.requestBids.removeAll(); - }); + it('should match placement with ad unit', function () { + const slot = makeSlot({ code: '/57778053/Browsi_Demo_300x250', divId: 'browsiAd_1' }); - after(function () { - config.resetConfig(); - }); + const test1 = browsiRTD.isIdMatchingAdUnit(slot, ['/57778053/Browsi_Demo_300x250']); // true + const test2 = browsiRTD.isIdMatchingAdUnit(slot, ['/57778053/Browsi_Demo_300x250', '/57778053/Browsi']); // true + const test3 = browsiRTD.isIdMatchingAdUnit(slot, ['/57778053/Browsi_Demo_Low']); // false + const test4 = browsiRTD.isIdMatchingAdUnit(slot, []); // true - it('check module using bidsBackCallback', function () { - let adUnits1 = [getAdUnitMock('browsiAd_1')]; - let targeting = []; - init(config); - browsiInit(config); - config.setConfig(conf); - setData(predictions); - - // set slot - const slots = createSlots(); - window.googletag.pubads().setSlots(slots); - - function afterBidHook() { - slots.map(s => { - targeting = []; - s.getTargeting().map(value => { - targeting.push(Object.keys(value).toString()); - }); - }); + expect(test1).to.equal(true); + expect(test2).to.equal(true); + expect(test3).to.equal(false); + expect(test4).to.equal(true); + }); - expect(targeting.indexOf('bv')).to.be.greaterThan(-1); - } - setTargetsAfterRequestBids(afterBidHook, adUnits1, true); - }); + it('should return correct macro values', function () { + const slot = makeSlot({ code: '/57778053/Browsi_Demo_300x250', divId: 'browsiAd_1' }); - it('check module using requestBidsHook', function () { - let adUnits1 = [getAdUnitMock('browsiAd_1')]; - let targeting = []; - let dataReceived = null; - - // set slot - const slotsB = createSlots(); - window.googletag.pubads().setSlots(slotsB); - - function afterBidHook(data) { - dataReceived = data; - slotsB.map(s => { - targeting = []; - s.getTargeting().map(value => { - targeting.push(Object.keys(value).toString()); - }); - }); + slot.setTargeting('test', ['test', 'value']); + // slot getTargeting doesn't act like GPT so we can't expect real value + const macroResult = browsiRTD.getMacroId({p: '/'}, slot); + expect(macroResult).to.equal('/57778053/Browsi_Demo_300x250/NA'); - expect(targeting.indexOf('bv')).to.be.greaterThan(-1); - dataReceived.adUnits.forEach(unit => { - unit.bids.forEach(bid => { - expect(bid.realTimeData).to.have.property('bv'); - }); - }); - } - requestBidsHook(afterBidHook, { adUnits: adUnits1 }); - }); - - it('check object deep merge', function () { - const obj1 = { - id1: { - key: 'value', - key2: 'value2' - }, - id2: { - k: 'v' - } - }; - const obj2 = { - id1: { - key3: 'value3' - } - }; - const obj3 = { - id3: { - key: 'value' - } - }; - const expected = { - id1: { - key: 'value', - key2: 'value2', - key3: 'value3' - }, - id2: { - k: 'v' - }, - id3: { - key: 'value' - } - }; - - const merged = deepMerge([obj1, obj2, obj3]); - assert.deepEqual(expected, merged); - }); + const macroResultB = browsiRTD.getMacroId({}, slot); + expect(macroResultB).to.equal('browsiAd_1'); - it('check browsi sub module', function () { - const script = addBrowsiTag('scriptUrl.com'); - expect(script.getAttribute('data-sitekey')).to.equal('testKey'); - expect(script.getAttribute('data-pubkey')).to.equal('testPub'); - expect(script.async).to.equal(true); - - const slots = createSlots(); - const test1 = isIdMatchingAdUnit('browsiAd_1', slots[0], ['/57778053/Browsi_Demo_300x250']); // true - const test2 = isIdMatchingAdUnit('browsiAd_1', slots[0], ['/57778053/Browsi_Demo_300x250', '/57778053/Browsi']); // true - const test3 = isIdMatchingAdUnit('browsiAd_1', slots[0], ['/57778053/Browsi_Demo_Low']); // false - const test4 = isIdMatchingAdUnit('browsiAd_1', slots[0], []); // true - - expect(test1).to.equal(true); - expect(test2).to.equal(true); - expect(test3).to.equal(false); - expect(test4).to.equal(true); - }) + const macroResultC = browsiRTD.getMacroId({p: '', s: {s: 0, e: 1}}, slot); + expect(macroResultC).to.equal('/'); }); - describe('Real time module with Audigent provider', function () { - before(function () { - init(config); - audigentInit(config); - config.setConfig(conf); - setAudigentData(audigentSegments); + describe('should return data to RTD module', function () { + it('should return empty if no ad units defined', function (done) { + browsiRTD.setData({}); + browsiRTD.browsiSubmodule.getData([], onDone); + function onDone(data) { + expect(data).to.eql({}); + done(); + } }); - afterEach(function () { - $$PREBID_GLOBAL$$.requestBids.removeAll(); - config.resetConfig(); + it('should return NA if no prediction for ad unit', function (done) { + const adUnits = [getAdUnitMock('adMock')]; + browsiRTD.setData({}); + browsiRTD.browsiSubmodule.getData(adUnits, onDone); + function onDone(data) { + expect(data).to.eql({adMock: {bv: 'NA'}}); + done(); + } }); - it('check module using requestBidsHook', function () { - let adUnits1 = [getAdUnitMock('audigentAd_1')]; - let targeting = []; - let dataReceived = null; - - // set slot - const slotsB = createSlots(); - window.googletag.pubads().setSlots(slotsB); - - function afterBidHook(data) { - dataReceived = data; - slotsB.map(s => { - targeting = []; - s.getTargeting().map(value => { - targeting.push(Object.keys(value).toString()); - }); - }); - - dataReceived.adUnits.forEach(unit => { - unit.bids.forEach(bid => { - expect(bid.realTimeData).to.have.property('audigent_segments'); - expect(bid.realTimeData.audigent_segments).to.deep.equal(audigentSegments.audigent_segments); - }); - }); + it('should return prediction from server', function (done) { + const adUnits = [getAdUnitMock('hasPrediction')]; + const data = { + p: {'hasPrediction': {p: 0.234}}, + kn: 'bv', + pmd: undefined + }; + browsiRTD.setData(data); + browsiRTD.browsiSubmodule.getData(adUnits, onDone); + function onDone(data) { + expect(data).to.eql({hasPrediction: {bv: '0.20'}}); + done(); } - - requestBidsHook(afterBidHook, { adUnits: adUnits1 }); - }); - }); + }) + }) }); diff --git a/test/spec/modules/relaidoBidAdapter_spec.js b/test/spec/modules/relaidoBidAdapter_spec.js index f0d3a2fb6d8..cd4918460db 100644 --- a/test/spec/modules/relaidoBidAdapter_spec.js +++ b/test/spec/modules/relaidoBidAdapter_spec.js @@ -136,7 +136,7 @@ describe('RelaidoAdapter', function () { expect(bidRequests).to.have.lengthOf(1); const request = bidRequests[0]; expect(request.method).to.equal('GET'); - expect(request.url).to.equal('https://api.relaido.jp/vast/v1/out/bid/100000'); + expect(request.url).to.equal('https://api.relaido.jp/bid/v1/prebid/100000'); expect(request.bidId).to.equal(bidRequest.bidId); expect(request.width).to.equal(bidRequest.mediaTypes.video.playerSize[0][0]); expect(request.height).to.equal(bidRequest.mediaTypes.video.playerSize[0][1]); @@ -169,6 +169,15 @@ describe('RelaidoAdapter', function () { const request = bidRequests[0]; expect(request.mediaType).to.equal('banner'); }); + + it('The referrer should be the last', function () { + const bidRequests = spec.buildRequests([bidRequest], bidderRequest); + expect(bidRequests).to.have.lengthOf(1); + const request = bidRequests[0]; + const keys = Object.keys(request.data); + expect(keys[0]).to.equal('version'); + expect(keys[keys.length - 1]).to.equal('ref'); + }); }); describe('spec.interpretResponse', function () { diff --git a/test/spec/modules/revcontentBidAdapter_spec.js b/test/spec/modules/revcontentBidAdapter_spec.js index 1aa08d9469e..0a0263837c6 100644 --- a/test/spec/modules/revcontentBidAdapter_spec.js +++ b/test/spec/modules/revcontentBidAdapter_spec.js @@ -3,6 +3,7 @@ import {assert, expect} from 'chai'; import {spec} from 'modules/revcontentBidAdapter.js'; import { NATIVE } from 'src/mediaTypes.js'; import { config } from 'src/config.js'; +import * as utils from 'src/utils.js'; describe('revcontent adapter', function () { let serverResponse, bidRequest, bidResponses; @@ -327,4 +328,24 @@ describe('revcontent adapter', function () { assert.ok(result); }); }); + + describe('onBidWon', function() { + const bid = { + nurl: 'https://trends-s0.revcontent.com/push/track/?p=${AUCTION_PRICE}&d=nTCdHIfsgKOLFuV7DS1LF%2FnTk5HiFduGU65BgKgB%2BvKyG9YV7ceQWN76HMbBE0C6gwQeXUjravv3Hq5x9TT8CM6r2oUNgkGC9mhgv2yroTH9i3cSoH%2BilxyY19fMXFirtBz%2BF%2FEXKi4bsNh%2BDMPfj0L4elo%2FJEZmx4nslvOneJJjsFjJJtUJc%2F3UPivOisSCa%2B36mAgFQqt%2FSWBriYB%2BVAufz70LaGspF6T6jDzuIyVFJUpLhZVDtLRSJEzh7Lyzzw1FmYarp%2FPg0gZDY48aDdjw5A3Tlj%2Bap0cPHLDprNOyF0dmHDn%2FOVJEDRTWvrQ2JNK1t%2Fg1bGHIih0ec6XBVIBNurqRpLFBuUY6LgXCt0wRZWTByTEZ8AEv8IoYVILJAL%2BXL%2F9IyS4eTcdOUfn5X7gT8QBghCrAFrsCg8ZXKgWddTEXbpN1lU%2FzHdI5eSHkxkJ6WcYxSkY9PyripaIbmKiyb98LQMgTD%2B20RJO5dAmXTQTAcauw6IUPTjgSPEU%2Bd6L5Txd3CM00Hbd%2Bw1bREIQcpKEmlMwrRSwe4bu1BCjlh5A9gvU9Xc2sf7ekS3qPPmtp059r5IfzdNFQJB5aH9HqeDEU%2FxbMHx4ggMgojLBBL1fKrCKLAteEDQxd7PVmFJv7GHU2733vt5TnjKiEhqxHVFyi%2B0MIYMGIziM5HfUqfq3KUf%2F%2FeiCtJKXjg7FS6hOambdimSt7BdGDIZq9QECWdXsXcQqqVLwli27HYDMFVU3TWWRyjkjbhnQID9gQJlcpwIi87jVAODb6qP%2FKGQ%3D%3D', + cpm: '0.1' + }; + + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + + afterEach(function() { + utils.triggerPixel.restore(); + }); + + it('make sure only 1 ajax call is happening', function() { + spec.onBidWon(bid); + expect(utils.triggerPixel.calledOnce).to.equal(true); + }); + }); }); diff --git a/test/spec/modules/richaudienceBidAdapter_spec.js b/test/spec/modules/richaudienceBidAdapter_spec.js index 2bc699b4640..1c710c46ea2 100644 --- a/test/spec/modules/richaudienceBidAdapter_spec.js +++ b/test/spec/modules/richaudienceBidAdapter_spec.js @@ -29,12 +29,12 @@ describe('Richaudience adapter tests', function () { user: {} }]; - var DEFAULT_PARAMS_VIDEO = [{ + var DEFAULT_PARAMS_VIDEO_IN = [{ adUnitCode: 'test-div', bidId: '2c7c8e9c900244', mediaTypes: { video: { - context: 'instream', // or 'outstream' + context: 'instream', playerSize: [640, 480], mimes: ['video/mp4'] } @@ -52,6 +52,57 @@ describe('Richaudience adapter tests', function () { user: {} }]; + var DEFAULT_PARAMS_VIDEO_OUT = [{ + adUnitCode: 'test-div', + bidId: '2c7c8e9c900244', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480], + mimes: ['video/mp4'] + } + }, + bidder: 'richaudience', + params: { + bidfloor: 0.5, + pid: 'ADb1f40rmi', + supplyType: 'site' + }, + auctionId: '0cb3144c-d084-4686-b0d6-f5dbe917c563', + bidRequestsCount: 1, + bidderRequestId: '1858b7382993ca', + transactionId: '29df2112-348b-4961-8863-1b33684d95e6', + user: {} + }]; + + var DEFAULT_PARAMS_VIDEO_OUT_PARAMS = [{ + adUnitCode: 'test-div', + bidId: '2c7c8e9c900244', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480], + mimes: ['video/mp4'] + } + }, + bidder: 'richaudience', + params: { + bidfloor: 0.5, + pid: 'ADb1f40rmi', + supplyType: 'site', + player: { + init: 'close', + end: 'close', + skin: 'dark' + } + }, + auctionId: '0cb3144c-d084-4686-b0d6-f5dbe917c563', + bidRequestsCount: 1, + bidderRequestId: '1858b7382993ca', + transactionId: '29df2112-348b-4961-8863-1b33684d95e6', + user: {} + }]; + var DEFAULT_PARAMS_APP = [{ adUnitCode: 'test-div', bidId: '2c7c8e9c900244', @@ -191,6 +242,45 @@ describe('Richaudience adapter tests', function () { expect(requestContent).to.have.property('numIframes').and.to.equal(0); }) + it('Verify build request to prebid video inestream', function() { + const request = spec.buildRequests(DEFAULT_PARAMS_VIDEO_IN, { + gdprConsent: { + consentString: 'BOZcQl_ObPFjWAeABAESCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NohBgA', + gdprApplies: true + }, + refererInfo: { + referer: 'https://domain.com', + numIframes: 0 + } + }); + + expect(request[0]).to.have.property('method').and.to.equal('POST'); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('demand').and.to.equal('video'); + expect(requestContent.videoData).to.have.property('format').and.to.equal('instream'); + // expect(requestContent.videoData.playerSize[0][0]).to.equal('640'); + // expect(requestContent.videoData.playerSize[0][0]).to.equal('480'); + }) + + it('Verify build request to prebid video outstream', function() { + const request = spec.buildRequests(DEFAULT_PARAMS_VIDEO_OUT, { + gdprConsent: { + consentString: 'BOZcQl_ObPFjWAeABAESCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NohBgA', + gdprApplies: true + }, + refererInfo: { + referer: 'https://domain.com', + numIframes: 0 + } + }); + + expect(request[0]).to.have.property('method').and.to.equal('POST'); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent.videoData).to.have.property('format').and.to.equal('outstream'); + }) + describe('gdpr test', function () { it('Verify build request with GDPR', function () { config.setConfig({ @@ -267,7 +357,7 @@ describe('Richaudience adapter tests', function () { }); it('Verify build id5', function () { DEFAULT_PARAMS_WO_OPTIONAL[0].userId = {}; - DEFAULT_PARAMS_WO_OPTIONAL[0].userId.id5id = 'id5-user-id'; + DEFAULT_PARAMS_WO_OPTIONAL[0].userId.id5id = { uid: 'id5-user-id' }; var request = spec.buildRequests(DEFAULT_PARAMS_WO_OPTIONAL, DEFAULT_PARAMS_GDPR); var requestContent = JSON.parse(request[0].data); @@ -279,13 +369,23 @@ describe('Richaudience adapter tests', function () { var request; DEFAULT_PARAMS_WO_OPTIONAL[0].userId = {}; - DEFAULT_PARAMS_WO_OPTIONAL[0].userId.id5id = 1; + DEFAULT_PARAMS_WO_OPTIONAL[0].userId.id5id = { uid: 1 }; request = spec.buildRequests(DEFAULT_PARAMS_WO_OPTIONAL, DEFAULT_PARAMS_GDPR); var requestContent = JSON.parse(request[0].data); expect(requestContent.user.eids).to.equal(undefined); - DEFAULT_PARAMS_WO_OPTIONAL[0].userId.id5id = []; + DEFAULT_PARAMS_WO_OPTIONAL[0].userId.id5id = { uid: [] }; + request = spec.buildRequests(DEFAULT_PARAMS_WO_OPTIONAL, DEFAULT_PARAMS_GDPR); + requestContent = JSON.parse(request[0].data); + expect(requestContent.user.eids).to.equal(undefined); + + DEFAULT_PARAMS_WO_OPTIONAL[0].userId.id5id = { uid: null }; + request = spec.buildRequests(DEFAULT_PARAMS_WO_OPTIONAL, DEFAULT_PARAMS_GDPR); + requestContent = JSON.parse(request[0].data); + expect(requestContent.user.eids).to.equal(undefined); + + DEFAULT_PARAMS_WO_OPTIONAL[0].userId.id5id = { uid: {} }; request = spec.buildRequests(DEFAULT_PARAMS_WO_OPTIONAL, DEFAULT_PARAMS_GDPR); requestContent = JSON.parse(request[0].data); expect(requestContent.user.eids).to.equal(undefined); @@ -502,8 +602,26 @@ describe('Richaudience adapter tests', function () { expect(bid.dealId).to.equal('dealId'); }); - it('no banner media response', function () { - const request = spec.buildRequests(DEFAULT_PARAMS_NEW_SIZES, { + it('no banner media response inestream', function () { + const request = spec.buildRequests(DEFAULT_PARAMS_VIDEO_IN, { + gdprConsent: { + consentString: 'BOZcQl_ObPFjWAeABAESCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NohBgA', + gdprApplies: true + }, + refererInfo: { + referer: 'https://domain.com', + numIframes: 0 + } + }); + + const bids = spec.interpretResponse(BID_RESPONSE_VIDEO, request[0]); + const bid = bids[0]; + expect(bid.mediaType).to.equal('video'); + expect(bid.vastXml).to.equal(''); + }); + + it('no banner media response outstream', function () { + const request = spec.buildRequests(DEFAULT_PARAMS_VIDEO_OUT, { gdprConsent: { consentString: 'BOZcQl_ObPFjWAeABAESCD-AAAAjx7_______9______9uz_Ov_v_f__33e8__9v_l_7_-___u_-33d4-_1vf99yfm1-7ftr3tp_87ues2_Xur__59__3z3_NohBgA', gdprApplies: true @@ -516,7 +634,9 @@ describe('Richaudience adapter tests', function () { const bids = spec.interpretResponse(BID_RESPONSE_VIDEO, request[0]); const bid = bids[0]; + expect(bid.mediaType).to.equal('video'); expect(bid.vastXml).to.equal(''); + expect(bid.renderer.url).to.equal('https://cdn3.richaudience.com/prebidVideo/player.js'); }); it('Verifies bidder_code', function () { diff --git a/test/spec/modules/rtbhouseBidAdapter_spec.js b/test/spec/modules/rtbhouseBidAdapter_spec.js index 93b9692d2e2..efaed87dd15 100644 --- a/test/spec/modules/rtbhouseBidAdapter_spec.js +++ b/test/spec/modules/rtbhouseBidAdapter_spec.js @@ -69,6 +69,18 @@ describe('RTBHouseAdapter', () => { 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', 'transactionId': 'example-transaction-id', + 'schain': { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'directseller.com', + 'sid': '00001', + 'rid': 'BidRequest1', + 'hp': 1 + } + ] + } } ]; const bidderRequest = { @@ -173,6 +185,36 @@ describe('RTBHouseAdapter', () => { expect(data.imp[0].bidfloor).to.equal(0.01) }); + it('should include source.ext.schain in request', () => { + const bidRequest = Object.assign([], bidRequests); + const request = spec.buildRequests(bidRequest, bidderRequest); + const data = JSON.parse(request.data); + expect(data.source.ext.schain).to.deep.equal({ + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'directseller.com', + 'sid': '00001', + 'rid': 'BidRequest1', + 'hp': 1 + } + ] + }); + }); + + it('should not include invalid schain', () => { + const bidRequest = Object.assign([], bidRequests); + bidRequest[0].schain = { + 'nodes': [{ + 'unknown_key': 1 + }] + }; + const request = spec.buildRequests(bidRequest, bidderRequest); + const data = JSON.parse(request.data); + expect(data.source).to.not.have.property('ext'); + }); + describe('native imp', () => { function basicRequest(extension) { return Object.assign({ diff --git a/test/spec/modules/rtbsapeBidAdapter_spec.js b/test/spec/modules/rtbsapeBidAdapter_spec.js new file mode 100644 index 00000000000..4c3814385b3 --- /dev/null +++ b/test/spec/modules/rtbsapeBidAdapter_spec.js @@ -0,0 +1,166 @@ +import {expect} from 'chai'; +import {spec} from 'modules/rtbsapeBidAdapter.js'; +import * as utils from 'src/utils.js'; +import {executeRenderer, Renderer} from 'src/Renderer.js'; + +describe('rtbsapeBidAdapterTests', function () { + describe('isBidRequestValid', function () { + it('valid', function () { + expect(spec.isBidRequestValid({bidder: 'rtbsape', mediaTypes: {banner: true}, params: {placeId: 4321}})).to.equal(true); + expect(spec.isBidRequestValid({bidder: 'rtbsape', mediaTypes: {video: true}, params: {placeId: 4321}})).to.equal(true); + }); + + it('invalid', function () { + expect(spec.isBidRequestValid({bidder: 'rtbsape', mediaTypes: {banner: true}, params: {}})).to.equal(false); + expect(spec.isBidRequestValid({bidder: 'rtbsape', params: {placeId: 4321}})).to.equal(false); + }); + }); + + it('buildRequests', function () { + let bidRequestData = [{ + bidId: 'bid1234', + bidder: 'rtbsape', + params: {placeId: 4321}, + sizes: [[240, 400]] + }]; + let bidderRequest = { + auctionId: '2e208334-cafe-4c2c-b06b-f055ff876852', + bidderRequestId: '1392d0aa613366', + refererInfo: {} + }; + let request = spec.buildRequests(bidRequestData, bidderRequest); + expect(request.data.auctionId).to.equal('2e208334-cafe-4c2c-b06b-f055ff876852'); + expect(request.data.requestId).to.equal('1392d0aa613366'); + expect(request.data.bids[0].bidId).to.equal('bid1234'); + expect(request.data.timezone).to.not.equal(undefined); + }); + + describe('interpretResponse', function () { + it('banner', function () { + let serverResponse = { + body: { + bids: [{ + requestId: 'bid1234', + cpm: 2.21, + currency: 'RUB', + width: 240, + height: 400, + netRevenue: true, + ad: 'Ad html' + }] + } + }; + let bids = spec.interpretResponse(serverResponse, {data: {bids: [{mediaTypes: {banner: true}}]}}); + expect(bids).to.have.lengthOf(1); + let bid = bids[0]; + expect(bid.cpm).to.equal(2.21); + expect(bid.currency).to.equal('RUB'); + expect(bid.width).to.equal(240); + expect(bid.height).to.equal(400); + expect(bid.netRevenue).to.equal(true); + expect(bid.requestId).to.equal('bid1234'); + expect(bid.ad).to.equal('Ad html'); + }); + + describe('video (outstream)', function () { + let bid; + + before(() => { + let serverResponse = { + body: { + bids: [{ + requestId: 'bid1234', + adUnitCode: 'ad-bid1234', + cpm: 3.32, + currency: 'RUB', + width: 600, + height: 340, + netRevenue: true, + vastUrl: 'https://cdn-rtb.sape.ru/vast/4321.xml', + meta: { + mediaType: 'video' + } + }] + } + }; + let serverRequest = { + data: { + bids: [{ + bidId: 'bid1234', + adUnitCode: 'ad-bid1234', + mediaTypes: { + video: { + context: 'outstream' + } + }, + params: { + placeId: 4321, + video: { + playerMuted: false + } + } + }] + } + }; + let bids = spec.interpretResponse(serverResponse, serverRequest); + expect(bids).to.have.lengthOf(1); + bid = bids[0]; + }); + + it('should add renderer', () => { + expect(bid).to.have.own.property('renderer'); + expect(bid.renderer).to.be.instanceof(Renderer); + expect(bid.renderer.url).to.equal('https://cdn-rtb.sape.ru/js/player.js'); + expect(bid.playerMuted).to.equal(false); + }); + + it('should create player instance', () => { + let spy = false; + + window.sapeRtbPlayerHandler = function (id, w, h, m) { + const player = {addSlot: () => [id, w, h, m]} + expect(spy).to.equal(false); + spy = sinon.spy(player, 'addSlot'); + return player; + }; + + executeRenderer(bid.renderer, bid); + expect(spy).to.not.equal(false); + expect(spy.called).to.be.true; + + const spyCall = spy.getCall(0); + expect(spyCall.args[0].url).to.be.equal('https://cdn-rtb.sape.ru/vast/4321.xml'); + expect(spyCall.returnValue[0]).to.be.equal('ad-bid1234'); + expect(spyCall.returnValue[1]).to.be.equal(600); + expect(spyCall.returnValue[2]).to.be.equal(340); + expect(spyCall.returnValue[3]).to.be.equal(false); + }); + }); + }); + + it('getUserSyncs', function () { + const syncs = spec.getUserSyncs({iframeEnabled: true}); + expect(syncs).to.be.an('array').that.to.have.lengthOf(1); + expect(syncs[0]).to.deep.equal({type: 'iframe', url: 'https://www.acint.net/mc/?dp=141'}); + }); + + describe('onBidWon', function () { + beforeEach(function () { + sinon.stub(utils, 'triggerPixel'); + }); + + afterEach(function () { + utils.triggerPixel.restore(); + }); + + it('called once', function () { + spec.onBidWon({cpm: '2.21', nurl: 'https://ssp-rtb.sape.ru/track?event=win'}); + expect(utils.triggerPixel.calledOnce).to.equal(true); + }); + + it('called false', function () { + spec.onBidWon({cpm: '2.21'}); + expect(utils.triggerPixel.called).to.equal(false); + }); + }); +}); diff --git a/test/spec/modules/rubiconAnalyticsAdapter_spec.js b/test/spec/modules/rubiconAnalyticsAdapter_spec.js index 9dc228ed288..2bbab506b34 100644 --- a/test/spec/modules/rubiconAnalyticsAdapter_spec.js +++ b/test/spec/modules/rubiconAnalyticsAdapter_spec.js @@ -2,16 +2,17 @@ import rubiconAnalyticsAdapter, { SEND_TIMEOUT, parseBidResponse, getHostNameFromReferer, + storage, + rubiConf, } from 'modules/rubiconAnalyticsAdapter.js'; import CONSTANTS from 'src/constants.json'; import { config } from 'src/config.js'; import { server } from 'test/mocks/xhr.js'; - +import * as mockGpt from '../integration/faker/googletag.js'; import { setConfig, addBidResponseHook, } from 'modules/currency.js'; - let Ajv = require('ajv'); let schema = require('./rubiconAnalyticsSchema.json'); let ajv = new Ajv({ @@ -272,11 +273,19 @@ const MOCK = { ] }; +const STUBBED_UUID = '12345678-1234-1234-1234-123456789abc'; + const ANALYTICS_MESSAGE = { + 'channel': 'web', 'eventTimeMillis': 1519767013781, 'integration': 'pbjs', 'version': '$prebid.version$', 'referrerUri': 'http://www.test.com/page.html', + 'session': { + 'expires': 1519788613781, + 'id': STUBBED_UUID, + 'start': 1519767013781 + }, 'referrerHostname': 'www.test.com', 'auctions': [ { @@ -466,13 +475,18 @@ const ANALYTICS_MESSAGE = { 'wrapperName': '10000_fakewrapper_test' }; -function performStandardAuction() { +function performStandardAuction(gptEvents) { events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[0]); events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[1]); events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); events.emit(AUCTION_END, MOCK.AUCTION_END); + + if (gptEvents && gptEvents.length) { + gptEvents.forEach(gptEvent => mockGpt.emitEvent(gptEvent.eventName, gptEvent.params)); + } + events.emit(SET_TARGETING, MOCK.SET_TARGETING); events.emit(BID_WON, MOCK.BID_WON[0]); events.emit(BID_WON, MOCK.BID_WON[1]); @@ -481,12 +495,20 @@ function performStandardAuction() { describe('rubicon analytics adapter', function () { let sandbox; let clock; - + let getDataFromLocalStorageStub, setDataInLocalStorageStub, localStorageIsEnabledStub; beforeEach(function () { + getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); + setDataInLocalStorageStub = sinon.stub(storage, 'setDataInLocalStorage'); + localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled'); + mockGpt.disable(); sandbox = sinon.sandbox.create(); + localStorageIsEnabledStub.returns(true); + sandbox.stub(events, 'getEvents').returns([]); + sandbox.stub(utils, 'generateUUID').returns(STUBBED_UUID); + clock = sandbox.useFakeTimers(1519767013781); rubiconAnalyticsAdapter.referrerHostname = ''; @@ -505,6 +527,10 @@ describe('rubicon analytics adapter', function () { afterEach(function () { sandbox.restore(); config.resetConfig(); + mockGpt.enable(); + getDataFromLocalStorageStub.restore(); + setDataInLocalStorageStub.restore(); + localStorageIsEnabledStub.restore(); }); it('should require accountId', function () { @@ -531,6 +557,73 @@ describe('rubicon analytics adapter', function () { expect(utils.logError.called).to.equal(true); }); + describe('config subscribe', function() { + it('should update the pvid if user asks', function () { + expect(utils.generateUUID.called).to.equal(false); + config.setConfig({rubicon: {updatePageView: true}}); + expect(utils.generateUUID.called).to.equal(true); + }); + it('should merge in and preserve older set configs', function () { + config.setConfig({ + rubicon: { + wrapperName: '1001_general', + int_type: 'dmpbjs', + fpkvs: { + source: 'fb' + } + } + }); + expect(rubiConf).to.deep.equal({ + pvid: '12345678', + wrapperName: '1001_general', + int_type: 'dmpbjs', + fpkvs: { + source: 'fb' + }, + updatePageView: true + }); + + // update it with stuff + config.setConfig({ + rubicon: { + fpkvs: { + link: 'email' + } + } + }); + expect(rubiConf).to.deep.equal({ + pvid: '12345678', + wrapperName: '1001_general', + int_type: 'dmpbjs', + fpkvs: { + source: 'fb', + link: 'email' + }, + updatePageView: true + }); + + // overwriting specific edge keys should update them + config.setConfig({ + rubicon: { + fpkvs: { + link: 'iMessage', + source: 'twitter' + } + } + }); + expect(rubiConf).to.deep.equal({ + pvid: '12345678', + wrapperName: '1001_general', + int_type: 'dmpbjs', + fpkvs: { + link: 'iMessage', + source: 'twitter' + }, + updatePageView: true + }); + }); + }); + describe('sampling', function () { beforeEach(function () { sandbox.stub(Math, 'random').returns(0.08); @@ -659,12 +752,50 @@ describe('rubicon analytics adapter', function () { expect(message).to.deep.equal(ANALYTICS_MESSAGE); }); - it('should capture price floor information correctly', function () { + it('should handle bidResponse dimensions correctly', function () { + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + + // mock bid response with playerWidth and playerHeight (NO width and height) + let bidResponse1 = utils.deepClone(MOCK.BID_RESPONSE[0]); + delete bidResponse1.width; + delete bidResponse1.height; + bidResponse1.playerWidth = 640; + bidResponse1.playerHeight = 480; + + // mock bid response with no width height or playerwidth playerheight + let bidResponse2 = utils.deepClone(MOCK.BID_RESPONSE[1]); + delete bidResponse2.width; + delete bidResponse2.height; + delete bidResponse2.playerWidth; + delete bidResponse2.playerHeight; + + events.emit(BID_RESPONSE, bidResponse1); + events.emit(BID_RESPONSE, bidResponse2); + events.emit(BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(BID_WON, MOCK.BID_WON[0]); + events.emit(BID_WON, MOCK.BID_WON[1]); + + let message = JSON.parse(server.requests[0].requestBody); + validate(message); + expect(message.auctions[0].adUnits[0].bids[0].bidResponse.dimensions).to.deep.equal({ + width: 640, + height: 480 + }); + expect(message.auctions[0].adUnits[1].bids[0].bidResponse.dimensions).to.equal(undefined); + }); + + function performFloorAuction(provider) { let auctionInit = utils.deepClone(MOCK.AUCTION_INIT); auctionInit.bidderRequests[0].bids[0].floorData = { skipped: false, modelVersion: 'someModelName', - location: 'setConfig' + location: 'setConfig', + skipRate: 15, + fetchStatus: 'error', + floorProvider: provider }; let flooredResponse = { ...BID, @@ -725,6 +856,46 @@ describe('rubicon analytics adapter', function () { let message = JSON.parse(server.requests[0].requestBody); validate(message); + return message; + } + + it('should capture price floor information correctly', function () { + let message = performFloorAuction('rubicon') + + // verify our floor stuff is passed + // top level floor info + expect(message.auctions[0].floors).to.deep.equal({ + location: 'setConfig', + modelName: 'someModelName', + skipped: false, + enforcement: true, + dealsEnforced: false, + skipRate: 15, + fetchStatus: 'error', + provider: 'rubicon' + }); + // first adUnit's adSlot + expect(message.auctions[0].adUnits[0].gam.adSlot).to.equal('12345/sports'); + // since no other bids, we set adUnit status to no-bid + expect(message.auctions[0].adUnits[0].status).to.equal('no-bid'); + // first adUnits bid is rejected + expect(message.auctions[0].adUnits[0].bids[0].status).to.equal('rejected-ipf'); + expect(message.auctions[0].adUnits[0].bids[0].bidResponse.floorValue).to.equal(4); + // if bid rejected should take cpmAfterAdjustments val + expect(message.auctions[0].adUnits[0].bids[0].bidResponse.bidPriceUSD).to.equal(2.1); + + // second adUnit's adSlot + expect(message.auctions[0].adUnits[1].gam.adSlot).to.equal('12345/news'); + // top level adUnit status is success + expect(message.auctions[0].adUnits[1].status).to.equal('success'); + // second adUnits bid is success + expect(message.auctions[0].adUnits[1].bids[0].status).to.equal('success'); + expect(message.auctions[0].adUnits[1].bids[0].bidResponse.floorValue).to.equal(1); + expect(message.auctions[0].adUnits[1].bids[0].bidResponse.bidPriceUSD).to.equal(1.52); + }); + + it('should still send floor info if provider is not rubicon', function () { + let message = performFloorAuction('randomProvider'); // verify our floor stuff is passed // top level floor info @@ -733,20 +904,23 @@ describe('rubicon analytics adapter', function () { modelName: 'someModelName', skipped: false, enforcement: true, - dealsEnforced: false + dealsEnforced: false, + skipRate: 15, + fetchStatus: 'error', + provider: 'randomProvider' }); // first adUnit's adSlot - expect(message.auctions[0].adUnits[0].adSlot).to.equal('12345/sports'); + expect(message.auctions[0].adUnits[0].gam.adSlot).to.equal('12345/sports'); // since no other bids, we set adUnit status to no-bid expect(message.auctions[0].adUnits[0].status).to.equal('no-bid'); // first adUnits bid is rejected - expect(message.auctions[0].adUnits[0].bids[0].status).to.equal('rejected'); + expect(message.auctions[0].adUnits[0].bids[0].status).to.equal('rejected-ipf'); expect(message.auctions[0].adUnits[0].bids[0].bidResponse.floorValue).to.equal(4); // if bid rejected should take cpmAfterAdjustments val expect(message.auctions[0].adUnits[0].bids[0].bidResponse.bidPriceUSD).to.equal(2.1); // second adUnit's adSlot - expect(message.auctions[0].adUnits[1].adSlot).to.equal('12345/news'); + expect(message.auctions[0].adUnits[1].gam.adSlot).to.equal('12345/news'); // top level adUnit status is success expect(message.auctions[0].adUnits[1].status).to.equal('success'); // second adUnits bid is success @@ -755,6 +929,344 @@ describe('rubicon analytics adapter', function () { expect(message.auctions[0].adUnits[1].bids[0].bidResponse.bidPriceUSD).to.equal(1.52); }); + describe('with session handling', function () { + const expectedPvid = STUBBED_UUID.slice(0, 8); + beforeEach(function () { + config.setConfig({rubicon: {updatePageView: true}}); + }); + + it('should not log any session data if local storage is not enabled', function () { + localStorageIsEnabledStub.returns(false); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + delete expectedMessage.session; + delete expectedMessage.fpkvs; + + performStandardAuction(); + + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + + expect(request.url).to.equal('//localhost:9999/event'); + + let message = JSON.parse(request.requestBody); + validate(message); + + expect(message).to.deep.equal(expectedMessage); + }); + + it('should should pass along custom rubicon kv and pvid when defined', function () { + config.setConfig({rubicon: { + fpkvs: { + source: 'fb', + link: 'email' + } + }}); + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + validate(message); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.session.pvid = STUBBED_UUID.slice(0, 8); + expectedMessage.fpkvs = [ + {key: 'source', value: 'fb'}, + {key: 'link', value: 'email'} + ] + expect(message).to.deep.equal(expectedMessage); + }); + + it('should pick up existing localStorage and use its values', function () { + // set some localStorage + let inputlocalStorage = { + id: '987654', + start: 1519766113781, // 15 mins before "now" + expires: 1519787713781, // six hours later + lastSeen: 1519766113781, + fpkvs: { source: 'tw' } + }; + getDataFromLocalStorageStub.withArgs('rpaSession').returns(btoa(JSON.stringify(inputlocalStorage))); + + config.setConfig({rubicon: { + fpkvs: { + link: 'email' // should merge this with what is in the localStorage! + } + }}); + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + validate(message); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.session = { + id: '987654', + start: 1519766113781, + expires: 1519787713781, + pvid: expectedPvid + } + expectedMessage.fpkvs = [ + {key: 'source', value: 'tw'}, + {key: 'link', value: 'email'} + ] + expect(message).to.deep.equal(expectedMessage); + + let calledWith; + try { + calledWith = JSON.parse(atob(setDataInLocalStorageStub.getCall(0).args[1])); + } catch (e) { + calledWith = {}; + } + + expect(calledWith).to.deep.equal({ + id: '987654', // should have stayed same + start: 1519766113781, // should have stayed same + expires: 1519787713781, // should have stayed same + lastSeen: 1519767013781, // lastSeen updated to our "now" + fpkvs: { source: 'tw', link: 'email' }, // link merged in + pvid: expectedPvid // new pvid stored + }); + }); + + it('should throw out session if lastSeen > 30 mins ago and create new one', function () { + // set some localStorage + let inputlocalStorage = { + id: '987654', + start: 1519764313781, // 45 mins before "now" + expires: 1519785913781, // six hours later + lastSeen: 1519764313781, // 45 mins before "now" + fpkvs: { source: 'tw' } + }; + getDataFromLocalStorageStub.withArgs('rpaSession').returns(btoa(JSON.stringify(inputlocalStorage))); + + config.setConfig({rubicon: { + fpkvs: { + link: 'email' // should merge this with what is in the localStorage! + } + }}); + + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + validate(message); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + // session should match what is already in ANALYTICS_MESSAGE, just need to add pvid + expectedMessage.session.pvid = expectedPvid; + + // the saved fpkvs should have been thrown out since session expired + expectedMessage.fpkvs = [ + {key: 'link', value: 'email'} + ] + expect(message).to.deep.equal(expectedMessage); + + let calledWith; + try { + calledWith = JSON.parse(atob(setDataInLocalStorageStub.getCall(0).args[1])); + } catch (e) { + calledWith = {}; + } + + expect(calledWith).to.deep.equal({ + id: STUBBED_UUID, // should have stayed same + start: 1519767013781, // should have stayed same + expires: 1519788613781, // should have stayed same + lastSeen: 1519767013781, // lastSeen updated to our "now" + fpkvs: { link: 'email' }, // link merged in + pvid: expectedPvid // new pvid stored + }); + }); + + it('should throw out session if past expires time and create new one', function () { + // set some localStorage + let inputlocalStorage = { + id: '987654', + start: 1519745353781, // 6 hours before "expires" + expires: 1519766953781, // little more than six hours ago + lastSeen: 1519767008781, // 5 seconds ago + fpkvs: { source: 'tw' } + }; + getDataFromLocalStorageStub.withArgs('rpaSession').returns(btoa(JSON.stringify(inputlocalStorage))); + + config.setConfig({rubicon: { + fpkvs: { + link: 'email' // should merge this with what is in the localStorage! + } + }}); + + performStandardAuction(); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + validate(message); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + // session should match what is already in ANALYTICS_MESSAGE, just need to add pvid + expectedMessage.session.pvid = expectedPvid; + + // the saved fpkvs should have been thrown out since session expired + expectedMessage.fpkvs = [ + {key: 'link', value: 'email'} + ] + expect(message).to.deep.equal(expectedMessage); + + let calledWith; + try { + calledWith = JSON.parse(atob(setDataInLocalStorageStub.getCall(0).args[1])); + } catch (e) { + calledWith = {}; + } + + expect(calledWith).to.deep.equal({ + id: STUBBED_UUID, // should have stayed same + start: 1519767013781, // should have stayed same + expires: 1519788613781, // should have stayed same + lastSeen: 1519767013781, // lastSeen updated to our "now" + fpkvs: { link: 'email' }, // link merged in + pvid: expectedPvid // new pvid stored + }); + }); + }); + describe('with googletag enabled', function () { + let gptSlot0, gptSlot1, gptEvent0, gptEvent1; + beforeEach(function () { + mockGpt.enable(); + gptSlot0 = mockGpt.makeSlot({code: '/19968336/header-bid-tag-0'}); + gptSlot1 = mockGpt.makeSlot({code: '/19968336/header-bid-tag1'}); + gptEvent0 = { + eventName: 'slotRenderEnded', + params: { + slot: gptSlot0, + isEmpty: false, + advertiserId: 1111, + creativeId: 2222, + lineItemId: 3333 + } + }; + gptEvent1 = { + eventName: 'slotRenderEnded', + params: { + slot: gptSlot1, + isEmpty: false, + advertiserId: 4444, + creativeId: 5555, + lineItemId: 6666 + } + }; + }); + + afterEach(function () { + mockGpt.disable(); + }); + + it('should add necessary gam information if gpt is enabled and slotRender event emmited', function () { + performStandardAuction([gptEvent0, gptEvent1]); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + validate(message); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.auctions[0].adUnits[0].gam = { + advertiserId: 1111, + creativeId: 2222, + lineItemId: 3333, + adSlot: '/19968336/header-bid-tag-0' + }; + expectedMessage.auctions[0].adUnits[1].gam = { + advertiserId: 4444, + creativeId: 5555, + lineItemId: 6666, + adSlot: '/19968336/header-bid-tag1' + }; + expect(message).to.deep.equal(expectedMessage); + }); + + it('should handle empty gam renders', function () { + performStandardAuction([gptEvent0, { + eventName: 'slotRenderEnded', + params: { + slot: gptSlot1, + isEmpty: true + } + }]); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + validate(message); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.auctions[0].adUnits[0].gam = { + advertiserId: 1111, + creativeId: 2222, + lineItemId: 3333, + adSlot: '/19968336/header-bid-tag-0' + }; + expectedMessage.auctions[0].adUnits[1].gam = { + isSlotEmpty: true, + adSlot: '/19968336/header-bid-tag1' + }; + expect(message).to.deep.equal(expectedMessage); + }); + + it('should still add gam ids if falsy', function () { + performStandardAuction([gptEvent0, { + eventName: 'slotRenderEnded', + params: { + slot: gptSlot1, + isEmpty: false, + advertiserId: 0, + creativeId: 0, + lineItemId: 0 + } + }]); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + validate(message); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.auctions[0].adUnits[0].gam = { + advertiserId: 1111, + creativeId: 2222, + lineItemId: 3333, + adSlot: '/19968336/header-bid-tag-0' + }; + expectedMessage.auctions[0].adUnits[1].gam = { + advertiserId: 0, + creativeId: 0, + lineItemId: 0, + adSlot: '/19968336/header-bid-tag1' + }; + expect(message).to.deep.equal(expectedMessage); + }); + + it('should handle empty gam renders', function () { + performStandardAuction([gptEvent0, gptEvent1]); + expect(server.requests.length).to.equal(1); + let request = server.requests[0]; + let message = JSON.parse(request.requestBody); + validate(message); + + let expectedMessage = utils.deepClone(ANALYTICS_MESSAGE); + expectedMessage.auctions[0].adUnits[0].gam = { + advertiserId: 1111, + creativeId: 2222, + lineItemId: 3333, + adSlot: '/19968336/header-bid-tag-0' + }; + expectedMessage.auctions[0].adUnits[1].gam = { + advertiserId: 4444, + creativeId: 5555, + lineItemId: 6666, + adSlot: '/19968336/header-bid-tag1' + }; + expect(message).to.deep.equal(expectedMessage); + }); + }); + it('should correctly overwrite bidId if seatBidId is on the bidResponse', function () { // Only want one bid request in our mock auction let bidRequested = utils.deepClone(MOCK.BID_REQUESTED); @@ -917,12 +1429,9 @@ describe('rubicon analytics adapter', function () { describe('config with integration type', () => { it('should use the integration type provided in the config instead of the default', () => { - sandbox.stub(config, 'getConfig').callsFake(function (key) { - const config = { - 'rubicon.int_type': 'testType' - }; - return config[key]; - }); + config.setConfig({rubicon: { + int_type: 'testType' + }}) rubiconAnalyticsAdapter.enableAnalytics({ options: { diff --git a/test/spec/modules/rubiconAnalyticsSchema.json b/test/spec/modules/rubiconAnalyticsSchema.json index 16cca629d8c..13d39e46cd0 100644 --- a/test/spec/modules/rubiconAnalyticsSchema.json +++ b/test/spec/modules/rubiconAnalyticsSchema.json @@ -34,6 +34,53 @@ "type": "string", "description": "Version of Prebid.js responsible for the auctions contained within." }, + "fpkvs": { + "type": "array", + "description": "List of any dynamic key value pairs set by publisher.", + "minItems": 1, + "items": { + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, + "session": { + "type": "object", + "description": "The session information for a given event", + "required": [ + "id", + "start", + "expires" + ], + "properties": { + "id": { + "type": "string", + "description": "UUID of session." + }, + "start": { + "type": "integer", + "description": "Unix timestamp of time of creation for this session in milliseconds." + }, + "expires": { + "type": "integer", + "description": "Unix timestamp of the maximum allowed time in milliseconds of the session." + }, + "pvid": { + "type": "string", + "description": "id to track page view." + } + } + }, "auctions": { "type": "array", "minItems": 1, @@ -125,6 +172,9 @@ "zoneId": { "type": "number", "description": "The Rubicon zoneId associated with this adUnit - Removed if null" + }, + "gam": { + "$ref": "#/definitions/gam" } } } @@ -197,6 +247,31 @@ } }, "definitions": { + "gam": { + "type": "object", + "description": "The gam information for a given ad unit", + "required": [ + "adSlot" + ], + "properties": { + "adSlot": { + "type": "string" + }, + "advertiserId": { + "type": "integer" + }, + "creativeId": { + "type": "integer" + }, + "LineItemId": { + "type": "integer" + }, + "isSlotEmpty": { + "type": "boolean", + "enum": [true] + } + } + }, "adserverTargeting": { "type": "object", "description": "The adserverTargeting key/value pairs", @@ -293,7 +368,8 @@ "success", "no-bid", "error", - "rejected" + "rejected-gdpr", + "rejected-ipf" ] }, "error": { @@ -333,7 +409,6 @@ "bidResponse": { "type": "object", "required": [ - "dimensions", "mediaType", "bidPriceUSD" ], diff --git a/test/spec/modules/rubiconBidAdapter_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js index 99928b41d7b..dd25fafb149 100644 --- a/test/spec/modules/rubiconBidAdapter_spec.js +++ b/test/spec/modules/rubiconBidAdapter_spec.js @@ -1,10 +1,17 @@ import {expect} from 'chai'; -import adapterManager from 'src/adapterManager.js'; -import {spec, getPriceGranularity, masSizeOrdering, resetUserSync, hasVideoMediaType, FASTLANE_ENDPOINT} from 'modules/rubiconBidAdapter.js'; +import { + spec, + getPriceGranularity, + masSizeOrdering, + resetUserSync, + hasVideoMediaType, + resetRubiConf +} from 'modules/rubiconBidAdapter.js'; import {parse as parseQuery} from 'querystring'; import {config} from 'src/config.js'; import * as utils from 'src/utils.js'; import find from 'core-js-pure/features/array/find.js'; +import {createEidsArray} from 'modules/userId/eids.js'; const INTEGRATION = `pbjs_lite_v$prebid.version$`; // $prebid.version$ will be substituted in by gulp in built prebid const PBS_INTEGRATION = 'pbjs'; @@ -13,7 +20,8 @@ describe('the rubicon adapter', function () { let sandbox, bidderRequest, sizeMap, - getFloorResponse; + getFloorResponse, + logErrorSpy; /** * @typedef {Object} sizeMapConverted @@ -136,7 +144,7 @@ describe('the rubicon adapter', function () { 'targeting': [ { 'key': getProp('targeting_key', `rpfl_${i}`), - 'values': [ '43_tier_all_test' ] + 'values': ['43_tier_all_test'] } ] }; @@ -219,12 +227,27 @@ describe('the rubicon adapter', function () { 'size_id': 201, }; bid.userId = { - lipb: { - lipbid: '0000-1111-2222-3333', - segments: ['segA', 'segB'] - }, - idl_env: '1111-2222-3333-4444' + lipb: {lipbid: '0000-1111-2222-3333', segments: ['segA', 'segB']}, + idl_env: '1111-2222-3333-4444', + sharedid: {id: '1111', third: '2222'}, + tdid: '3000', + pubcid: '4000', + pubProvidedId: [{ + source: 'example.com', + uids: [{ + id: '333333', + ext: { + stype: 'ppuid' + } + }] + }, { + source: 'id-partner.com', + uids: [{ + id: '4444444' + }] + }] }; + bid.userIdAsEids = createEidsArray(bid.userId); bid.storedAuctionResponse = 11111; } @@ -272,6 +295,7 @@ describe('the rubicon adapter', function () { beforeEach(function () { sandbox = sinon.sandbox.create(); + logErrorSpy = sinon.spy(utils, 'logError'); getFloorResponse = {}; bidderRequest = { bidderCode: 'rubicon', @@ -343,6 +367,9 @@ describe('the rubicon adapter', function () { afterEach(function () { sandbox.restore(); + utils.logError.restore(); + config.resetConfig(); + resetRubiConf(); }); describe('MAS mapping / ordering', function () { @@ -412,7 +439,18 @@ describe('the rubicon adapter', function () { it('should correctly send hard floors when getFloor function is present and returns valid floor', function () { // default getFloor response is empty object so should not break and not send hard_floor bidderRequest.bids[0].getFloor = () => getFloorResponse; + sinon.spy(bidderRequest.bids[0], 'getFloor'); let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + + // make sure banner bid called with right stuff + expect( + bidderRequest.bids[0].getFloor.calledWith({ + currency: 'USD', + mediaType: 'banner', + size: '*' + }) + ).to.be.true; + let data = parseQuery(request.data); expect(data.rp_hard_floor).to.be.undefined; @@ -446,35 +484,30 @@ describe('the rubicon adapter', function () { data = parseQuery(request.data); expect(data.rp_hard_floor).to.equal('1.23'); }); - it('should not send p_pos to AE if not params.position specified', function() { - var noposRequest = utils.deepClone(bidderRequest); - delete noposRequest.bids[0].params.position; + it('should not send p_pos to AE if not params.position specified', function () { + var noposRequest = utils.deepClone(bidderRequest); + delete noposRequest.bids[0].params.position; - let [request] = spec.buildRequests(noposRequest.bids, noposRequest); - let data = parseQuery(request.data); + let [request] = spec.buildRequests(noposRequest.bids, noposRequest); + let data = parseQuery(request.data); - expect(data['site_id']).to.equal('70608'); - expect(data['p_pos']).to.equal(undefined); + expect(data['site_id']).to.equal('70608'); + expect(data['p_pos']).to.equal(undefined); }); - it('should not send p_pos to AE if not params.position is invalid', function() { - var badposRequest = utils.deepClone(bidderRequest); - badposRequest.bids[0].params.position = 'bad'; + it('should not send p_pos to AE if not params.position is invalid', function () { + var badposRequest = utils.deepClone(bidderRequest); + badposRequest.bids[0].params.position = 'bad'; - let [request] = spec.buildRequests(badposRequest.bids, badposRequest); - let data = parseQuery(request.data); + let [request] = spec.buildRequests(badposRequest.bids, badposRequest); + let data = parseQuery(request.data); - expect(data['site_id']).to.equal('70608'); - expect(data['p_pos']).to.equal(undefined); + expect(data['site_id']).to.equal('70608'); + expect(data['p_pos']).to.equal(undefined); }); it('should correctly send p_pos in sra fashion', function() { - sandbox.stub(config, 'getConfig').callsFake((key) => { - const config = { - 'rubicon.singleRequest': true - }; - return config[key]; - }); + config.setConfig({rubicon: {singleRequest: true}}); // first one is atf var sraPosRequest = utils.deepClone(bidderRequest); @@ -504,11 +537,11 @@ describe('the rubicon adapter', function () { expect(data['p_pos']).to.equal('atf;;btf;;'); }); - it('should not send x_source.pchain to AE if params.pchain is not specified', function() { - var noPchainRequest = utils.deepClone(bidderRequest); - delete noPchainRequest.bids[0].params.pchain; + it('should not send x_source.pchain to AE if params.pchain is not specified', function () { + var noPchainRequest = utils.deepClone(bidderRequest); + delete noPchainRequest.bids[0].params.pchain; - let [request] = spec.buildRequests(noPchainRequest.bids, noPchainRequest); + let [request] = spec.buildRequests(noPchainRequest.bids, noPchainRequest); expect(request.data).to.contain('&site_id=70608&'); expect(request.data).to.not.contain('x_source.pchain'); }); @@ -609,7 +642,7 @@ describe('the rubicon adapter', function () { expect(parseQuery(request.data).rf).to.equal('localhost'); delete bidderRequest.bids[0].params.referrer; - let refererInfo = { referer: 'https://www.prebid.org' }; + let refererInfo = {referer: 'https://www.prebid.org'}; bidderRequest = Object.assign({refererInfo}, bidderRequest); [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); expect(parseQuery(request.data).rf).to.equal('https://www.prebid.org'); @@ -1026,7 +1059,7 @@ describe('the rubicon adapter', function () { keywords: ['d'], gender: 'M', yob: '1984', - geo: { country: 'ca' } + geo: {country: 'ca'} }; sandbox.stub(config, 'getConfig').callsFake(key => { @@ -1067,12 +1100,7 @@ describe('the rubicon adapter', function () { it('should group all bid requests with the same site id', function () { sandbox.stub(Math, 'random').callsFake(() => 0.1); - sandbox.stub(config, 'getConfig').callsFake((key) => { - const config = { - 'rubicon.singleRequest': true - }; - return config[key]; - }); + config.setConfig({rubicon: {singleRequest: true}}); const expectedQuery = { 'account_id': '14062', @@ -1180,13 +1208,7 @@ describe('the rubicon adapter', function () { }); it('should not send more than 10 bids in a request (split into separate requests with <= 10 bids each)', function () { - sandbox.stub(config, 'getConfig').callsFake((key) => { - const config = { - 'rubicon.singleRequest': true - }; - return config[key]; - }); - + config.setConfig({rubicon: {singleRequest: true}}); let serverRequests; let data; @@ -1228,12 +1250,7 @@ describe('the rubicon adapter', function () { }); it('should not group bid requests if singleRequest does not equal true', function () { - sandbox.stub(config, 'getConfig').callsFake((key) => { - const config = { - 'rubicon.singleRequest': false - }; - return config[key]; - }); + config.setConfig({rubicon: {singleRequest: false}}); const bidCopy = utils.deepClone(bidderRequest.bids[0]); bidderRequest.bids.push(bidCopy); @@ -1251,12 +1268,7 @@ describe('the rubicon adapter', function () { }); it('should not group video bid requests', function () { - sandbox.stub(config, 'getConfig').callsFake((key) => { - const config = { - 'rubicon.singleRequest': true - }; - return config[key]; - }); + config.setConfig({rubicon: {singleRequest: true}}); const bidCopy = utils.deepClone(bidderRequest.bids[0]); bidderRequest.bids.push(bidCopy); @@ -1300,12 +1312,13 @@ describe('the rubicon adapter', function () { }); }); - describe('user id config', function() { - it('should send tpid_tdid when userId defines tdid', function () { + describe('user id config', function () { + it('should send tpid_tdid when userIdAsEids contains unifiedId', function () { const clonedBid = utils.deepClone(bidderRequest.bids[0]); clonedBid.userId = { tdid: 'abcd-efgh-ijkl-mnop-1234' }; + clonedBid.userIdAsEids = createEidsArray(clonedBid.userId); let [request] = spec.buildRequests([clonedBid], bidderRequest); let data = parseQuery(request.data); @@ -1313,20 +1326,21 @@ describe('the rubicon adapter', function () { }); describe('LiveIntent support', function () { - it('should send tpid_liveintent.com when userId defines lipd', function () { + it('should send tpid_liveintent.com when userIdAsEids contains liveintentId', function () { const clonedBid = utils.deepClone(bidderRequest.bids[0]); clonedBid.userId = { lipb: { lipbid: '0000-1111-2222-3333' } }; + clonedBid.userIdAsEids = createEidsArray(clonedBid.userId); let [request] = spec.buildRequests([clonedBid], bidderRequest); let data = parseQuery(request.data); expect(data['tpid_liveintent.com']).to.equal('0000-1111-2222-3333'); }); - it('should send tg_v.LIseg when userId defines lipd.segments', function () { + it('should send tg_v.LIseg when userIdAsEids contains liveintentId with ext.segments as array', function () { const clonedBid = utils.deepClone(bidderRequest.bids[0]); clonedBid.userId = { lipb: { @@ -1334,6 +1348,7 @@ describe('the rubicon adapter', function () { segments: ['segD', 'segE'] } }; + clonedBid.userIdAsEids = createEidsArray(clonedBid.userId); let [request] = spec.buildRequests([clonedBid], bidderRequest); const unescapedData = unescape(request.data); @@ -1343,18 +1358,80 @@ describe('the rubicon adapter', function () { }); describe('LiveRamp support', function () { - it('should send tpid_liveramp.com when userId defines idl_env', function () { + it('should send x_liverampidl when userIdAsEids contains liverampId', function () { const clonedBid = utils.deepClone(bidderRequest.bids[0]); clonedBid.userId = { idl_env: '1111-2222-3333-4444' }; + clonedBid.userIdAsEids = createEidsArray(clonedBid.userId); let [request] = spec.buildRequests([clonedBid], bidderRequest); let data = parseQuery(request.data); - expect(data['tpid_liveramp.com']).to.equal('1111-2222-3333-4444'); + expect(data['x_liverampidl']).to.equal('1111-2222-3333-4444'); + }); + }); + + describe('SharedID support', function () { + it('should send sharedid when userIdAsEids contains sharedId', function () { + const clonedBid = utils.deepClone(bidderRequest.bids[0]); + clonedBid.userId = { + sharedid: { + id: '1111', + third: '2222' + } + }; + clonedBid.userIdAsEids = createEidsArray(clonedBid.userId); + let [request] = spec.buildRequests([clonedBid], bidderRequest); + let data = parseQuery(request.data); + + expect(data['eid_sharedid.org']).to.equal('1111^1^2222'); }); }); - }) + + describe('pubProvidedId support', function () { + it('should send pubProvidedId when userIdAsEids contains pubProvidedId ids', function () { + const clonedBid = utils.deepClone(bidderRequest.bids[0]); + clonedBid.userId = { + pubProvidedId: [{ + source: 'example.com', + uids: [{ + id: '11111', + ext: { + stype: 'ppuid' + } + }] + }, { + source: 'id-partner.com', + uids: [{ + id: '222222' + }] + }] + }; + clonedBid.userIdAsEids = createEidsArray(clonedBid.userId); + let [request] = spec.buildRequests([clonedBid], bidderRequest); + let data = parseQuery(request.data); + + expect(data['ppuid']).to.equal('11111'); + }); + }); + + describe('Config user.id support', function () { + it('should send ppuid when config defines user.id', function () { + config.setConfig({user: {id: '123'}}); + const clonedBid = utils.deepClone(bidderRequest.bids[0]); + clonedBid.userId = { + sharedid: { + id: '1111', + third: '2222' + } + }; + let [request] = spec.buildRequests([clonedBid], bidderRequest); + let data = parseQuery(request.data); + + expect(data['ppuid']).to.equal('123'); + }); + }); + }); describe('Prebid AdSlot', function () { beforeEach(function () { @@ -1364,25 +1441,25 @@ describe('the rubicon adapter', function () { } }); - it('should not send \"tg_i.dfp_ad_unit_code\" if \"fpd.context\" object is not valid', function () { + it('should not send \"tg_i.pbadslot’\" if \"fpd.context\" object is not valid', function () { const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); const data = parseQuery(request.data); expect(data).to.be.an('Object'); - expect(data).to.not.have.property('tg_i.dfp_ad_unit_code'); + expect(data).to.not.have.property('tg_i.pbadslot’'); }); - it('should not send \"tg_i.dfp_ad_unit_code\" if \"fpd.context.pbAdSlot\" is undefined', function () { + it('should not send \"tg_i.pbadslot’\" if \"fpd.context.pbAdSlot\" is undefined', function () { bidderRequest.bids[0].fpd = {}; const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); const data = parseQuery(request.data); expect(data).to.be.an('Object'); - expect(data).to.not.have.property('tg_i.dfp_ad_unit_code'); + expect(data).to.not.have.property('tg_i.pbadslot’'); }); - it('should not send \"tg_i.dfp_ad_unit_code\" if \"fpd.context.pbAdSlot\" value is an empty string', function () { + it('should not send \"tg_i.pbadslot’\" if \"fpd.context.pbAdSlot\" value is an empty string', function () { bidderRequest.bids[0].fpd = { context: { pbAdSlot: '' @@ -1393,10 +1470,10 @@ describe('the rubicon adapter', function () { const data = parseQuery(request.data); expect(data).to.be.an('Object'); - expect(data).to.not.have.property('tg_i.dfp_ad_unit_code'); + expect(data).to.not.have.property('tg_i.pbadslot'); }); - it('should send \"tg_i.dfp_ad_unit_code\" if \"fpd.context.pbAdSlot\" value is a valid string', function () { + it('should send \"tg_i.pbadslot\" if \"fpd.context.pbAdSlot\" value is a valid string', function () { bidderRequest.bids[0].fpd = { context: { pbAdSlot: 'abc' @@ -1406,15 +1483,92 @@ describe('the rubicon adapter', function () { const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); const data = parseQuery(request.data); + expect(data).to.be.an('Object'); + expect(data).to.have.property('tg_i.pbadslot'); + expect(data['tg_i.pbadslot']).to.equal('abc'); + }); + + it('should send \"tg_i.pbadslot\" if \"fpd.context.pbAdSlot\" value is a valid string, but all leading slash characters should be removed', function () { + bidderRequest.bids[0].fpd = { + context: { + pbAdSlot: '/a/b/c' + } + }; + + const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + const data = parseQuery(request.data); + + expect(data).to.be.an('Object'); + expect(data).to.have.property('tg_i.pbadslot'); + expect(data['tg_i.pbadslot']).to.equal('a/b/c'); + }); + }); + + describe('GAM ad unit', function () { + beforeEach(function () { + // enforce that the bid at 0 does not have a 'context' property + if (bidderRequest.bids[0].hasOwnProperty('fpd')) { + delete bidderRequest.bids[0].fpd; + } + }); + + it('should not send \"tg_i.dfp_ad_unit_code’\" if \"fpd.context\" object is not valid', function () { + const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + const data = parseQuery(request.data); + + expect(data).to.be.an('Object'); + expect(data).to.not.have.property('tg_i.dfp_ad_unit_code’'); + }); + + it('should not send \"tg_i.dfp_ad_unit_code’\" if \"fpd.context.adServer.adSlot\" is undefined', function () { + bidderRequest.bids[0].fpd = {}; + + const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + const data = parseQuery(request.data); + + expect(data).to.be.an('Object'); + expect(data).to.not.have.property('tg_i.dfp_ad_unit_code’'); + }); + + it('should not send \"tg_i.dfp_ad_unit_code’\" if \"fpd.context.adServer.adSlot\" value is an empty string', function () { + bidderRequest.bids[0].fpd = { + context: { + adServer: { + adSlot: '' + } + } + }; + + const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + const data = parseQuery(request.data); + + expect(data).to.be.an('Object'); + expect(data).to.not.have.property('tg_i.dfp_ad_unit_code'); + }); + + it('should send \"tg_i.dfp_ad_unit_code\" if \"fpd.context.adServer.adSlot\" value is a valid string', function () { + bidderRequest.bids[0].fpd = { + context: { + adServer: { + adSlot: 'abc' + } + } + } + + const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + const data = parseQuery(request.data); + expect(data).to.be.an('Object'); expect(data).to.have.property('tg_i.dfp_ad_unit_code'); expect(data['tg_i.dfp_ad_unit_code']).to.equal('abc'); }); - it('should send \"tg_i.dfp_ad_unit_code\" if \"fpd.context.pbAdSlot\" value is a valid string, but all leading slash characters should be removed', function () { + it('should send \"tg_i.dfp_ad_unit_code\" if \"fpd.context.adServer.adSlot\" value is a valid string, but all leading slash characters should be removed', function () { bidderRequest.bids[0].fpd = { context: { - pbAdSlot: '/a/b/c' + adServer: { + adSlot: 'a/b/c' + } } }; @@ -1461,20 +1615,46 @@ describe('the rubicon adapter', function () { expect(post.site.content.language).to.equal('en'); expect(imp.ext.rubicon.video.skip).to.equal(1); expect(imp.ext.rubicon.video.skipafter).to.equal(15); + expect(imp.ext.prebid.auctiontimestamp).to.equal(1472239426000); expect(post.user.ext.consent).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A=='); + // EIDs should exist + expect(post.user.ext).to.have.property('eids').that.is.an('array'); + // LiveIntent should exist expect(post.user.ext.eids[0].source).to.equal('liveintent.com'); expect(post.user.ext.eids[0].uids[0].id).to.equal('0000-1111-2222-3333'); - expect(post.user.ext.tpid).that.is.an('object'); + expect(post.user.ext.eids[0].uids[0].atype).to.equal(1); + expect(post.user.ext.eids[0]).to.have.property('ext').that.is.an('object'); + expect(post.user.ext.eids[0].ext).to.have.property('segments').that.is.an('array'); + expect(post.user.ext.eids[0].ext.segments[0]).to.equal('segA'); + expect(post.user.ext.eids[0].ext.segments[1]).to.equal('segB'); + // Non-EID properties set using liveintent EID values + expect(post.user.ext).to.have.property('tpid').that.is.an('object'); expect(post.user.ext.tpid.source).to.equal('liveintent.com'); expect(post.user.ext.tpid.uid).to.equal('0000-1111-2222-3333'); + expect(post).to.have.property('rp').that.is.an('object'); + expect(post.rp).to.have.property('target').that.is.an('object'); + expect(post.rp.target).to.have.property('LIseg').that.is.an('array'); + expect(post.rp.target.LIseg[0]).to.equal('segA'); + expect(post.rp.target.LIseg[1]).to.equal('segB'); // LiveRamp should exist expect(post.user.ext.eids[1].source).to.equal('liveramp.com'); expect(post.user.ext.eids[1].uids[0].id).to.equal('1111-2222-3333-4444'); - expect(post.rp).that.is.an('object'); - expect(post.rp.target).that.is.an('object'); - expect(post.rp.target.LIseg).that.is.an('array'); - expect(post.rp.target.LIseg[0]).to.equal('segA'); - expect(post.rp.target.LIseg[1]).to.equal('segB'); + expect(post.user.ext.eids[1].uids[0].atype).to.equal(1); + + // SharedId should exist + expect(post.user.ext.eids[2].source).to.equal('sharedid.org'); + expect(post.user.ext.eids[2].uids[0].id).to.equal('1111'); + expect(post.user.ext.eids[2].uids[0].atype).to.equal(1); + expect(post.user.ext.eids[2].uids[0].ext.third).to.equal('2222'); + // UnifiedId should exist + expect(post.user.ext.eids[3].source).to.equal('adserver.org'); + expect(post.user.ext.eids[3].uids[0].atype).to.equal(1); + expect(post.user.ext.eids[3].uids[0].id).to.equal('3000'); + // PubCommonId should exist + expect(post.user.ext.eids[4].source).to.equal('pubcid.org'); + expect(post.user.ext.eids[4].uids[0].atype).to.equal(1); + expect(post.user.ext.eids[4].uids[0].id).to.equal('4000'); + expect(post.regs.ext.gdpr).to.equal(1); expect(post.regs.ext.us_privacy).to.equal('1NYN'); expect(post).to.have.property('ext').that.is.an('object'); @@ -1490,12 +1670,23 @@ describe('the rubicon adapter', function () { createVideoBidderRequest(); // default getFloor response is empty object so should not break and not send hard_floor bidderRequest.bids[0].getFloor = () => getFloorResponse; + sinon.spy(bidderRequest.bids[0], 'getFloor'); + sandbox.stub(Date, 'now').callsFake(() => bidderRequest.auctionStart + 100 ); let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + // make sure banner bid called with right stuff + expect( + bidderRequest.bids[0].getFloor.calledWith({ + currency: 'USD', + mediaType: 'video', + size: [640, 480] + }) + ).to.be.true; + // not an object should work and not send expect(request.data.imp[0].bidfloor).to.be.undefined; @@ -1519,7 +1710,31 @@ describe('the rubicon adapter', function () { [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); expect(request.data.imp[0].bidfloor).to.equal(1.23); }); - it('should add alias name to PBS Request', function() { + + it('should continue with auction and log error if getFloor throws one', function () { + createVideoBidderRequest(); + // default getFloor response is empty object so should not break and not send hard_floor + bidderRequest.bids[0].getFloor = () => { + throw new Error('An exception!'); + }; + sandbox.stub(Date, 'now').callsFake(() => + bidderRequest.auctionStart + 100 + ); + + let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + + // log error called + expect(logErrorSpy.calledOnce).to.equal(true); + + // should have an imp + expect(request.data.imp).to.exist.and.to.be.a('array'); + expect(request.data.imp).to.have.lengthOf(1); + + // should be NO bidFloor + expect(request.data.imp[0].bidfloor).to.be.undefined; + }); + + it('should add alias name to PBS Request', function () { createVideoBidderRequest(); bidderRequest.bidderCode = 'superRubicon'; @@ -1535,7 +1750,7 @@ describe('the rubicon adapter', function () { expect(request.data.imp[0].ext).to.not.haveOwnProperty('rubicon'); }); - it('should send correct bidfloor to PBS', function() { + it('should send correct bidfloor to PBS', function () { createVideoBidderRequest(); bidderRequest.bids[0].params.floor = 0.1; @@ -1725,14 +1940,14 @@ describe('the rubicon adapter', function () { let requests = spec.buildRequests(bidderRequest.bids, bidderRequest); expect(requests.length).to.equal(1); - expect(requests[0].url).to.equal(FASTLANE_ENDPOINT); + expect(requests[0].url).to.equal('https://fastlane.rubiconproject.com/a/api/fastlane.json'); bidderRequest.mediaTypes.video.context = 'instream'; requests = spec.buildRequests(bidderRequest.bids, bidderRequest); expect(requests.length).to.equal(1); - expect(requests[0].url).to.equal(FASTLANE_ENDPOINT); + expect(requests[0].url).to.equal('https://fastlane.rubiconproject.com/a/api/fastlane.json'); }); it('should send request as banner when invalid video bid in multiple mediaType bidRequest', function () { @@ -1751,7 +1966,7 @@ describe('the rubicon adapter', function () { let requests = spec.buildRequests(bidRequestCopy.bids, bidRequestCopy); expect(requests.length).to.equal(1); - expect(requests[0].url).to.equal(FASTLANE_ENDPOINT); + expect(requests[0].url).to.equal('https://fastlane.rubiconproject.com/a/api/fastlane.json'); }); it('should include coppa flag in video bid request', () => { @@ -1783,7 +1998,7 @@ describe('the rubicon adapter', function () { keywords: ['d'], gender: 'M', yob: '1984', - geo: { country: 'ca' } + geo: {country: 'ca'} }; sandbox.stub(config, 'getConfig').callsFake(key => { @@ -1797,7 +2012,7 @@ describe('the rubicon adapter', function () { }); const expected = [{ - bidders: [ 'rubicon' ], + bidders: ['rubicon'], config: { fpd: { site: Object.assign({}, bidderRequest.bids[0].params.inventory, context), @@ -1839,43 +2054,96 @@ describe('the rubicon adapter', function () { ); const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); - expect(request.data.imp[0].ext.context.data.adslot).to.equal('1234567890'); + expect(request.data.imp[0].ext.context.data.pbadslot).to.equal('1234567890'); + }); + + it('should include GAM ad unit in bid request', function () { + createVideoBidderRequest(); + bidderRequest.bids[0].fpd = { + context: { + adserver: { + adSlot: '1234567890', + name: 'adServerName1' + } + } + }; + + sandbox.stub(Date, 'now').callsFake(() => + bidderRequest.auctionStart + 100 + ); + + const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + expect(request.data.imp[0].ext.context.data.adserver.adslot).to.equal('1234567890'); + expect(request.data.imp[0].ext.context.data.adserver.name).to.equal('adServerName1'); }); it('should use the integration type provided in the config instead of the default', () => { createVideoBidderRequest(); - sandbox.stub(config, 'getConfig').callsFake(function (key) { - const config = { - 'rubicon.int_type': 'testType' - }; - return config[key]; - }); + config.setConfig({rubicon: {int_type: 'testType'}}); const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); expect(request.data.ext.prebid.bidders.rubicon.integration).to.equal('testType'); }); - }); - it('should include pbAdSlot in bid request', function () { - createVideoBidderRequest(); - bidderRequest.bids[0].fpd = { - context: { - pbAdSlot: '1234567890' - } - }; + it('should pass the user.id provided in the config', function () { + config.setConfig({user: {id: '123'}}); + createVideoBidderRequest(); - sandbox.stub(Date, 'now').callsFake(() => - bidderRequest.auctionStart + 100 - ); + sandbox.stub(Date, 'now').callsFake(() => + bidderRequest.auctionStart + 100 + ); - const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); - expect(request.data.imp[0].ext.context.data.adslot).to.equal('1234567890'); + let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + let post = request.data; + + expect(post).to.have.property('imp') + // .with.length.of(1); + let imp = post.imp[0]; + expect(imp.id).to.equal(bidderRequest.bids[0].adUnitCode); + expect(imp.exp).to.equal(300); + expect(imp.video.w).to.equal(640); + expect(imp.video.h).to.equal(480); + expect(imp.video.pos).to.equal(1); + expect(imp.video.context).to.equal('instream'); + expect(imp.video.minduration).to.equal(15); + expect(imp.video.maxduration).to.equal(30); + expect(imp.video.startdelay).to.equal(0); + expect(imp.video.skip).to.equal(1); + expect(imp.video.skipafter).to.equal(15); + expect(imp.ext.rubicon.video.playerWidth).to.equal(640); + expect(imp.ext.rubicon.video.playerHeight).to.equal(480); + expect(imp.ext.rubicon.video.size_id).to.equal(201); + expect(imp.ext.rubicon.video.language).to.equal('en'); + // Also want it to be in post.site.content.language + expect(post.site.content.language).to.equal('en'); + expect(imp.ext.rubicon.video.skip).to.equal(1); + expect(imp.ext.rubicon.video.skipafter).to.equal(15); + expect(imp.ext.prebid.auctiontimestamp).to.equal(1472239426000); + expect(post.user.ext.consent).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A=='); + + // Config user.id + expect(post.user.id).to.equal('123'); + + expect(post.regs.ext.gdpr).to.equal(1); + expect(post.regs.ext.us_privacy).to.equal('1NYN'); + expect(post).to.have.property('ext').that.is.an('object'); + expect(post.ext.prebid.targeting.includewinners).to.equal(true); + expect(post.ext.prebid).to.have.property('cache').that.is.an('object'); + expect(post.ext.prebid.cache).to.have.property('vastxml').that.is.an('object'); + expect(post.ext.prebid.cache.vastxml).to.have.property('returnCreative').that.is.an('boolean'); + expect(post.ext.prebid.cache.vastxml.returnCreative).to.equal(false); + expect(post.ext.prebid.bidders.rubicon.integration).to.equal(PBS_INTEGRATION); + }) }); describe('combineSlotUrlParams', function () { it('should combine an array of slot url params', function () { expect(spec.combineSlotUrlParams([])).to.deep.equal({}); - expect(spec.combineSlotUrlParams([{p1: 'foo', p2: 'test', p3: ''}])).to.deep.equal({p1: 'foo', p2: 'test', p3: ''}); + expect(spec.combineSlotUrlParams([{p1: 'foo', p2: 'test', p3: ''}])).to.deep.equal({ + p1: 'foo', + p2: 'test', + p3: '' + }); expect(spec.combineSlotUrlParams([{}, {p1: 'foo', p2: 'test'}])).to.deep.equal({p1: ';foo', p2: ';test'}); @@ -2431,7 +2699,7 @@ describe('the rubicon adapter', function () { }] }; - let bids = spec.interpretResponse({ body: response }, { + let bids = spec.interpretResponse({body: response}, { bidRequest: [utils.deepClone(bidderRequest.bids[0])] }); @@ -2442,7 +2710,7 @@ describe('the rubicon adapter', function () { describe('singleRequest enabled', function () { it('handles bidRequest of type Array and returns associated adUnits', function () { const overrideMap = []; - overrideMap[0] = { impression_id: '1' }; + overrideMap[0] = {impression_id: '1'}; const stubAds = []; for (let i = 0; i < 10; i++) { @@ -2464,7 +2732,8 @@ describe('the rubicon adapter', function () { 'tracking': '', 'inventory': {}, 'ads': stubAds - }}, { bidRequest: stubBids }); + } + }, {bidRequest: stubBids}); expect(bids).to.be.a('array').with.lengthOf(10); bids.forEach((bid) => { @@ -2497,7 +2766,7 @@ describe('the rubicon adapter', function () { it('handles incorrect adUnits length by returning all bids with matching ads', function () { const overrideMap = []; - overrideMap[0] = { impression_id: '1' }; + overrideMap[0] = {impression_id: '1'}; const stubAds = []; for (let i = 0; i < 6; i++) { @@ -2519,7 +2788,8 @@ describe('the rubicon adapter', function () { 'tracking': '', 'inventory': {}, 'ads': stubAds - }}, { bidRequest: stubBids }); + } + }, {bidRequest: stubBids}); // no bids expected because response didn't match requested bid number expect(bids).to.be.a('array').with.lengthOf(6); @@ -2530,11 +2800,11 @@ describe('the rubicon adapter', function () { // Create overrides to break associations between bids and ads // Each override should cause one less bid to be returned by interpretResponse const overrideMap = []; - overrideMap[0] = { impression_id: '1' }; - overrideMap[2] = { status: 'error' }; - overrideMap[4] = { status: 'error' }; - overrideMap[7] = { status: 'error' }; - overrideMap[8] = { status: 'error' }; + overrideMap[0] = {impression_id: '1'}; + overrideMap[2] = {status: 'error'}; + overrideMap[4] = {status: 'error'}; + overrideMap[7] = {status: 'error'}; + overrideMap[8] = {status: 'error'}; for (let i = 0; i < 10; i++) { stubAds.push(createResponseAdByIndex(i, sizeMap[i].sizeId, overrideMap)); @@ -2555,7 +2825,8 @@ describe('the rubicon adapter', function () { 'tracking': '', 'inventory': {}, 'ads': stubAds - }}, { bidRequest: stubBids }); + } + }, {bidRequest: stubBids}); expect(bids).to.be.a('array').with.lengthOf(6); bids.forEach((bid) => { @@ -2646,12 +2917,7 @@ describe('the rubicon adapter', function () { describe('config with integration type', () => { it('should use the integration type provided in the config instead of the default', () => { - sandbox.stub(config, 'getConfig').callsFake(function (key) { - const config = { - 'rubicon.int_type': 'testType' - }; - return config[key]; - }); + config.setConfig({rubicon: {int_type: 'testType'}}); const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); expect(parseQuery(request.data).tk_flint).to.equal('testType_v$prebid.version$'); }); @@ -2686,7 +2952,7 @@ describe('the rubicon adapter', function () { }); it('should pass gdpr params if consent is true', function () { - expect(spec.getUserSyncs({ iframeEnabled: true }, {}, { + expect(spec.getUserSyncs({iframeEnabled: true}, {}, { gdprApplies: true, consentString: 'foo' })).to.deep.equal({ type: 'iframe', url: `${emilyUrl}?gdpr=1&gdpr_consent=foo` @@ -2694,7 +2960,7 @@ describe('the rubicon adapter', function () { }); it('should pass gdpr params if consent is false', function () { - expect(spec.getUserSyncs({ iframeEnabled: true }, {}, { + expect(spec.getUserSyncs({iframeEnabled: true}, {}, { gdprApplies: false, consentString: 'foo' })).to.deep.equal({ type: 'iframe', url: `${emilyUrl}?gdpr=0&gdpr_consent=foo` @@ -2702,7 +2968,7 @@ describe('the rubicon adapter', function () { }); it('should pass gdpr param gdpr_consent only when gdprApplies is undefined', function () { - expect(spec.getUserSyncs({ iframeEnabled: true }, {}, { + expect(spec.getUserSyncs({iframeEnabled: true}, {}, { consentString: 'foo' })).to.deep.equal({ type: 'iframe', url: `${emilyUrl}?gdpr_consent=foo` @@ -2710,13 +2976,13 @@ describe('the rubicon adapter', function () { }); it('should pass no params if gdpr consentString is not defined', function () { - expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {})).to.deep.equal({ + expect(spec.getUserSyncs({iframeEnabled: true}, {}, {})).to.deep.equal({ type: 'iframe', url: `${emilyUrl}` }); }); it('should pass no params if gdpr consentString is a number', function () { - expect(spec.getUserSyncs({ iframeEnabled: true }, {}, { + expect(spec.getUserSyncs({iframeEnabled: true}, {}, { consentString: 0 })).to.deep.equal({ type: 'iframe', url: `${emilyUrl}` @@ -2724,7 +2990,7 @@ describe('the rubicon adapter', function () { }); it('should pass no params if gdpr consentString is null', function () { - expect(spec.getUserSyncs({ iframeEnabled: true }, {}, { + expect(spec.getUserSyncs({iframeEnabled: true}, {}, { consentString: null })).to.deep.equal({ type: 'iframe', url: `${emilyUrl}` @@ -2732,7 +2998,7 @@ describe('the rubicon adapter', function () { }); it('should pass no params if gdpr consentString is a object', function () { - expect(spec.getUserSyncs({ iframeEnabled: true }, {}, { + expect(spec.getUserSyncs({iframeEnabled: true}, {}, { consentString: {} })).to.deep.equal({ type: 'iframe', url: `${emilyUrl}` @@ -2740,19 +3006,19 @@ describe('the rubicon adapter', function () { }); it('should pass no params if gdpr is not defined', function () { - expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined)).to.deep.equal({ + expect(spec.getUserSyncs({iframeEnabled: true}, {}, undefined)).to.deep.equal({ type: 'iframe', url: `${emilyUrl}` }); }); it('should pass us_privacy if uspConsent is defined', function () { - expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, '1NYN')).to.deep.equal({ + expect(spec.getUserSyncs({iframeEnabled: true}, {}, undefined, '1NYN')).to.deep.equal({ type: 'iframe', url: `${emilyUrl}?us_privacy=1NYN` }); }); it('should pass us_privacy after gdpr if both are present', function () { - expect(spec.getUserSyncs({ iframeEnabled: true }, {}, { + expect(spec.getUserSyncs({iframeEnabled: true}, {}, { consentString: 'foo' }, '1NYN')).to.deep.equal({ type: 'iframe', url: `${emilyUrl}?gdpr_consent=foo&us_privacy=1NYN` @@ -2760,8 +3026,8 @@ describe('the rubicon adapter', function () { }); }); - describe('get price granularity', function() { - it('should return correct buckets for all price granularity values', function() { + describe('get price granularity', function () { + it('should return correct buckets for all price granularity values', function () { const CUSTOM_PRICE_BUCKET_ITEM = {max: 5, increment: 0.5}; const mockConfig = { @@ -2794,7 +3060,7 @@ describe('the rubicon adapter', function () { }); }); - describe('Supply Chain Support', function() { + describe('Supply Chain Support', function () { const nodePropsOrder = ['asi', 'sid', 'hp', 'rid', 'name', 'domain']; let bidRequests; let schainConfig; @@ -2887,4 +3153,51 @@ describe('the rubicon adapter', function () { expect(request[0].data.source.ext.schain).to.deep.equal(schain); }); }); + + describe('configurable settings', function() { + afterEach(() => { + config.setConfig({ + rubicon: { + bannerHost: 'rubicon', + videoHost: 'prebid-server', + syncHost: 'eus', + returnVast: false + } + }); + config.resetConfig(); + }); + + beforeEach(function () { + resetUserSync(); + }); + + it('should update fastlane endpoint if', function () { + config.setConfig({ + rubicon: { + bannerHost: 'fastlane-qa', + videoHost: 'prebid-server-qa', + syncHost: 'eus-qa', + returnVast: true + } + }); + + // banner + let [bannerRequest] = spec.buildRequests(bidderRequest.bids, bidderRequest); + expect(bannerRequest.url).to.equal('https://fastlane-qa.rubiconproject.com/a/api/fastlane.json'); + + // video and returnVast + createVideoBidderRequest(); + let [videoRequest] = spec.buildRequests(bidderRequest.bids, bidderRequest); + let post = videoRequest.data; + expect(videoRequest.url).to.equal('https://prebid-server-qa.rubiconproject.com/openrtb2/auction'); + expect(post.ext.prebid.cache.vastxml).to.have.property('returnCreative').that.is.an('boolean'); + expect(post.ext.prebid.cache.vastxml.returnCreative).to.equal(true); + + // user sync + let syncs = spec.getUserSyncs({ + iframeEnabled: true + }); + expect(syncs).to.deep.equal({type: 'iframe', url: 'https://eus-qa.rubiconproject.com/usync.html'}); + }); + }); }); diff --git a/test/spec/modules/saambaaBidAdapter_spec.js b/test/spec/modules/saambaaBidAdapter_spec.js new file mode 100755 index 00000000000..80a85ae895d --- /dev/null +++ b/test/spec/modules/saambaaBidAdapter_spec.js @@ -0,0 +1,139 @@ +import { expect } from 'chai'; +import { spec } from 'modules/saambaaBidAdapter.js'; +import { BANNER, VIDEO } from 'src/mediaTypes.js'; + +describe('saambaaBidAdapter', function () { + let bidRequests; + let bidRequestsVid; + + beforeEach(function () { + bidRequests = [{'bidder': 'saambaa', 'params': {'pubid': '121ab139faf7ac67428a23f1d0a9a71b', 'floor': 0.5, 'placement': 1234, size: '320x250'}, 'crumbs': {'pubcid': '979fde13-c71e-4ac2-98b7-28c90f99b449'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]]}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'transactionId': 'f72931e6-2b0e-4e37-a2bc-1ea912141f81', 'sizes': [[300, 250]], 'bidId': '2aa73f571eaf29', 'bidderRequestId': '1bac84515a7af3', 'auctionId': '5dbc60fa-1aa1-41ce-9092-e6bbd4d478f7', 'src': 'client', 'bidRequestsCount': 1, 'pageurl': 'http://google.com'}]; + + bidRequestsVid = [{'bidder': 'saambaa', 'params': {'pubid': '121ab139faf7ac67428a23f1d0a9a71b', 'floor': 1.0, 'placement': 1234, size: '320x480', 'video': {'id': 123, 'skip': 1, 'mimes': ['video/mp4', 'application/javascript'], 'playbackmethod': [2, 6], 'maxduration': 30}}, 'crumbs': {'pubcid': '979fde13-c71e-4ac2-98b7-28c90f99b449'}, 'mediaTypes': {'video': {'playerSize': [[320, 480]], 'context': 'instream'}}, 'adUnitCode': 'video1', 'transactionId': '8b060952-93f7-4863-af44-bb8796b97c42', 'sizes': [], 'bidId': '25c6ab92aa0e81', 'bidderRequestId': '1d420b73a013fc', 'auctionId': '9a69741c-34fb-474c-83e1-cfa003aaee17', 'src': 'client', 'bidRequestsCount': 1, 'pageurl': 'http://google.com'}]; + }); + + describe('spec.isBidRequestValid', function () { + it('should return true when the required params are passed for banner', function () { + const bidRequest = bidRequests[0]; + expect(spec.isBidRequestValid(bidRequest)).to.equal(true); + }); + + it('should return true when the required params are passed for video', function () { + const bidRequests = bidRequestsVid[0]; + expect(spec.isBidRequestValid(bidRequests)).to.equal(true); + }); + + it('should return false when no pub id params are passed', function () { + const bidRequest = bidRequests[0]; + bidRequest.params.pubid = ''; + expect(spec.isBidRequestValid(bidRequest)).to.equal(false); + }); + + it('should return false when no placement params are passed', function () { + const bidRequest = bidRequests[0]; + bidRequest.params.placement = ''; + expect(spec.isBidRequestValid(bidRequest)).to.equal(false); + }); + + it('should return false when a bid request is not passed', function () { + expect(spec.isBidRequestValid()).to.equal(false); + expect(spec.isBidRequestValid({})).to.equal(false); + }); + }); + + describe('spec.buildRequests', function () { + it('should create a POST request for each bid', function () { + const bidRequest = bidRequests[0]; + const requests = spec.buildRequests([ bidRequest ]); + expect(requests[0].method).to.equal('POST'); + }); + + it('should create a POST request for each bid in video request', function () { + const bidRequest = bidRequestsVid[0]; + const requests = spec.buildRequests([ bidRequest ]); + expect(requests[0].method).to.equal('POST'); + }); + + it('should have domain in request', function () { + const bidRequest = bidRequests[0]; + const requests = spec.buildRequests([ bidRequest ]); + expect(requests[0].data.site.domain).length !== 0; + }); + }); + + describe('spec.interpretResponse', function () { + describe('for banner bids', function () { + it('should return no bids if the response is not valid', function () { + const bidRequest = bidRequests[0]; + bidRequest.mediaTypes = { banner: {} }; + const bidResponse = spec.interpretResponse({ body: null }, { bidRequest }); + + if (typeof bidResponse !== 'undefined') { + expect(bidResponse.length).to.equal(0); + } else { + expect(true).to.equal(true); + } + }); + + it('should return no bids if the response is empty', function () { + const bidRequest = bidRequests[0]; + bidRequest.mediaTypes = { banner: {} }; + const bidResponse = spec.interpretResponse({ body: [] }, { bidRequest }); + if (typeof bidResponse !== 'undefined') { + expect(bidResponse.length).to.equal(0); + } else { expect(true).to.equal(true); } + }); + + it('should return valid video bid responses', function () { + let _mediaTypes = VIDEO; + const saambaabidreqVid = {'bidRequest': {'mediaTypes': {'video': {'w': 320, 'h': 480}}}}; + const serverResponseVid = {'cur': 'USD', 'id': '25c6ab92aa0e81', 'seatbid': [{'seat': '3', 'bid': [{'crid': '1855', 'h': 480, 'protocol': 2, 'nurl': 'http://nep.advangelists.com/xp/evt?pp=1MO1wiaMhhq7wLRzZZwwwPkJxxKpYEnM5k5MH4qSGm1HR8rp3Nl7vDocvzZzSAvE4pnREL9mQ1kf5PDjk6E8em6DOk7vVrYUH1TYQyqCucd58PFpJNN7h30RXKHHFg3XaLuQ3PKfMuI1qZATBJ6WHcu875y0hqRdiewn0J4JsCYF53M27uwmcV0HnQxARQZZ72mPqrW95U6wgkZljziwKrICM3aBV07TU6YK5R5AyzJRuD6mtrQ2xtHlQ3jXVYKE5bvWFiUQd90t0jOGhPtYBNoOfP7uQ4ZZj4pyucxbr96orHe9PSOn9UpCSWArdx7s8lOfDpwOvbMuyGxynbStDWm38sDgd4bMHnIt762m5VMDNJfiUyX0vWzp05OsufJDVEaWhAM62i40lQZo7mWP4ipoOWLkmlaAzFIMsTcNaHAHiKKqGEOZLkCEhFNM0SLcvgN2HFRULOOIZvusq7TydOKxuXgCS91dLUDxDDDFUK83BFKlMkTxnCzkLbIR1bd9GKcr1TRryOrulyvRWAKAIhEsUzsc5QWFUhmI2dZ1eqnBQJ0c89TaPcnoaP2WipF68UgyiOstf2CBy0M34858tC5PmuQwQYwXscg6zyqDwR0i9MzGH4FkTyU5yeOlPcsA0ht6UcoCdFpHpumDrLUwAaxwGk1Nj8S6YlYYT5wNuTifDGbg22QKXzZBkUARiyVvgPn9nRtXnrd7WmiMYq596rya9RQj7LC0auQW8bHVQLEe49shsZDnAwZTWr4QuYKqgRGZcXteG7RVJe0ryBZezOq11ha9C0Lv0siNVBahOXE35Wzoq4c4BDaGpqvhaKN7pjeWLGlQR04ufWekwxiMWAvjmfgAfexBJ7HfbYNZpq__', 'adid': '61_1855', 'adomain': ['chevrolet.com'], 'price': 2, 'w': 320, 'iurl': 'https://daf37cpxaja7f.cloudfront.net/c61/creative_url_14922301369663_1.png', 'cat': ['IAB2'], 'id': '7f570b40-aca1-4806-8ea8-818ea679c82b_0', 'attr': [], 'impid': '0', 'cid': '61'}]}], 'bidid': '7f570b40-aca1-4806-8ea8-818ea679c82b'} + const bidResponseVid = spec.interpretResponse({ body: serverResponseVid }, saambaabidreqVid); + delete bidResponseVid['vastUrl']; + delete bidResponseVid['ad']; + expect(bidResponseVid).to.deep.equal({ + requestId: bidRequestsVid[0].bidId, + bidderCode: 'saambaa', + creativeId: serverResponseVid.seatbid[0].bid[0].crid, + cpm: serverResponseVid.seatbid[0].bid[0].price, + width: serverResponseVid.seatbid[0].bid[0].w, + height: serverResponseVid.seatbid[0].bid[0].h, + mediaType: 'video', + meta: { advertiserDomains: serverResponseVid.seatbid[0].bid[0].adomain }, + currency: 'USD', + netRevenue: true, + ttl: 60 + }); + }); + + it('should return valid banner bid responses', function () { + const saambaabidreq = {bids: {}}; + bidRequests.forEach(bid => { + let _mediaTypes = (bid.mediaTypes && bid.mediaTypes.video ? VIDEO : BANNER); + saambaabidreq.bids[bid.bidId] = {mediaTypes: _mediaTypes, + w: _mediaTypes == BANNER ? bid.mediaTypes[_mediaTypes].sizes[0][0] : bid.mediaTypes[_mediaTypes].playerSize[0], + h: _mediaTypes == BANNER ? bid.mediaTypes[_mediaTypes].sizes[0][1] : bid.mediaTypes[_mediaTypes].playerSize[1] + + }; + }); + const serverResponse = {'id': '2aa73f571eaf29', 'seatbid': [{'bid': [{'id': '2c5e8a1a84522d', 'impid': '2c5e8a1a84522d', 'price': 0.81, 'adid': 'abcde-12345', 'nurl': '', 'adm': '
', 'adomain': ['advertiserdomain.com'], 'iurl': '', 'cid': 'campaign1', 'crid': 'abcde-12345', 'w': 300, 'h': 250}], 'seat': '19513bcfca8006'}], 'bidid': '19513bcfca8006', 'cur': 'USD', 'w': 300, 'h': 250}; + + const bidResponse = spec.interpretResponse({ body: serverResponse }, saambaabidreq); + expect(bidResponse).to.deep.equal({ + requestId: bidRequests[0].bidId, + ad: serverResponse.seatbid[0].bid[0].adm, + bidderCode: 'saambaa', + creativeId: serverResponse.seatbid[0].bid[0].crid, + cpm: serverResponse.seatbid[0].bid[0].price, + width: serverResponse.seatbid[0].bid[0].w, + height: serverResponse.seatbid[0].bid[0].h, + mediaType: 'banner', + meta: { advertiserDomains: serverResponse.seatbid[0].bid[0].adomain }, + currency: 'USD', + netRevenue: true, + ttl: 60 + }); + }); + }); + }); +}); diff --git a/test/spec/modules/seedingAllianceAdapter_spec.js b/test/spec/modules/seedingAllianceAdapter_spec.js index e6f96c92fd9..81af9546ff0 100755 --- a/test/spec/modules/seedingAllianceAdapter_spec.js +++ b/test/spec/modules/seedingAllianceAdapter_spec.js @@ -38,7 +38,7 @@ describe('SeedingAlliance adapter', function () { }); it('should have default request structure', function () { - let keys = 'site,device,cur,imp,user'.split(','); + let keys = 'site,device,cur,imp,user,regs'.split(','); let validBidRequests = [{ bidId: 'bidId', params: {} diff --git a/test/spec/modules/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js index 5c8c58196f7..8957bde6bd9 100644 --- a/test/spec/modules/seedtagBidAdapter_spec.js +++ b/test/spec/modules/seedtagBidAdapter_spec.js @@ -1,6 +1,9 @@ import { expect } from 'chai' import { spec, getTimeoutUrl } from 'modules/seedtagBidAdapter.js' +const PUBLISHER_ID = '0000-0000-01' +const ADUNIT_ID = '000000' + function getSlotConfigs(mediaTypes, params) { return { params: params, @@ -16,10 +19,16 @@ function getSlotConfigs(mediaTypes, params) { } } +function createVideoSlotConfig(mediaType) { + return getSlotConfigs(mediaType, { + publisherId: PUBLISHER_ID, + adUnitId: ADUNIT_ID, + placement: 'video' + }) +} + describe('Seedtag Adapter', function() { describe('isBidRequestValid method', function() { - const PUBLISHER_ID = '0000-0000-01' - const ADUNIT_ID = '000000' describe('returns true', function() { describe('when banner slot config has all mandatory params', () => { describe('and placement has the correct value', function() { @@ -66,13 +75,13 @@ describe('Seedtag Adapter', function() { }) describe('returns false', function() { describe('when params are not correct', function() { - function createSlotconfig(params) { + function createSlotConfig(params) { return getSlotConfigs({ banner: {} }, params) } it('does not have the PublisherToken.', function() { const isBidRequestValid = spec.isBidRequestValid( - createSlotconfig({ - adUnitId: '000000', + createSlotConfig({ + adUnitId: ADUNIT_ID, placement: 'banner' }) ) @@ -80,8 +89,8 @@ describe('Seedtag Adapter', function() { }) it('does not have the AdUnitId.', function() { const isBidRequestValid = spec.isBidRequestValid( - createSlotconfig({ - publisherId: '0000-0000-01', + createSlotConfig({ + publisherId: PUBLISHER_ID, placement: 'banner' }) ) @@ -89,18 +98,18 @@ describe('Seedtag Adapter', function() { }) it('does not have the placement.', function() { const isBidRequestValid = spec.isBidRequestValid( - createSlotconfig({ - publisherId: '0000-0000-01', - adUnitId: '000000' + createSlotConfig({ + publisherId: PUBLISHER_ID, + adUnitId: ADUNIT_ID }) ) expect(isBidRequestValid).to.equal(false) }) it('does not have a the correct placement.', function() { const isBidRequestValid = spec.isBidRequestValid( - createSlotconfig({ - publisherId: '0000-0000-01', - adUnitId: '000000', + createSlotConfig({ + publisherId: PUBLISHER_ID, + adUnitId: ADUNIT_ID, placement: 'another_thing' }) ) @@ -117,19 +126,19 @@ describe('Seedtag Adapter', function() { } it('is a void object', function() { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotconfig({ video: {} }) + createVideoSlotConfig({ video: {} }) ) expect(isBidRequestValid).to.equal(false) }) it('does not have playerSize.', function() { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotconfig({ video: { context: 'instream' } }) + createVideoSlotConfig({ video: { context: 'instream' } }) ) expect(isBidRequestValid).to.equal(false) }) it('is not instream ', function() { const isBidRequestValid = spec.isBidRequestValid( - createVideoSlotconfig({ + createVideoSlotConfig({ video: { context: 'outstream', playerSize: [[600, 200]] @@ -138,6 +147,20 @@ describe('Seedtag Adapter', function() { ) expect(isBidRequestValid).to.equal(false) }) + describe('order does not matter', function() { + it('when video is not the first slot', function() { + const isBidRequestValid = spec.isBidRequestValid( + createVideoSlotConfig({ banner: {}, video: {} }) + ) + expect(isBidRequestValid).to.equal(false) + }) + it('when video is the first slot', function() { + const isBidRequestValid = spec.isBidRequestValid( + createVideoSlotConfig({ video: {}, banner: {} }) + ) + expect(isBidRequestValid).to.equal(false) + }) + }) }) }) }) @@ -148,8 +171,8 @@ describe('Seedtag Adapter', function() { timeout: 1000 } const mandatoryParams = { - publisherId: '0000-0000-01', - adUnitId: '000000', + publisherId: PUBLISHER_ID, + adUnitId: ADUNIT_ID, placement: 'banner' } const inStreamParams = Object.assign({}, mandatoryParams, { diff --git a/test/spec/modules/sigmoidAnalyticsAdapter_spec.js b/test/spec/modules/sigmoidAnalyticsAdapter_spec.js index 75afb0ed86e..854c3a8e22d 100644 --- a/test/spec/modules/sigmoidAnalyticsAdapter_spec.js +++ b/test/spec/modules/sigmoidAnalyticsAdapter_spec.js @@ -38,7 +38,7 @@ describe('sigmoid Prebid Analytic', function () { events.emit(constants.EVENTS.BID_RESPONSE, {}); events.emit(constants.EVENTS.BID_WON, {}); - sinon.assert.callCount(sigmoidAnalytic.track, 5); + sinon.assert.callCount(sigmoidAnalytic.track, 7); }); }); describe('build utm tag data', function () { diff --git a/test/spec/modules/sizeMappingV2_spec.js b/test/spec/modules/sizeMappingV2_spec.js index cbfc02752a8..77e17ef360f 100644 --- a/test/spec/modules/sizeMappingV2_spec.js +++ b/test/spec/modules/sizeMappingV2_spec.js @@ -235,7 +235,7 @@ describe('sizeMappingV2', function () { adUnitSetupChecks.validateBannerMediaType.restore(); }); - it('should delete banner mediaType if it does not constain sizes or sizeConfig property', function () { + it('should delete banner mediaType if it does not contain sizes or sizeConfig property', function () { let adUnits = utils.deepClone(AD_UNITS); delete adUnits[0].mediaTypes.banner.sizeConfig; @@ -255,7 +255,7 @@ describe('sizeMappingV2', function () { checkAdUnitSetupHook(adUnits); sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, 'Detected a mediaTypes.banner object did not include required property sizes or sizeConfig. Removing invalid mediaTypes.banner object from Ad Unit.'); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: 'mediaTypes.banner' does not contain either 'sizes' or 'sizeConfig' property. Removing 'mediaTypes.banner' from ad unit.`); }); it('should call function "validateBannerMediaType" if mediaTypes.sizes is present', function () { @@ -293,7 +293,7 @@ describe('sizeMappingV2', function () { checkAdUnitSetupHook(adUnits); sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.banner.sizeConfig is NOT an Array. Removing the invalid object mediaTypes.banner from Ad Unit.`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Invalid declaration of 'sizeConfig' in 'mediaTypes.banner.sizeConfig'. Removing mediaTypes.banner from ad unit.`); }); it('should delete mediaTypes.banner object if it\'s property sizeConfig does not contain the required properties "minViewPort" and "sizes"', function () { @@ -329,7 +329,7 @@ describe('sizeMappingV2', function () { checkAdUnitSetupHook(adUnits); sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.banner.sizeConfig[2] is missing required property minViewPort or sizes or both.`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Missing required property 'minViewPort' or 'sizes' from 'mediaTypes.banner.sizeConfig[2]'. Removing mediaTypes.banner from ad unit.`); }); it('should delete mediaTypes.banner object if it\'s property sizeConfig has declared minViewPort property which is NOT an Array of two integers', function () { @@ -365,7 +365,7 @@ describe('sizeMappingV2', function () { checkAdUnitSetupHook(adUnits); sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.banner.sizeConfig[0] has property minViewPort decalared with invalid value. Please ensure minViewPort is an Array and is listed like: [700, 0]. Declaring an empty array is not allowed, instead use: [0, 0].`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Invalid declaration of 'minViewPort' in 'mediaTypes.banner.sizeConfig[0]'. Removing mediaTypes.banner from ad unit.`); }); it('should delete mediaTypes.banner object if it\'s property sizeConfig has declared sizes property which is not in the format, [[vw1, vh1], [vw2, vh2]], where vw is viewport width and vh is viewport height', function () { @@ -401,7 +401,7 @@ describe('sizeMappingV2', function () { checkAdUnitSetupHook(adUnits); sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.banner.sizeConfig[1] has propery sizes declared with invalid value. Please ensure the sizes are listed like: [[300, 250], ...] or like: [] if no sizes are present for that size bucket.`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Invalid declaration of 'sizes' in 'mediaTypes.banner.sizeConfig[1]'. Removing mediaTypes.banner from ad unit.`); }); it('should convert sizeConfig.sizes to an array of array, i.e., [360, 600] to [[360, 600]]', function () { @@ -427,6 +427,21 @@ describe('sizeMappingV2', function () { expect(validatedAdUnits[0].mediaTypes.banner.sizeConfig[0].sizes).to.deep.equal([[]]); }); + it('should log an error message if "sizes" in sizeConfig is not declared as an array', function () { + const adUnits = utils.deepClone(AD_UNITS); + const badSizeConfig = [ + { minViewPort: [0, 0], sizes: [] }, + { minViewPort: [750, 0], sizes: { 'incorrect': 'format' } }, + { minViewPort: [1200, 0], sizes: [[300, 250], [300, 600]] } + ] + adUnits[0].mediaTypes.banner.sizeConfig = badSizeConfig; + + checkAdUnitSetupHook(adUnits); + + // Assertions + sinon.assert.callCount(utils.logError, 1); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Invalid declaration of 'sizes' in 'mediaTypes.banner.sizeConfig[1]'. Removing mediaTypes.banner from ad unit.`); + }); it('should NOT delete mediaTypes.banner object if sizeConfig object is declared correctly', function () { const adUnits = utils.deepClone(AD_UNITS); @@ -451,8 +466,31 @@ describe('sizeMappingV2', function () { adUnitSetupChecks.validateVideoMediaType.restore(); }); - it('should call function "validateVideoMediaType" if mediaTypes.video.playerSize is present in the Ad Unit', function () { + it('should call function "validateVideoMediaType" if mediaTypes.video.playerSize is present in the Ad Unit (PART - 1)', function () { + // PART - 1 (Ad unit has banner.sizes defined, so, validateVideoMediaType function would be called with 'validatedBanner' as an argument) + + const adUnits = utils.deepClone(AD_UNITS); + + checkAdUnitSetupHook(adUnits); + + // since adUntis[1].mediaTypes.video has defined property "playserSize", it should call function "validateVideoMediaType" only once + sinon.assert.callCount(adUnitSetupChecks.validateVideoMediaType, 1); + /* + 'validateVideoMediaType' function should be called with 'validatedBanner' as an argument instead of the adUnit because validatedBanner is already a processed form of adUnit and is validated by banner checks. + It is not 'undefined' in this case because the adUnit[1] is using 'mediaTypes.banner.sizes' which will populate data into 'validatedBanner' variable. + + 'validatedBanner' will be idetical to adUnits[1] with the exceptions of an added property, 'sizes' on the validateBanner object itself. + */ + const validatedBanner = adUnits[1]; + validatedBanner.sizes = [[300, 250], [300, 600]]; + sinon.assert.calledWith(adUnitSetupChecks.validateVideoMediaType, validatedBanner); + }); + + it('should call function "validateVideoMediaType" if mediaTypes.video.playerSize" is present in the Ad Unit (PART - 2)', function () { + // PART - 2 (Ad unit does not have banner.sizes defined, so, validateVideoMediaType function would be called with 'adUnit' as an argument) + const adUnits = utils.deepClone(AD_UNITS); + delete adUnits[1].mediaTypes.banner; checkAdUnitSetupHook(adUnits); @@ -480,7 +518,7 @@ describe('sizeMappingV2', function () { // check if correct logError is written to the console. sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.video.sizeConfig is NOT an Array. Removing the invalid property mediaTypes.video.sizeConfig from Ad Unit.`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Invalid declaration of 'sizeConfig' in 'mediaTypes.video.sizeConfig'. Removing mediaTypes.video.sizeConfig from ad unit.`); }); it('should delete mediaTypes.video.sizeConfig property if sizeConfig does not contain the required properties "minViewPort" and "playerSize"', function () { @@ -503,7 +541,7 @@ describe('sizeMappingV2', function () { // check if correct logError is written to the console. sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.video.sizeConfig[0] is missing required property minViewPort or playerSize or both. Removing the invalid property mediaTypes.video.sizeConfig from Ad Unit.`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Missing required property 'minViewPort' or 'sizes' from 'mediaTypes.video.sizeConfig[0]'. Removing mediaTypes.video.sizeConfig from ad unit.`); }); it('should delete mediaTypes.video.sizeConfig property if sizeConfig has declared minViewPort property which is NOT an Array of two integers', function () { @@ -526,7 +564,7 @@ describe('sizeMappingV2', function () { // check if correct logError is written to the console. sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.video.sizeConfig[1] has property minViewPort decalared with invalid value. Please ensure minViewPort is an Array and is listed like: [700, 0]. Declaring an empty array is not allowed, instead use: [0, 0].`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Invalid declaration of 'minViewPort' in 'mediaTypes.video.sizeConfig[1]'. Removing mediaTypes.video.sizeConfig from ad unit.`); }); it('should delete mediaTypes.video.sizeConfig property if sizeConfig has declared "playerSize" property which is not in the format, [[vw1, vh1]], where vw is viewport width and vh is viewport height', function () { @@ -549,7 +587,7 @@ describe('sizeMappingV2', function () { // check if correct logError is written to the console. sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.video.sizeConfig[0] has propery playerSize declared with invalid value. Please ensure the playerSize is listed like: [640, 480] or like: [] if no playerSize is present for that size bucket.`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Invalid declaration of 'playerSize' in 'mediaTypes.video.sizeConfig[0]'. Removing mediaTypes.video.sizeConfig from ad unit.`); }); it('should convert sizeConfig.playerSize to an array of array, i.e., [360, 600] to [[360, 600]]', function () { @@ -602,9 +640,74 @@ describe('sizeMappingV2', function () { it('should call function "validateNativeMediaTypes" if mediaTypes.native is defined', function () { const adUnits = utils.deepClone(AD_UNITS); checkAdUnitSetupHook(adUnits); + sinon.assert.callCount(adUnitSetupChecks.validateNativeMediaType, 1); }); + it('should call function "validateNativeMediaTypes" if mediaTypes.native is defined (PART - 1)', function () { + // PART - 1 (Ad unit contains 'banner', 'video' and 'native' media types) + const adUnit = [{ + code: 'ad-unit-1', + mediaTypes: { + banner: { + sizes: [[300, 400]] + }, + video: { + playerSize: [[600, 400]] + }, + native: {} + }, + bids: [] + }]; + + checkAdUnitSetupHook(adUnit); + + // 'validatedVideo' should be passed as an argument to "validatedNativeMediaType" + const validatedVideo = adUnit[0]; + validatedVideo.sizes = [[600, 400]]; + sinon.assert.callCount(adUnitSetupChecks.validateNativeMediaType, 1); + sinon.assert.calledWith(adUnitSetupChecks.validateNativeMediaType, validatedVideo); + }); + + it('should call function "validateNativeMediaTypes" if mediaTypes.native is defined (PART - 2)', function () { + // PART - 2 (Ad unit contains only 'banner' and 'native' media types) + const adUnit = [{ + code: 'ad-unit-1', + mediaTypes: { + banner: { + sizes: [[300, 400]] + }, + native: {} + }, + bids: [] + }]; + + checkAdUnitSetupHook(adUnit); + + // 'validatedBanner' should be passed as an argument to "validatedNativeMediaType" + const validatedBanner = adUnit[0]; + validatedBanner.sizes = [[300, 400]]; + sinon.assert.callCount(adUnitSetupChecks.validateNativeMediaType, 1); + sinon.assert.calledWith(adUnitSetupChecks.validateNativeMediaType, validatedBanner); + }); + + it('should call function "validateNativeMediaTypes" if mediaTypes.native is defined (PART - 3)', function () { + // PART - 2 (Ad unit contains only 'native' media types) + const adUnit = [{ + code: 'ad-unit-1', + mediaTypes: { + native: {} + }, + bids: [] + }]; + + checkAdUnitSetupHook(adUnit); + + // 'adUnit[0]' should be passed as an argument to "validatedNativeMediaType" + sinon.assert.callCount(adUnitSetupChecks.validateNativeMediaType, 1); + sinon.assert.calledWith(adUnitSetupChecks.validateNativeMediaType, adUnit[0]); + }); + it('should delete mediaTypes.native.sizeConfig property if sizeConfig does not contain the required properties "minViewPort" and "active"', function () { const adUnits = utils.deepClone(AD_UNITS); // badSizeConfig[1] doesn't include required property "active" @@ -618,7 +721,7 @@ describe('sizeMappingV2', function () { const validatedAdUnits = checkAdUnitSetupHook(adUnits); expect(validatedAdUnits[0].mediaTypes.native).to.not.have.property('sizeConfig'); sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.native.sizeConfig is missing required property minViewPort or active or both. Removing the invalid property mediaTypes.native.sizeConfig from Ad Unit.`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Missing required property 'minViewPort' or 'sizes' from 'mediaTypes.native.sizeConfig[1]'. Removing mediaTypes.native.sizeConfig from ad unit.`); }); it('should delete mediaTypes.native.sizeConfig property if sizeConfig[].minViewPort is NOT an array of TWO integers', function () { @@ -634,7 +737,7 @@ describe('sizeMappingV2', function () { const validatedAdUnits = checkAdUnitSetupHook(adUnits); expect(validatedAdUnits[0].mediaTypes.native).to.not.have.property('sizeConfig'); sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.native.sizeConfig has properties minViewPort or active decalared with invalid values. Removing the invalid property mediaTypes.native.sizeConfig from Ad Unit.`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Invalid declaration of 'minViewPort' in 'mediaTypes.native.sizeConfig[0]'. Removing mediaTypes.native.sizeConfig from ad unit.`); }); it('should delete mediaTypes.native.sizeConfig property if sizeConfig[].active is NOT a Boolean', function () { @@ -651,7 +754,7 @@ describe('sizeMappingV2', function () { const validatedAdUnits = checkAdUnitSetupHook(adUnits); expect(validatedAdUnits[0].mediaTypes.native).to.not.have.property('sizeConfig'); sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Ad Unit: div-gpt-ad-1460505748561-0: mediaTypes.native.sizeConfig has properties minViewPort or active decalared with invalid values. Removing the invalid property mediaTypes.native.sizeConfig from Ad Unit.`); + sinon.assert.calledWith(utils.logError, `Ad unit div-gpt-ad-1460505748561-0: Invalid declaration of 'active' in 'mediaTypes.native.sizeConfig[0]'. Removing mediaTypes.native.sizeConfig from ad unit.`); }); it('should NOT delete mediaTypes.native.sizeConfig property if sizeConfig property is declared correctly', function () { @@ -722,10 +825,15 @@ describe('sizeMappingV2', function () { { minViewPort: [1600, 0], relevantMediaTypes: ['native', 'video'] } ]; + // relevantMediaTypes can only include one or more of these values: 'none', 'banner', 'video', 'native' + const sizeConfig_5 = [ + { minViewPort: [0, 0], relevantMediaTypes: ['wrong'] } + ] expect(checkBidderSizeConfigFormat(sizeConfig_1)).to.equal(false); expect(checkBidderSizeConfigFormat(sizeConfig_2)).to.equal(false); expect(checkBidderSizeConfigFormat(sizeConfig_3)).to.equal(false); expect(checkBidderSizeConfigFormat(sizeConfig_4)).to.equal(false); + expect(checkBidderSizeConfigFormat(sizeConfig_5)).to.equal(false); }); it('should return "true" if the sizeConfig object is being configured properly at the Bidder level', function () { @@ -738,11 +846,12 @@ describe('sizeMappingV2', function () { }); }); - describe('isLabelActivated(bidOrAdUnit, activeLabels, adUnitCode)', function () { + describe('isLabelActivated(bidOrAdUnit, activeLabels, adUnitCode, adUnitInstance)', function () { const labelAny = ['mobile', 'tablet']; const labelAll = ['mobile', 'tablet', 'desktop', 'HD-Tv']; const activeLabels = ['mobile', 'tablet', 'desktop']; const adUnitCode = 'div-gpt-ad-1460505748561-0'; + const adUnitInstance = 1; beforeEach(function () { sinon.spy(utils, 'logWarn'); @@ -757,10 +866,10 @@ describe('sizeMappingV2', function () { adUnits.labelAny = labelAny; adUnits.labelAll = labelAll; - isLabelActivated(adUnits, activeLabels, adUnitCode); + isLabelActivated(adUnits, activeLabels, adUnitCode, adUnitInstance); sinon.assert.callCount(utils.logWarn, 1); - sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0 => Ad unit has multiple label operators. Using the first declared operator: labelAny`); + sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0(1) => Ad unit has multiple label operators. Using the first declared operator: labelAny`); }); it('should throw a warning message if both the label operator, "labelAny"/"labelAll" are configured for an Bidder', function () { @@ -769,10 +878,10 @@ describe('sizeMappingV2', function () { adUnits.bids[0].labelAny = labelAny; adUnits.bids[0].labelAll = labelAll; - isLabelActivated(adUnits.bids[0], activeLabels, adUnitCode); + isLabelActivated(adUnits.bids[0], activeLabels, adUnitCode, adUnitInstance); sinon.assert.callCount(utils.logWarn, 1); - sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0, Bidder: appnexus => Bidder has multiple label operators. Using the first declared operator: labelAny`); + sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0(1), Bidder: appnexus => Bidder has multiple label operators. Using the first declared operator: labelAny`); }); it('should give priority to the label operator declared first incase two label operators are found on the same Ad Unit or Bidder', function () { @@ -783,7 +892,7 @@ describe('sizeMappingV2', function () { // activeAdUnit should be "false" // 'labelAll' -> ['mobile', 'tablet', 'desktop', 'HD-Tv'] will be given priority since it's declared before 'labelAny' // since, activeLabels -> ['mobile', 'tablet', 'desktop'], doesn't include 'HD-Tv', 'isLabelActivated' function should return "false" - const activeAdUnit = isLabelActivated(adUnits, activeLabels, adUnitCode); + const activeAdUnit = isLabelActivated(adUnits, activeLabels, adUnitCode, adUnitInstance); expect(activeAdUnit).to.equal(false); // bidder level check @@ -793,7 +902,7 @@ describe('sizeMappingV2', function () { // activeBidder should be "true" // 'labelAny' -> ['mobile', 'tablet'] will be given priority since it's declared before 'labelAll' // since, activeLabels -> ['mobile', 'tablet', 'desktop'] and matches atleast one element in labelAny array, so, it'll return true - const activeBidder = isLabelActivated(adUnits.bids[0], activeLabels, adUnitCode); + const activeBidder = isLabelActivated(adUnits.bids[0], activeLabels, adUnitCode, adUnitInstance); expect(activeBidder).to.equal(true); }); @@ -802,16 +911,16 @@ describe('sizeMappingV2', function () { adUnit.labelAll = []; // adUnit level check - isLabelActivated(adUnit, activeLabels, adUnitCode); + isLabelActivated(adUnit, activeLabels, adUnitCode, adUnitInstance); sinon.assert.callCount(utils.logWarn, 1); - sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0 => Ad unit has declared property 'labelAll' with an empty array. Ad Unit is still enabled!`); + sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0(1) => Ad unit has declared property 'labelAll' with an empty array.`); // bidder level check - isLabelActivated(adUnit.bids[0], activeLabels, adUnitCode); + isLabelActivated(adUnit.bids[0], activeLabels, adUnitCode, adUnitInstance); sinon.assert.callCount(utils.logWarn, 1); - sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0 => Ad unit has declared property 'labelAll' with an empty array. Ad Unit is still enabled!`); + sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0(1) => Ad unit has declared property 'labelAll' with an empty array.`); }); it('should throw a warning log message if "labelAny" operator is declared as an empty array', function () { @@ -819,26 +928,26 @@ describe('sizeMappingV2', function () { adUnit.labelAny = []; // adUnit level check - isLabelActivated(adUnit, activeLabels, adUnitCode); + isLabelActivated(adUnit, activeLabels, adUnitCode, adUnitInstance); sinon.assert.callCount(utils.logWarn, 1); - sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0 => Ad unit has declared property 'labelAny' with an empty array. Ad Unit is still enabled!`); + sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0(1) => Ad unit has declared property 'labelAny' with an empty array.`); // bidder level check - isLabelActivated(adUnit.bids[0], activeLabels, adUnitCode); + isLabelActivated(adUnit.bids[0], activeLabels, adUnitCode, adUnitInstance); sinon.assert.callCount(utils.logWarn, 1); - sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0 => Ad unit has declared property 'labelAny' with an empty array. Ad Unit is still enabled!`); + sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-0(1) => Ad unit has declared property 'labelAny' with an empty array.`); }); it('should return "true" if label operators are not present on the Ad Unit or Bidder', function () { const [adUnit] = utils.deepClone(AD_UNITS); // adUnit level check - const activeAdUnit = isLabelActivated(adUnit, activeLabels, adUnitCode); + const activeAdUnit = isLabelActivated(adUnit, activeLabels, adUnitCode, adUnitInstance); expect(activeAdUnit).to.equal(true); // bidder level check - const activeBidder = isLabelActivated(adUnit.bids[0], activeLabels, adUnitCode); + const activeBidder = isLabelActivated(adUnit.bids[0], activeLabels, adUnitCode, adUnitInstance); expect(activeBidder).to.equal(true); }); @@ -851,13 +960,13 @@ describe('sizeMappingV2', function () { // const labelAll = ['mobile', 'tablet', 'desktop', 'HD-Tv']; // const activeLabels = ['mobile', 'tablet', 'desktop']; - const activeAdUnit = isLabelActivated(adUnit, activeLabels, adUnitCode); + const activeAdUnit = isLabelActivated(adUnit, activeLabels, adUnitCode, adUnitInstance); expect(activeAdUnit).to.equal(false) // bidder level checks adUnit.bids[0].labelAll = labelAll; - const activeBidder = isLabelActivated(adUnit.bids[0], activeLabels, adUnitCode); + const activeBidder = isLabelActivated(adUnit.bids[0], activeLabels, adUnitCode, adUnitInstance); expect(activeBidder).to.equal(false); }); @@ -870,15 +979,47 @@ describe('sizeMappingV2', function () { // const labelAny = ['mobile', 'tablet']; // const activeLabels = ['mobile', 'tablet', 'desktop']; - const activeAdUnit = isLabelActivated(adUnit, activeLabels, adUnitCode); + const activeAdUnit = isLabelActivated(adUnit, activeLabels, adUnitCode, adUnitInstance); expect(activeAdUnit).to.equal(true) // bidder level checks adUnit.bids[0].labelAny = labelAny; - const activeBidder = isLabelActivated(adUnit.bids[0], activeLabels, adUnitCode); + const activeBidder = isLabelActivated(adUnit.bids[0], activeLabels, adUnitCode, adUnitInstance); expect(activeBidder).to.equal(true); }); + + it('should throw a warning message if labelAny/labelAll operator found on adunit/bidder when "label" is not passed to pbjs.requestBids', function () { + const adUnit = { + code: 'ad-unit-1', + mediaTypes: { + banner: { + sizeConfig: [{ minViewPort: [0, 0], sizes: [[300, 300], [400, 400]] }] + } + }, + labelAny: ['mobile'], + bids: [{ + bidder: 'appnexus', + params: 27, + labelAll: ['tablet', 'desktop'] + }] + } + const labels = undefined; + + // adUnit level check + isLabelActivated(adUnit, labels, adUnit.code, adUnitInstance); + + sinon.assert.callCount(utils.logWarn, 1); + sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: ad-unit-1(1) => Found 'labelAny' on ad unit, but 'labels' is not set. Did you pass 'labels' to pbjs.requestBids() ?`); + utils.logWarn.restore(); + + sinon.spy(utils, 'logWarn'); + + // bidder level check + isLabelActivated(adUnit.bids[0], labels, adUnit.code, adUnitInstance); + sinon.assert.callCount(utils.logWarn, 1); + sinon.assert.calledWith(utils.logWarn, `Size Mapping V2:: Ad Unit: ad-unit-1(1), Bidder: appnexus => Found 'labelAll' on bidder, but 'labels' is not set. Did you pass 'labels' to pbjs.requestBids() ?`); + }); }); describe('isSizeConfigActivated(mediaType, sizeConfig)', function () { @@ -998,7 +1139,7 @@ describe('sizeMappingV2', function () { }); }); - describe('getAdUnitDetail(auctionId, adUnit)', function () { + describe('getAdUnitDetail(auctionId, adUnit, labels)', function () { const adUnitDetailFixture_1 = { adUnitCode: 'div-gpt-ad-1460505748561-0', mediaTypes: { @@ -1052,7 +1193,10 @@ describe('sizeMappingV2', function () { }, sizeBucketToSizeMap: {}, activeViewport: {}, - transformedMediaTypes: {} + transformedMediaTypes: {}, + cacheHits: 0, + instance: 1, + isLabelActivated: true, }; const adUnitDetailFixture_2 = { adUnitCode: 'div-gpt-ad-1460505748561-1', @@ -1067,6 +1211,9 @@ describe('sizeMappingV2', function () { }, sizeBucketToSizeMap: {}, activeViewport: {}, + cacheHits: 0, + instance: 1, + isLabelActivated: true, transformedMediaTypes: { banner: {}, video: {} } } // adunit with same code at adUnitDetailFixture_1 but differnet mediaTypes object @@ -1082,8 +1229,12 @@ describe('sizeMappingV2', function () { }, sizeBucketToSizeMap: {}, activeViewport: {}, - transformedMediaTypes: {} + transformedMediaTypes: {}, + cacheHits: 0, + instance: 1, + isLabelActivated: true, } + const labels = ['mobile']; beforeEach(function () { sinon .stub(sizeMappingInternalStore, 'getAuctionDetail') @@ -1121,14 +1272,15 @@ describe('sizeMappingV2', function () { it('should return adUnit detail object from "sizeMappingInternalStore" if adUnit is already present in the store', function () { const [adUnit] = utils.deepClone(AD_UNITS); - const adUnitDetail = getAdUnitDetail('a1b2c3', adUnit); + const adUnitDetail = getAdUnitDetail('a1b2c3', adUnit, labels); sinon.assert.callCount(sizeMappingInternalStore.getAuctionDetail, 1); sinon.assert.callCount(utils.deepEqual, 1); sinon.assert.callCount(internal.getFilteredMediaTypes, 0); + expect(adUnitDetail.cacheHits).to.equal(1); expect(adUnitDetail).to.deep.equal(adUnitDetailFixture_1); }); - it('should NOT return adunit detail object from "sizeMappingInternalStore" if adUnit with the SAME CODE BUT DIFFERENT MEDIATYPES OBJECT is present in the store', function() { + it('should NOT return adunit detail object from "sizeMappingInternalStore" if adUnit with the SAME CODE BUT DIFFERENT MEDIATYPES OBJECT is present in the store', function () { const [adUnit] = utils.deepClone(AD_UNITS); adUnit.mediaTypes = { banner: { @@ -1138,7 +1290,7 @@ describe('sizeMappingV2', function () { ] } }; - const adUnitDetail = getAdUnitDetail('a1b2c3', adUnit); + const adUnitDetail = getAdUnitDetail('a1b2c3', adUnit, labels); sinon.assert.callCount(sizeMappingInternalStore.getAuctionDetail, 1); sinon.assert.callCount(utils.deepEqual, 1); expect(adUnitDetail).to.not.deep.equal(adUnitDetailFixture_1); @@ -1147,7 +1299,7 @@ describe('sizeMappingV2', function () { it('should store value in "sizeMappingInterStore" object if adUnit is NOT preset in this object', function () { const [, adUnit] = utils.deepClone(AD_UNITS); - const adUnitDetail = getAdUnitDetail('a1b2c3', adUnit); + const adUnitDetail = getAdUnitDetail('a1b2c3', adUnit, labels); sinon.assert.callCount(sizeMappingInternalStore.setAuctionDetail, 1); sinon.assert.callCount(internal.getFilteredMediaTypes, 1); expect(adUnitDetail).to.deep.equal(adUnitDetailFixture_2); @@ -1155,41 +1307,45 @@ describe('sizeMappingV2', function () { it('should log info message to show the details for activeSizeBucket', function () { const [, adUnit] = utils.deepClone(AD_UNITS); - getAdUnitDetail('a1b2c3', adUnit); + getAdUnitDetail('a1b2c3', adUnit, labels); sinon.assert.callCount(utils.logInfo, 1); - sinon.assert.calledWith(utils.logInfo, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-1 => Active size buckets after filtration: `, adUnitDetailFixture_2.sizeBucketToSizeMap); + sinon.assert.calledWith(utils.logInfo, `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-1(1) => Active size buckets after filtration: `, adUnitDetailFixture_2.sizeBucketToSizeMap); }); - it('should log info message if any of the mediaTypes defined in adUnit.mediaTypes got filtered out', function () { - const [, adUnit] = utils.deepClone(AD_UNITS); - - internal.getFilteredMediaTypes.restore(); - - const adUnitDetailFixture = { - adUnitCode: 'div-gpt-ad-1460505748561-1', + it('should increment "instance" count if presence of "Identical ad units" is detected', function () { + const adUnit = { + code: 'div-gpt-ad-1460505748561-0', mediaTypes: { banner: { - sizes: [[300, 250], [300, 600]] - }, - video: { - context: 'instream', - playerSize: [300, 460] + sizeConfig: [{ minViewPort: [0, 0], sizes: [[300, 300]] }] } }, - sizeBucketToSizeMap: {}, - activeViewport: {}, - transformedMediaTypes: { banner: {} } - } + bids: [{ + bidder: 'appnexus', + params: 12 + }] + }; - sinon - .stub(internal, 'getFilteredMediaTypes') - .withArgs(adUnitDetailFixture.mediaTypes) - .returns(adUnitDetailFixture); + internal.getFilteredMediaTypes.restore(); - getAdUnitDetail('a1b2c3', adUnit); + sinon.stub(internal, 'getFilteredMediaTypes') + .withArgs(adUnit.mediaTypes) + .returns({ mediaTypes: {}, sizeBucketToSizeMap: {}, activeViewPort: [], transformedMediaTypes: {} }); - sinon.assert.callCount(utils.logInfo, 2); - sinon.assert.calledWith(utils.logInfo.getCall(1), `Size Mapping V2:: Ad Unit: div-gpt-ad-1460505748561-1 => Media types that got filtered out: video`); + const adUnitDetail = getAdUnitDetail('a1b2c3', adUnit, labels); + sinon.assert.callCount(sizeMappingInternalStore.setAuctionDetail, 1); + sinon.assert.callCount(internal.getFilteredMediaTypes, 1); + expect(adUnitDetail.instance).to.equal(2); + }); + + it('should not execute "getFilteredMediaTypes" function if label is not activated on the ad unit', function () { + const [adUnit] = utils.deepClone(AD_UNITS); + adUnit.labelAny = ['tablet']; + getAdUnitDetail('a1b2c3', adUnit, labels); + + // assertions + sinon.assert.callCount(internal.getFilteredMediaTypes, 0); + sinon.assert.callCount(utils.logInfo, 0); }); }); @@ -1370,12 +1526,15 @@ describe('sizeMappingV2', function () { ], sizes: [[300, 200], [400, 600]] } - } + }, + isLabelActivated: true, + instance: 1, + cacheHits: 0 }; beforeEach(function () { sinon .stub(internal, 'getAdUnitDetail') - .withArgs('6d51e2d7-1447-4242-b6af-aaa5525a2c6e', basic_AdUnit[0]) + .withArgs('6d51e2d7-1447-4242-b6af-aaa5525a2c6e', basic_AdUnit[0], []) .returns(adUnitDetailFixture); sinon.spy(internal, 'getRelevantMediaTypesForBidder'); @@ -1456,7 +1615,10 @@ describe('sizeMappingV2', function () { } }, activeViewport: [560, 260], - transformedMediaTypes: {} + transformedMediaTypes: {}, + isLabelActivated: true, + instance: 1, + cacheHits: 0 }; sinon @@ -1474,7 +1636,7 @@ describe('sizeMappingV2', function () { }); expect(bidRequests[0]).to.be.undefined; sinon.assert.callCount(utils.logInfo, 1); - sinon.assert.calledWith(utils.logInfo, `Size Mapping V2:: Ad Unit: adUnit1 => Ad unit disabled since there are no active media types after sizeConfig filtration.`); + sinon.assert.calledWith(utils.logInfo, `Size Mapping V2:: Ad Unit: adUnit1(1) => Ad unit disabled since there are no active media types after sizeConfig filtration.`); }); it('should throw an error if bidder level sizeConfig is not configured properly', function () { @@ -1502,7 +1664,7 @@ describe('sizeMappingV2', function () { expect(bidRequests[0]).to.not.be.undefined; sinon.assert.callCount(utils.logError, 1); - sinon.assert.calledWith(utils.logError, `Size Mapping V2:: Ad Unit: adUnit1, Bidder: rubicon => 'sizeConfig' is not configured properly. This bidder won't be eligible for sizeConfig checks and will remail active.`); + sinon.assert.calledWith(utils.logError, `Size Mapping V2:: Ad Unit: adUnit1(1), Bidder: rubicon => 'sizeConfig' is not configured properly. This bidder won't be eligible for sizeConfig checks and will remail active.`); }); it('should ensure bidder relevantMediaTypes is a subset of active media types at the ad unit level', function () { @@ -1585,12 +1747,15 @@ describe('sizeMappingV2', function () { activeViewport: [560, 260], transformedMediaTypes: { native: {} - } + }, + isLabelActivated: true, + instance: 1, + cacheHits: 0 }; sinon .stub(internal, 'getAdUnitDetail') - .withArgs('6d51e2d7-1447-4242-b6af-aaa5525a2c6e', adUnit[0]) + .withArgs('6d51e2d7-1447-4242-b6af-aaa5525a2c6e', adUnit[0], []) .returns(adUnitDetailFixture); const bidRequests = getBids({ @@ -1603,7 +1768,7 @@ describe('sizeMappingV2', function () { }); expect(bidRequests[0]).to.be.undefined; sinon.assert.callCount(utils.logInfo, 1); - sinon.assert.calledWith(utils.logInfo, `Size Mapping V2:: Ad Unit: adUnit1, Bidder: rubicon => 'relevantMediaTypes' does not match with any of the active mediaTypes at the Ad Unit level. This bidder is disabled.`); + sinon.assert.calledWith(utils.logInfo, `Size Mapping V2:: Ad Unit: adUnit1(1), Bidder: rubicon => 'relevantMediaTypes' does not match with any of the active mediaTypes at the Ad Unit level. This bidder is disabled.`); }); it('should throw a warning if mediaTypes object is not correctly formatted', function () { @@ -1626,10 +1791,13 @@ describe('sizeMappingV2', function () { }); it('should log a message if ad unit is disabled due to a failing label check', function () { + internal.getAdUnitDetail.restore(); + const adUnitDetail = Object.assign({}, adUnitDetailFixture); + adUnitDetail.isLabelActivated = false; sinon - .stub(internal, 'isLabelActivated') - .onFirstCall() - .returns(false); + .stub(internal, 'getAdUnitDetail') + .withArgs('6d51e2d7-1447-4242-b6af-aaa5525a2c6e', basic_AdUnit[0], []) + .returns(adUnitDetail); getBids({ bidderCode: 'appnexus', @@ -1641,15 +1809,11 @@ describe('sizeMappingV2', function () { }); sinon.assert.callCount(utils.logInfo, 1); - sinon.assert.calledWith(utils.logInfo, `Size Mapping V2:: Ad Unit: adUnit1 => Ad unit is disabled due to failing label check.`); - - internal.isLabelActivated.restore(); + sinon.assert.calledWith(utils.logInfo, `Size Mapping V2:: Ad Unit: adUnit1(1) => Ad unit is disabled due to failing label check.`); }); it('should log a message if bidder is disabled due to a failing label check', function () { - const stub = sinon.stub(internal, 'isLabelActivated') - stub.onFirstCall().returns(true); - stub.onSecondCall().returns(false); + const stub = sinon.stub(internal, 'isLabelActivated').returns(false); getBids({ bidderCode: 'appnexus', @@ -1661,7 +1825,7 @@ describe('sizeMappingV2', function () { }); sinon.assert.callCount(utils.logInfo, 1); - sinon.assert.calledWith(utils.logInfo, `Size Mapping V2:: Ad Unit: adUnit1, Bidder: appnexus => Label check for this bidder has failed. This bidder is disabled.`); + sinon.assert.calledWith(utils.logInfo, `Size Mapping V2:: Ad Unit: adUnit1(1), Bidder: appnexus => Label check for this bidder has failed. This bidder is disabled.`); internal.isLabelActivated.restore(); }) diff --git a/test/spec/modules/smaatoBidAdapter_spec.js b/test/spec/modules/smaatoBidAdapter_spec.js new file mode 100644 index 00000000000..13716b51436 --- /dev/null +++ b/test/spec/modules/smaatoBidAdapter_spec.js @@ -0,0 +1,562 @@ +import { spec } from 'modules/smaatoBidAdapter.js'; +import * as utils from 'src/utils.js'; +import {config} from 'src/config.js'; + +const imageAd = { + image: { + img: { + url: 'https://prebid/static/ad.jpg', + w: 320, + h: 50, + ctaurl: 'https://prebid/track/ctaurl' + }, + impressiontrackers: [ + 'https://prebid/track/imp/1', + 'https://prebid/track/imp/2' + ], + clicktrackers: [ + 'https://prebid/track/click/1' + ] + } +}; + +const richmediaAd = { + richmedia: { + mediadata: { + content: '

RICHMEDIA CONTENT

', + w: 800, + h: 600 + }, + impressiontrackers: [ + 'https://prebid/track/imp/1', + 'https://prebid/track/imp/2' + ], + clicktrackers: [ + 'https://prebid/track/click/1' + ] + } +}; + +const ADTYPE_IMG = 'Img'; +const ADTYPE_RICHMEDIA = 'Richmedia'; +const ADTYPE_VIDEO = 'Video'; + +const context = { + keywords: 'power tools,drills' +}; + +const user = { + keywords: 'a,b', + gender: 'M', + yob: 1984 +}; + +const openRtbBidResponse = (adType) => { + let adm = ''; + + switch (adType) { + case ADTYPE_IMG: + adm = JSON.stringify(imageAd); + break; + case ADTYPE_RICHMEDIA: + adm = JSON.stringify(richmediaAd); + break; + case ADTYPE_VIDEO: + adm = ''; + break; + default: + throw Error('Invalid AdType'); + } + + let resp = { + body: { + bidid: '04db8629-179d-4bcd-acce-e54722969006', + cur: 'USD', + ext: {}, + id: '5ebea288-f13a-4754-be6d-4ade66c68877', + seatbid: [ + { + bid: [ + { + 'adm': adm, + 'adomain': [ + 'smaato.com' + ], + 'bidderName': 'smaato', + 'cid': 'CM6523', + 'crid': 'CR69381', + 'dealid': '12345', + 'id': '6906aae8-7f74-4edd-9a4f-f49379a3cadd', + 'impid': '226416e6e6bf41', + 'iurl': 'https://prebid/iurl', + 'nurl': 'https://prebid/nurl', + 'price': 0.01, + 'w': 350, + 'h': 50 + } + ], + seat: 'CM6523' + } + ], + }, + headers: { + get: function (header) { + if (header === 'X-SMT-ADTYPE') { + return adType; + } + } + } + }; + return resp; +}; + +const request = { + method: 'POST', + url: 'https://prebid.ad.smaato.net/oapi/prebid', + data: '' +}; + +const interpretedBidsImg = [ + { + requestId: '226416e6e6bf41', + cpm: 0.01, + width: 350, + height: 50, + ad: '
\"\"\"\"
', + ttl: 300, + creativeId: 'CR69381', + dealId: '12345', + netRevenue: true, + currency: 'USD', + meta: { + advertiserDomains: ['smaato.com'], + agencyId: 'CM6523', + networkName: 'smaato', + mediaType: 'banner' + } + } +]; + +const interpretedBidsRichmedia = [ + { + requestId: '226416e6e6bf41', + cpm: 0.01, + width: 350, + height: 50, + ad: '

RICHMEDIA CONTENT

\"\"\"\"
', + ttl: 300, + creativeId: 'CR69381', + dealId: '12345', + netRevenue: true, + currency: 'USD', + meta: { + advertiserDomains: ['smaato.com'], + agencyId: 'CM6523', + networkName: 'smaato', + mediaType: 'banner' + } + } +]; + +const interpretedBidsVideo = [ + { + requestId: '226416e6e6bf41', + cpm: 0.01, + width: 350, + height: 50, + vastXml: '', + ttl: 300, + creativeId: 'CR69381', + dealId: '12345', + netRevenue: true, + currency: 'USD', + meta: { + advertiserDomains: ['smaato.com'], + agencyId: 'CM6523', + networkName: 'smaato', + mediaType: 'video' + } + } +]; + +const defaultBidderRequest = { + gdprConsent: { + consentString: 'HFIDUYFIUYIUYWIPOI87392DSU', + gdprApplies: true + }, + uspConsent: 'uspConsentString', + refererInfo: { + referer: 'http://example.com/page.html', + }, + timeout: 1200 +}; + +const minimalBidderRequest = { + refererInfo: { + referer: 'http://example.com/page.html', + } +}; + +const singleBannerBidRequest = { + bidder: 'smaato', + params: { + publisherId: 'publisherId', + adspaceId: 'adspaceId' + }, + mediaTypes: { + banner: { + sizes: [[300, 50]] + } + }, + adUnitCode: '/19968336/header-bid-tag-0', + transactionId: 'transactionId', + sizes: [[300, 50]], + bidId: 'bidId', + bidderRequestId: 'bidderRequestId', + auctionId: 'auctionId', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0 +}; + +const singleVideoBidRequest = { + bidder: 'smaato', + params: { + publisherId: 'publisherId', + adspaceId: 'adspaceId' + }, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [[768, 1024]], + mimes: ['video\/mp4', 'video\/quicktime', 'video\/3gpp', 'video\/x-m4v'], + minduration: 5, + maxduration: 30, + startdelay: 0, + linearity: 1, + protocols: [7], + skip: 1, + skipmin: 5, + api: [7], + ext: {rewarded: 0} + } + }, + adUnitCode: '/19968336/header-bid-tag-0', + transactionId: 'transactionId', + sizes: [[300, 50]], + bidId: 'bidId', + bidderRequestId: 'bidderRequestId', + auctionId: 'auctionId', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0 +}; + +const combinedBannerAndVideoBidRequest = { + bidder: 'smaato', + params: { + publisherId: 'publisherId', + adspaceId: 'adspaceId' + }, + mediaTypes: { + banner: { + sizes: [[300, 50]] + }, + video: { + context: 'outstream', + playerSize: [[768, 1024]], + mimes: ['video\/mp4', 'video\/quicktime', 'video\/3gpp', 'video\/x-m4v'], + minduration: 5, + maxduration: 30, + startdelay: 0, + linearity: 1, + protocols: [7], + skip: 1, + skipmin: 5, + api: [7], + ext: {rewarded: 0} + } + }, + adUnitCode: '/19968336/header-bid-tag-0', + transactionId: 'transactionId', + sizes: [[300, 50]], + bidId: 'bidId', + bidderRequestId: 'bidderRequestId', + auctionId: 'auctionId', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0 +}; + +const inAppBidRequest = { + bidder: 'smaato', + params: { + publisherId: 'publisherId', + adspaceId: 'adspaceId', + app: { + ifa: 'aDeviceId', + geo: { + lat: 33.3, + lon: -88.8 + } + } + }, + mediaTypes: { + banner: { + sizes: [[300, 50]] + } + }, + adUnitCode: '/19968336/header-bid-tag-0', + transactionId: 'transactionId', + sizes: [[300, 50]], + bidId: 'bidId', + bidderRequestId: 'bidderRequestId', + auctionId: 'auctionId', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0 +}; + +describe('smaatoBidAdapterTest', () => { + describe('isBidRequestValid', () => { + it('has valid params', () => { + expect(spec.isBidRequestValid({params: {publisherId: '123', adspaceId: '456'}})).to.be.true; + expect(spec.isBidRequestValid(singleBannerBidRequest)).to.be.true; + }); + it('has invalid params', () => { + expect(spec.isBidRequestValid({})).to.be.false; + expect(spec.isBidRequestValid({params: {}})).to.be.false; + expect(spec.isBidRequestValid({params: {publisherId: '123'}})).to.be.false; + expect(spec.isBidRequestValid({params: {publisherId: '123', adspaceId: 456}})).to.be.false; + }); + }); + + describe('buildRequests', () => { + beforeEach(() => { + this.req = JSON.parse(spec.buildRequests([singleBannerBidRequest], defaultBidderRequest).data); + this.sandbox = sinon.sandbox.create(); + }); + + afterEach(() => { + this.sandbox.restore(); + }); + + it('can override endpoint', () => { + const overridenEndpoint = 'https://prebid/bidder'; + let bidRequest = utils.deepClone(singleBannerBidRequest); + utils.deepSetValue(bidRequest, 'params.endpoint', overridenEndpoint); + const actualEndpoint = spec.buildRequests([bidRequest], defaultBidderRequest).url; + expect(actualEndpoint).to.equal(overridenEndpoint); + }); + + it('sends correct imps', () => { + expect(this.req.imp).to.deep.equal([ + { + id: 'bidId', + banner: { + w: 300, + h: 50, + format: [ + { + h: 50, + w: 300 + } + ] + }, + tagid: 'adspaceId' + } + ]) + }); + + it('sends correct site', () => { + expect(this.req.site.id).to.exist.and.to.be.a('string'); + expect(this.req.site.domain).to.exist.and.to.be.a('string'); + expect(this.req.site.page).to.exist.and.to.be.a('string'); + expect(this.req.site.ref).to.equal('http://example.com/page.html'); + expect(this.req.site.publisher.id).to.equal('publisherId'); + }) + + it('sends gdpr applies if exists', () => { + expect(this.req.regs.ext.gdpr).to.equal(1); + expect(this.req.user.ext.consent).to.equal('HFIDUYFIUYIUYWIPOI87392DSU'); + }); + + it('sends no gdpr applies if no gdpr exists', () => { + let req_without_gdpr = JSON.parse(spec.buildRequests([singleBannerBidRequest], minimalBidderRequest).data); + expect(req_without_gdpr.regs.ext.gdpr).to.not.exist; + expect(req_without_gdpr.user.ext.consent).to.not.exist; + }); + + it('sends usp if exists', () => { + expect(this.req.regs.ext.us_privacy).to.equal('uspConsentString'); + }); + + it('sends tmax', () => { + expect(this.req.tmax).to.equal(1200); + }); + + it('sends no usp if no usp exists', () => { + let req_without_usp = JSON.parse(spec.buildRequests([singleBannerBidRequest], minimalBidderRequest).data); + expect(req_without_usp.regs.ext.us_privacy).to.not.exist; + }); + + it('sends fp data', () => { + this.sandbox.stub(config, 'getConfig').callsFake(key => { + const config = { + fpd: { + context, + user + } + }; + return utils.deepAccess(config, key); + }); + let bidRequest = utils.deepClone(singleBannerBidRequest); + let req_fpd = JSON.parse(spec.buildRequests([bidRequest], defaultBidderRequest).data); + expect(req_fpd.user.gender).to.equal('M'); + expect(req_fpd.user.yob).to.equal(1984); + expect(req_fpd.user.keywords).to.eql('a,b'); + expect(req_fpd.user.ext.consent).to.equal('HFIDUYFIUYIUYWIPOI87392DSU'); + expect(req_fpd.site.keywords).to.eql('power tools,drills'); + expect(req_fpd.site.publisher.id).to.equal('publisherId'); + }) + }); + + describe('buildRequests for video imps', () => { + it('sends correct video imps', () => { + let req = JSON.parse(spec.buildRequests([singleVideoBidRequest], defaultBidderRequest).data); + expect(req.imp).to.deep.equal([ + { + id: 'bidId', + video: { + mimes: ['video\/mp4', 'video\/quicktime', 'video\/3gpp', 'video\/x-m4v'], + minduration: 5, + startdelay: 0, + linearity: 1, + h: 1024, + maxduration: 30, + skip: 1, + protocols: [7], + ext: { + rewarded: 0 + }, + skipmin: 5, + api: [7], + w: 768 + }, + tagid: 'adspaceId' + } + ]) + }); + it('allows combines banner and video imp in single bid request', () => { + let req = JSON.parse(spec.buildRequests([combinedBannerAndVideoBidRequest], defaultBidderRequest).data); + expect(req.imp).to.deep.equal([ + { + id: 'bidId', + banner: { + w: 300, + h: 50, + format: [ + { + h: 50, + w: 300 + } + ] + }, + video: { + mimes: ['video\/mp4', 'video\/quicktime', 'video\/3gpp', 'video\/x-m4v'], + minduration: 5, + startdelay: 0, + linearity: 1, + h: 1024, + maxduration: 30, + skip: 1, + protocols: [7], + ext: { + rewarded: 0 + }, + skipmin: 5, + api: [7], + w: 768 + }, + tagid: 'adspaceId' + } + ]) + }); + it('allows two imps in the same bid request', () => { + let req = JSON.parse(spec.buildRequests([singleBannerBidRequest, singleBannerBidRequest], defaultBidderRequest).data); + expect(req.imp).to.have.length(2); + }); + }); + + describe('in-app requests', () => { + it('add geo and ifa info to device object', () => { + let req = JSON.parse(spec.buildRequests([inAppBidRequest], defaultBidderRequest).data); + expect(req.device.geo).to.deep.equal({'lat': 33.3, 'lon': -88.8}); + expect(req.device.ifa).to.equal('aDeviceId'); + }); + it('add only ifa to device object', () => { + let inAppBidRequestWithoutGeo = utils.deepClone(inAppBidRequest); + delete inAppBidRequestWithoutGeo.params.app.geo + let req = JSON.parse(spec.buildRequests([inAppBidRequestWithoutGeo], defaultBidderRequest).data); + + expect(req.device.geo).to.not.exist; + expect(req.device.ifa).to.equal('aDeviceId'); + }); + it('add no specific device info if param does not exist', () => { + let req = JSON.parse(spec.buildRequests([singleBannerBidRequest], defaultBidderRequest).data); + expect(req.device.geo).to.not.exist; + expect(req.device.ifa).to.not.exist; + }); + }); + + describe('interpretResponse', () => { + it('single image reponse', () => { + const bids = spec.interpretResponse(openRtbBidResponse(ADTYPE_IMG), request); + assert.deepStrictEqual(bids, interpretedBidsImg); + }); + it('single richmedia reponse', () => { + const bids = spec.interpretResponse(openRtbBidResponse(ADTYPE_RICHMEDIA), request); + assert.deepStrictEqual(bids, interpretedBidsRichmedia); + }); + it('single video reponse', () => { + const bids = spec.interpretResponse(openRtbBidResponse(ADTYPE_VIDEO), request); + assert.deepStrictEqual(bids, interpretedBidsVideo); + }); + it('ignores bid response with invalid ad type', () => { + let resp = openRtbBidResponse(ADTYPE_IMG); + resp.headers.get = (header) => { + if (header === 'X-SMT-ADTYPE') { + return undefined; + } + } + const bids = spec.interpretResponse(resp, request); + expect(bids).to.be.empty + }); + it('uses correct TTL when expire header exists', () => { + const clock = sinon.useFakeTimers(); + clock.tick(2000); + let resp = openRtbBidResponse(ADTYPE_IMG); + resp.headers.get = (header) => { + if (header === 'X-SMT-ADTYPE') { + return ADTYPE_IMG; + } + if (header === 'X-SMT-Expires') { + return 2000 + (400 * 1000); + } + } + const bids = spec.interpretResponse(resp, request); + expect(bids[0].ttl).to.equal(400); + clock.restore(); + }); + it('uses net revenue flag send from server', () => { + let resp = openRtbBidResponse(ADTYPE_IMG); + resp.body.seatbid[0].bid[0].ext = {net: false}; + const bids = spec.interpretResponse(resp, request); + expect(bids[0].netRevenue).to.equal(false); + }) + }); +}); diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js index 5e6397f1b2e..2de7cb2c9ff 100644 --- a/test/spec/modules/smartadserverBidAdapter_spec.js +++ b/test/spec/modules/smartadserverBidAdapter_spec.js @@ -42,6 +42,45 @@ describe('Smart bid adapter tests', function () { transactionId: 'zsfgzzg' }]; + var DEFAULT_PARAMS_WITH_EIDS = [{ + adUnitCode: 'sas_42', + bidId: 'abcd1234', + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [300, 200] + ] + } + }, + bidder: 'smartadserver', + params: { + domain: 'https://prg.smartadserver.com', + siteId: '1234', + pageId: '5678', + formatId: '90', + target: 'test=prebid', + bidfloor: 0.420, + buId: '7569', + appName: 'Mozilla', + ckId: 42 + }, + requestId: 'efgh5678', + transactionId: 'zsfgzzg', + userId: { + britepoolid: '1111', + criteoId: '1111', + digitrustid: { data: { id: 'DTID', keyv: 4, privacy: { optout: false }, producer: 'ABC', version: 2 } }, + id5id: { uid: '1111' }, + idl_env: '1111', + lipbid: '1111', + parrableid: 'eidVersion.encryptionKeyReference.encryptedValue', + pubcid: '1111', + tdid: '1111', + netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg', + } + }]; + // Default params without optional ones var DEFAULT_PARAMS_WO_OPTIONAL = [{ adUnitCode: 'sas_42', @@ -434,6 +473,33 @@ describe('Smart bid adapter tests', function () { }); }); + describe('External ids tests', function () { + it('Verify external ids in request and ids found', function () { + config.setConfig({ + 'currency': { + 'adServerCurrency': 'EUR' + } + }); + const request = spec.buildRequests(DEFAULT_PARAMS_WITH_EIDS); + expect(request[0]).to.have.property('url').and.to.equal('https://prg.smartadserver.com/prebid/v1'); + expect(request[0]).to.have.property('method').and.to.equal('POST'); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('eids'); + expect(requestContent.eids).to.not.equal(null).and.to.not.be.undefined; + expect(requestContent.eids.length).to.greaterThan(0); + for (let index in requestContent.eids) { + let eid = requestContent.eids[index]; + expect(eid.source).to.not.equal(null).and.to.not.be.undefined; + expect(eid.uids).to.not.equal(null).and.to.not.be.undefined; + for (let uidsIndex in eid.uids) { + let uid = eid.uids[uidsIndex]; + expect(uid.id).to.not.equal(null).and.to.not.be.undefined; + } + } + }); + }); + describe('Supply Chain Serializer tests', function () { it('Verify a multi node supply chain serialization matches iab example', function() { let schain = { diff --git a/test/spec/modules/smartxBidAdapter_spec.js b/test/spec/modules/smartxBidAdapter_spec.js new file mode 100644 index 00000000000..efc6abcc5fa --- /dev/null +++ b/test/spec/modules/smartxBidAdapter_spec.js @@ -0,0 +1,513 @@ +import { + expect +} from 'chai'; +import { + spec +} from 'modules/smartxBidAdapter.js'; + +describe('The smartx adapter', function () { + function getValidBidObject() { + return { + bidId: 123, + mediaTypes: { + video: { + // context: 'outstream', + playerSize: [ + ['640', '360'] + ] + } + }, + params: { + tagId: 'Nu68JuOWAvrbzoyrOR9a7A', + publisherId: '__name__', + siteId: '__name__', + bidfloor: 0.3, + bidfloorcur: 'EUR', + // user: { + // data: '' + // } + // outstream_options: { + // slot: 'yourelementid' + // } + } + + }; + }; + + describe('isBidRequestValid', function () { + var bid; + + beforeEach(function () { + bid = getValidBidObject(); + }); + + it('should fail validation if the bid isn\'t defined or not an object', function () { + var result = spec.isBidRequestValid(); + + expect(result).to.equal(false); + + result = spec.isBidRequestValid('not an object'); + + expect(result).to.equal(false); + }); + + it('should succeed validation with all the right parameters', function () { + expect(spec.isBidRequestValid(getValidBidObject())).to.equal(true); + }); + + it('should succeed validation with mediaType and outstream_function or outstream_options', function () { + bid.mediaType = 'video'; + bid.params.outstream_function = 'outstream_func'; + + expect(spec.isBidRequestValid(bid)).to.equal(true); + + delete bid.params.outstream_function; + bid.params.outstream_options = { + slot: 'yourelementid' + }; + + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should succeed with ad_unit outstream and outstream function set', function () { + bid.params.ad_unit = 'outstream'; + bid.params.outstream_function = function () {}; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should succeed with mediaTypes_video_context outstream, options set for outstream and slot provided', function () { + bid.mediaTypes.video.context = 'outstream'; + bid.params.outstream_options = { + slot: 'yourelementid' + }; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should fail without video', function () { + delete bid.mediaTypes.video; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail without playerSize', function () { + delete bid.mediaTypes.video.playerSize; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail without tagId', function () { + delete bid.params.tagId; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail without publisherId', function () { + delete bid.params.publisherId; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail without siteId', function () { + delete bid.params.siteId; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail without bidfloor', function () { + delete bid.params.bidfloor; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail without bidfloorcur', function () { + delete bid.params.bidfloorcur; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail with context outstream but no options set for outstream', function () { + bid.mediaTypes.video.context = 'outstream'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail with context outstream, options set for outstream but no slot provided', function () { + bid.mediaTypes.video.context = 'outstream'; + bid.params.outstream_options = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should succeed with context outstream, options set for outstream but no outstream_function is set', function () { + bid.mediaTypes.video.context = 'outstream'; + bid.params.outstream_options = { + slot: 'yourelementid' + }; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + }); + + describe('buildRequests', function () { + var bid, + bidRequestObj; + + beforeEach(function () { + bid = getValidBidObject(); + bidRequestObj = { + refererInfo: { + referer: 'prebid.js' + } + }; + }); + + it('should build a very basic request', function () { + var request = spec.buildRequests([bid], bidRequestObj)[0]; + expect(request.method).to.equal('POST'); + expect(request.url).to.equal('https://bid.sxp.smartclip.net/bid/1000'); + expect(request.bidRequest).to.equal(bidRequestObj); + expect(request.data.imp.id).to.match(/\d+/); + expect(request.data.imp.secure).to.equal(0); + + expect(request.data.imp.video).to.deep.equal({ + ext: { + sdk_name: 'Prebid 1+' + }, + h: '360', + w: '640', + mimes: [ + 'application/javascript', 'video/mp4', 'video/webm' + ], + api: [2], + delivery: [2], + linearity: 1, + maxbitrate: 3500, + maxduration: 500, + minbitrate: 0, + minduration: 0, + protocols: [ + 2, 3, 5, 6 + ], + startdelay: 0, + placement: 1, + pos: 1 + }); + + expect(request.data.site).to.deep.equal({ + content: 'content', + id: '__name__', + page: 'prebid.js', + cat: '', + domain: '', + publisher: { + id: '__name__' + } + }); + }); + + it('should change request parameters based on options sent', function () { + var request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.imp.video.ext).to.deep.equal({ + sdk_name: 'Prebid 1+' + }); + + expect(request.data.imp.video).to.contain({ + placement: 1 + }); + + bid.mediaTypes.video.context = 'outstream'; + + bid.params = { + outstream_options: { + foo: 'bar' + }, + outstream_function: '987', + mimes: 'foo', + linearity: 2, + minduration: 5, + maxduration: 10, + startdelay: 1, + minbitrate: 50, + maxbitrate: 500, + delivery: [1], + pos: 2, + api: [1], + protocols: [ + 2, 3, 5 + ], + bidfloor: 55, + bidfloorcur: 'foo', + at: 1, + cur: ['FOO'] + }; + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.imp.video.ext).to.deep.equal({ + sdk_name: 'Prebid 1+' + }); + + expect(request.data.imp.video).to.contain({ + minduration: 5, + maxduration: 10 + }); + + expect(request.data.imp.video.startdelay).to.equal(1); + + expect(request.data.imp.video).to.contain({ + placement: 3 + }); + + expect(request.data.imp.bidfloor).to.equal(55); + + expect(request.data.imp.bidfloorcur).to.equal('foo'); + + expect(request.data.imp.video.linearity).to.equal(2); + + expect(request.data.imp.video.minbitrate).to.equal(50); + + expect(request.data.imp.video.maxbitrate).to.equal(500); + }); + + it('should pass GDPR params', function () { + var request; + + bidRequestObj.gdprConsent = { + gdprApplies: true, + consentString: 'foo' + } + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.regs.ext.gdpr).to.equal(1); + expect(request.data.user.ext.consent).to.be.an('string'); + expect(request.data.user.ext.consent).to.equal('foo'); + }); + + it('should pass emq params', function () { + var request; + + bid.params.user = { + data: [{ + id: 'emq', + name: 'emq', + segment: [{ + name: 'emq', + value: 'foo' + }] + }] + } + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.user.data).to.deep.equal([{ + id: 'emq', + name: 'emq', + segment: { + name: 'emq', + value: 'foo' + } + }]); + }); + + it('should pass crumbs params', function () { + var request; + + bid.crumbs = { + pubcid: 'pubcid_1' + }; + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.user.ext).to.contain({ + fpc: 'pubcid_1' + }); + }); + + it('should pass linearity params', function () { + var request; + + bid.params.linearity = 3 + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.imp.video.linearity).to.equal(3); + }); + + it('should pass min and max duration params', function () { + var request; + + bid.params.minduration = 3 + bid.params.maxduration = 15 + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.imp.video.minduration).to.equal(3); + expect(request.data.imp.video.maxduration).to.equal(15); + }); + }); + + describe('interpretResponse', function () { + var serverResponse, bidderRequestObj; + + beforeEach(function () { + bidderRequestObj = { + bidRequest: { + bids: [{ + mediaTypes: { + video: { + playerSize: [ + ['400', '300'] + ] + } + }, + bidId: 123, + params: { + player_width: 400, + player_height: 300, + content_page_url: 'prebid.js', + ad_mute: 1, + outstream_options: { + foo: 'bar' + }, + outstream_function: 'function', + } + }, { + mediaTypes: { + video: { + playerSize: [ + ['200', '100'] + ] + } + }, + bidId: 124, + params: { + player_width: 200, + player_height: 100, + content_page_url: 'prebid.js', + ad_mute: 1, + outstream_options: { + foo: 'bar' + }, + outstream_function: 'function' + } + }] + } + }; + + serverResponse = { + body: { + id: 12345, + seatbid: [{ + bid: [{ + impid: 123, + cur: 'USD', + price: 12, + adomain: ['abc.com'], + crid: 321, + w: 400, + h: 300, + ext: { + slot: 'slot123' + } + }, { + impid: 124, + cur: 'USD', + price: 13, + adomain: ['def.com'], + crid: 654, + w: 200, + h: 100, + ext: { + slot: 'slot124' + } + }] + }] + } + }; + }); + + it('should return an array of bid responses', function () { + var responses = spec.interpretResponse(serverResponse, bidderRequestObj); + expect(responses).to.be.an('array').with.length(2); + expect(responses[0].requestId).to.equal(123); + expect(responses[0].currency).to.equal('USD'); + expect(responses[0].cpm).to.equal(12); + expect(responses[0].creativeId).to.equal(321); + expect(responses[0].ttl).to.equal(360); + expect(responses[0].netRevenue).to.equal(true); + expect(responses[0].mediaType).to.equal('video'); + expect(responses[0].width).to.equal(400); + expect(responses[0].height).to.equal(300); + expect(responses[1].requestId).to.equal(124); + expect(responses[1].currency).to.equal('USD'); + expect(responses[1].cpm).to.equal(13); + expect(responses[1].creativeId).to.equal(654); + expect(responses[1].ttl).to.equal(360); + expect(responses[1].netRevenue).to.equal(true); + expect(responses[1].mediaType).to.equal('video'); + expect(responses[1].width).to.equal(200); + expect(responses[1].height).to.equal(100); + }); + }); + + describe('oustreamRender', function () { + var serverResponse, bidderRequestObj; + + beforeEach(function () { + bidderRequestObj = { + bidRequest: { + bids: [{ + mediaTypes: { + video: { + context: 'outstream', + playerSize: [ + ['400', '300'] + ] + } + }, + bidId: 123, + params: { + player_width: 400, + player_height: 300, + content_page_url: 'prebid.js', + ad_mute: 1, + outstream_options: { + slot: 'slot123' + }, + outstream_function: 'function', + } + }] + } + }; + + serverResponse = { + body: { + id: 12345, + seatbid: [{ + bid: [{ + impid: 123, + cur: 'USD', + price: 12, + adomain: ['abc.com'], + crid: 321, + w: 400, + h: 300, + ext: { + slot: 'slot123' + } + }] + }] + } + }; + }); + + it('should attempt to insert the EASI script', function () { + var scriptTag; + sinon.stub(window.document, 'getElementById').returns({ + appendChild: sinon.stub().callsFake(function (script) { + scriptTag = script + }) + }); + var responses = spec.interpretResponse(serverResponse, bidderRequestObj); + + responses[0].renderer.render(responses[0]); + + expect(scriptTag.getAttribute('type')).to.equal('text/javascript'); + expect(scriptTag.getAttribute('src')).to.equal('https://dco.smartclip.net/?plc=7777777'); + + window.document.getElementById.restore(); + }); + }); +}) diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js index 019edd84c9f..52821072a21 100644 --- a/test/spec/modules/sonobiBidAdapter_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -303,47 +303,6 @@ describe('SonobiBidAdapter', function () { }, uspConsent: 'someCCPAString' }; - it('should include the digitrust id and keyv', () => { - window.DigiTrust = { - getUser: function () { - } - }; - let sandbox = sinon.sandbox.create(); - sandbox.stub(window.DigiTrust, 'getUser').callsFake(() => - ({ - success: true, - identity: { - id: 'Vb0YJIxTMJV4W0GHRdJ3MwyiOVYJjYEgc2QYdBSG', - keyv: 4, - version: 2, - privacy: {} - } - }) - ); - const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.data.digid).to.equal('Vb0YJIxTMJV4W0GHRdJ3MwyiOVYJjYEgc2QYdBSG'); - expect(bidRequests.data.digkeyv).to.equal(4); - sandbox.restore(); - delete window.DigiTrust; - }); - - it('should not include the digitrust id and keyv', () => { - window.DigiTrust = { - getUser: function () { - } - }; - let sandbox = sinon.sandbox.create(); - sandbox.stub(window.DigiTrust, 'getUser').callsFake(() => - ({ - success: false - }) - ); - const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.data.digid).to.be.undefined; - expect(bidRequests.data.digkeyv).to.be.undefined; - sandbox.restore(); - delete window.DigiTrust; - }); it('should return a properly formatted request', function () { const bidRequests = spec.buildRequests(bidRequest, bidderRequests) diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js index c82cc32207a..54ccff870eb 100644 --- a/test/spec/modules/sovrnBidAdapter_spec.js +++ b/test/spec/modules/sovrnBidAdapter_spec.js @@ -70,12 +70,17 @@ describe('sovrnBidAdapter', function() { }); it('sets the proper banner object', function() { - const payload = JSON.parse(request.data); + const payload = JSON.parse(request.data) expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}, {w: 300, h: 600}]) expect(payload.imp[0].banner.w).to.equal(1) expect(payload.imp[0].banner.h).to.equal(1) }) + it('includes the ad unit code int the request', function() { + const payload = JSON.parse(request.data); + expect(payload.imp[0].adunitcode).to.equal('adunit-code') + }) + it('accepts a single array as a size', function() { const singleSize = [{ 'bidder': 'sovrn', @@ -234,7 +239,7 @@ describe('sovrnBidAdapter', function() { expect(data.source.ext.schain.nodes.length).to.equal(1) }); - it('should add digitrust data if present', function() { + it('should add the unifiedID if present', function() { const digitrustRequests = [{ 'bidder': 'sovrn', 'params': { @@ -249,12 +254,7 @@ describe('sovrnBidAdapter', function() { 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', 'userId': { - 'digitrustid': { - 'data': { - 'id': 'digitrust-id-123', - 'keyv': 4 - } - } + 'tdid': 'SOMESORTOFID', } }].concat(bidRequests); const bidderRequest = { @@ -262,13 +262,13 @@ describe('sovrnBidAdapter', function() { referer: 'http://example.com/page.html', } }; - const data = JSON.parse(spec.buildRequests(digitrustRequests, bidderRequest).data); - expect(data.user.ext.digitrust.id).to.equal('digitrust-id-123'); - expect(data.user.ext.digitrust.keyv).to.equal(4); - }); + const data = JSON.parse(spec.buildRequests(digitrustRequests, bidderRequest).data); + expect(data.user.ext.eids[0].source).to.equal('adserver.org') + expect(data.user.ext.eids[0].uids[0].id).to.equal('SOMESORTOFID') + expect(data.user.ext.eids[0].uids[0].ext.rtiPartner).to.equal('TDID') + }) }); - describe('interpretResponse', function () { let response; beforeEach(function () { diff --git a/test/spec/modules/spotxBidAdapter_spec.js b/test/spec/modules/spotxBidAdapter_spec.js index 9c6e6071155..798fb3eec10 100644 --- a/test/spec/modules/spotxBidAdapter_spec.js +++ b/test/spec/modules/spotxBidAdapter_spec.js @@ -1,4 +1,5 @@ import {expect} from 'chai'; +import {config} from 'src/config.js'; import {spec, GOOGLE_CONSENT} from 'modules/spotxBidAdapter.js'; describe('the spotx adapter', function () { @@ -89,6 +90,7 @@ describe('the spotx adapter', function () { expect(spec.isBidRequestValid(bid)).to.equal(false); }); }); + describe('buildRequests', function() { var bid, bidRequestObj; @@ -125,6 +127,7 @@ describe('the spotx adapter', function () { page: 'prebid.js' }); }); + it('should change request parameters based on options sent', function() { var request = spec.buildRequests([bid], bidRequestObj)[0]; expect(request.data.imp.video.ext).to.deep.equal({ @@ -144,11 +147,15 @@ describe('the spotx adapter', function () { price_floor: 123, start_delay: true, number_of_ads: 2, - spotx_all_google_consent: 1 + spotx_all_google_consent: 1, + min_duration: 5, + max_duration: 10, + placement_type: 1, + position: 1 }; bid.userId = { - id5id: 'id5id_1', + id5id: { uid: 'id5id_1' }, tdid: 'tdid_1' }; @@ -169,6 +176,10 @@ describe('the spotx adapter', function () { request = spec.buildRequests([bid], bidRequestObj)[0]; expect(request.data.id).to.equal(54321); + expect(request.data.imp.video).to.contain({ + minduration: 5, + maxduration: 10 + }) expect(request.data.imp.video.ext).to.deep.equal({ ad_volume: 1, hide_skin: 1, @@ -177,7 +188,9 @@ describe('the spotx adapter', function () { outstream_function: '987', custom: {bar: 'foo'}, sdk_name: 'Prebid 1+', - versionOrtb: '2.3' + versionOrtb: '2.3', + placement: 1, + pos: 1 }); expect(request.data.imp.video.startdelay).to.equal(1); @@ -192,7 +205,8 @@ describe('the spotx adapter', function () { source: 'id5-sync.com', uids: [{ id: 'id5id_1' - }] + }], + ext: {} }, { source: 'adserver.org', @@ -297,6 +311,74 @@ describe('the spotx adapter', function () { expect(request.data.user.ext.consent).to.equal('consent123'); expect(request.data.regs.ext.us_privacy).to.equal('1YYY'); }); + + it('should pass min and max duration params', function() { + var request; + + bid.params.min_duration = 3 + bid.params.max_duration = 15 + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.imp.video.minduration).to.equal(3); + expect(request.data.imp.video.maxduration).to.equal(15); + }); + + it('should pass placement_type and position params', function() { + var request; + + bid.params.placement_type = 2 + bid.params.position = 5 + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.imp.video.ext.placement).to.equal(2); + expect(request.data.imp.video.ext.pos).to.equal(5); + }); + + it('should pass page param and override refererInfo.referer', function() { + var request; + + bid.params.page = 'https://example.com'; + + var origGetConfig = config.getConfig; + sinon.stub(config, 'getConfig').callsFake(function (key) { + if (key === 'pageUrl') { + return 'https://www.spotx.tv'; + } + return origGetConfig.apply(config, arguments); + }); + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.site.page).to.equal('https://example.com'); + config.getConfig.restore(); + }); + + it('should use pageUrl from config if page param is not passed', function() { + var request; + + var origGetConfig = config.getConfig; + sinon.stub(config, 'getConfig').callsFake(function (key) { + if (key === 'pageUrl') { + return 'https://www.spotx.tv'; + } + return origGetConfig.apply(config, arguments); + }); + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.site.page).to.equal('https://www.spotx.tv'); + config.getConfig.restore(); + }); + + it('should use refererInfo.referer if no page or pageUrl are passed', function() { + var request; + + request = spec.buildRequests([bid], bidRequestObj)[0]; + + expect(request.data.site.page).to.equal('prebid.js'); + }); }); describe('interpretResponse', function() { @@ -347,6 +429,7 @@ describe('the spotx adapter', function () { impid: 123, cur: 'USD', price: 12, + adomain: ['abc.com'], crid: 321, w: 400, h: 300, @@ -358,6 +441,7 @@ describe('the spotx adapter', function () { impid: 124, cur: 'USD', price: 13, + adomain: ['def.com'], w: 200, h: 100, ext: { @@ -375,6 +459,7 @@ describe('the spotx adapter', function () { expect(responses).to.be.an('array').with.length(2); expect(responses[0].cache_key).to.equal('cache123'); expect(responses[0].channel_id).to.equal(12345); + expect(responses[0].meta.advertiserDomains[0]).to.equal('abc.com'); expect(responses[0].cpm).to.equal(12); expect(responses[0].creativeId).to.equal(321); expect(responses[0].currency).to.equal('USD'); @@ -389,6 +474,7 @@ describe('the spotx adapter', function () { expect(responses[1].cache_key).to.equal('cache124'); expect(responses[1].channel_id).to.equal(12345); expect(responses[1].cpm).to.equal(13); + expect(responses[1].meta.advertiserDomains[0]).to.equal('def.com'); expect(responses[1].creativeId).to.equal(''); expect(responses[1].currency).to.equal('USD'); expect(responses[1].height).to.equal(100); @@ -477,6 +563,7 @@ describe('the spotx adapter', function () { expect(scriptTag.getAttribute('data-spotx_digitrust_opt_out')).to.equal('1'); expect(scriptTag.getAttribute('data-spotx_content_width')).to.equal('400'); expect(scriptTag.getAttribute('data-spotx_content_height')).to.equal('300'); + expect(scriptTag.getAttribute('data-spotx_ad_mute')).to.equal('1'); window.document.getElementById.restore(); }); diff --git a/test/spec/modules/sspBCAdapter_spec.js b/test/spec/modules/sspBCAdapter_spec.js new file mode 100644 index 00000000000..2cb0e8defa4 --- /dev/null +++ b/test/spec/modules/sspBCAdapter_spec.js @@ -0,0 +1,334 @@ +import { assert, expect } from 'chai'; +import { spec } from 'modules/sspBCAdapter.js'; +import * as utils from 'src/utils.js'; + +const BIDDER_CODE = 'sspBC'; +const BIDDER_URL = 'https://ssp.wp.pl/bidder/'; +const SYNC_URL = 'https://ssp.wp.pl/bidder/usersync'; + +describe('SSPBC adapter', function () { + function prepareTestData() { + const bidderRequestId = '1041bb47b0fafa'; + const auctionId = '8eda6d06-3d7c-4a94-9b35-74e42fbb3089'; + const transactionId = '50259989-b5c0-4edf-8f47-b1ef5fbedf39'; + const gdprConsent = { + consentString: 'BOtq-3dOtq-30BIABCPLC4-AAAAthr_7__7-_9_-_f__9uj3Or_v_f__30ccL59v_h_7v-_7fi_20nV4u_1vft9yfk1-5ctDztp505iakivHmqNeb9v_mz1_5pRP78k89r7337Ew_v8_v-b7JCON_Ig', + gdprApplies: true, + } + const bids = [{ + adUnitCode: 'test_wideboard', + bidder: BIDDER_CODE, + mediaTypes: { + banner: { + sizes: [ + [728, 90], + [750, 100], + [750, 200] + ] + } + }, + sizes: [ + [728, 90], + [750, 100], + [750, 200] + ], + params: { + id: '003', + siteId: '8816', + }, + auctionId, + bidderRequestId, + bidId: auctionId + '1', + transactionId, + }, + { + adUnitCode: 'test_rectangle', + bidder: BIDDER_CODE, + mediaTypes: { + banner: { + sizes: [ + [300, 250] + ] + } + }, + sizes: [ + [300, 250] + ], + params: { + id: '005', + siteId: '8816', + }, + auctionId, + bidderRequestId, + bidId: auctionId + '1', + transactionId, + } + ]; + const bids_test = [{ + adUnitCode: 'test_wideboard', + bidder: BIDDER_CODE, + mediaTypes: { + banner: { + sizes: [ + [970, 300], + [750, 300], + [750, 200], + [750, 100], + [300, 250] + ] + } + }, + sizes: [ + [970, 300], + [750, 300], + [750, 200], + [750, 100], + [300, 250] + ], + params: { + id: '005', + siteId: '235911', + test: 1 + }, + auctionId, + bidderRequestId, + bidId: auctionId + '1', + transactionId, + }]; + const bidRequest = { + auctionId, + bidderCode: BIDDER_CODE, + bidderRequestId, + bids, + gdprConsent, + refererInfo: { + reachedTop: true, + referer: 'https://test.site.pl/', + stack: ['https://test.site.pl/'], + } + }; + const bidRequestSingle = { + auctionId, + bidderCode: BIDDER_CODE, + bidderRequestId, + bids: [bids[0]], + gdprConsent, + refererInfo: { + reachedTop: true, + referer: 'https://test.site.pl/', + stack: ['https://test.site.pl/'], + } + }; + const bidRequestTest = { + auctionId, + bidderCode: BIDDER_CODE, + bidderRequestId, + bids: bids_test, + gdprConsent, + refererInfo: { + reachedTop: true, + referer: 'https://test.site.pl/', + stack: ['https://test.site.pl/'], + } + }; + const bidRequestTestNoGDPR = { + auctionId, + bidderCode: BIDDER_CODE, + bidderRequestId, + bids: bids_test, + refererInfo: { + reachedTop: true, + referer: 'https://test.site.pl/', + stack: ['https://test.site.pl/'], + } + }; + const serverResponse = { + 'body': { + 'id': auctionId, + 'seatbid': [{ + 'bid': [{ + 'id': '3347324c-6889-46d2-a800-ae78a5214c06', + 'impid': '003', + 'price': 1, + 'adid': 'lxHWkB7OnZeso3QiN1N4', + 'nurl': '', + 'adm': 'AD CODE 1', + 'adomain': ['adomain.pl'], + 'cid': 'BZ4gAg21T5nNtxlUCDSW', + 'crid': 'lxHWkB7OnZeso3QiN1N4', + 'w': 728, + 'h': 90 + }], + 'seat': 'dsp1', + 'group': 0 + }, { + 'bid': [{ + 'id': '2d766853-ea07-4529-8299-5f0ebadc546a', + 'impid': '005', + 'price': 2, + 'adm': 'AD CODE 2', + 'cid': '57744', + 'crid': '858252', + 'w': 300, + 'h': 250 + }], + 'seat': 'dsp2', + 'group': 0 + }], + 'cur': 'PLN' + } + }; + const serverResponseSingle = { + 'body': { + 'id': auctionId, + 'seatbid': [{ + 'bid': [{ + 'id': '3347324c-6889-46d2-a800-ae78a5214c06', + 'impid': '003', + 'price': 1, + 'adid': 'lxHWkB7OnZeso3QiN1N4', + 'nurl': '', + 'adm': 'AD CODE 1', + 'adomain': ['adomain.pl'], + 'cid': 'BZ4gAg21T5nNtxlUCDSW', + 'crid': 'lxHWkB7OnZeso3QiN1N4', + 'w': 728, + 'h': 90 + }], + 'seat': 'dsp1', + 'group': 0 + }], + 'cur': 'PLN' + } + }; + const emptyResponse = { + 'body': { + 'id': auctionId, + } + } + return { + bids, + bids_test, + bidRequest, + bidRequestSingle, + bidRequestTest, + bidRequestTestNoGDPR, + serverResponse, + serverResponseSingle, + emptyResponse + }; + }; + + describe('dependencies', function () { + it('utils should contain required functions', function () { + expect(utils.parseUrl).to.be.a('function'); + expect(utils.deepAccess).to.be.a('function'); + expect(utils.logWarn).to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + const { bids } = prepareTestData(); + let bid = bids[0]; + + it('should return true when required params found', function () { + assert(spec.isBidRequestValid(bid)); + }); + + it('should return false when required params are missing', function () { + bid.params.id = undefined; + assert.isFalse(spec.isBidRequestValid(bid)); + }); + }); + + describe('buildRequests', function () { + const { bids, bidRequest, bidRequestSingle } = prepareTestData(); + const request = spec.buildRequests(bids, bidRequest); + const requestSingle = spec.buildRequests([bids[0]], bidRequestSingle); + const payload = request ? JSON.parse(request.data) : { site: false, imp: false }; + const payloadSingle = request ? JSON.parse(requestSingle.data) : { site: false, imp: false }; + + it('should send bid request to endpoint via POST', function () { + expect(request.url).to.contain(BIDDER_URL); + expect(request.method).to.equal('POST'); + }); + + it('should contain prebid and bidder versions', function () { + expect(request.url).to.contain('bdver'); + expect(request.url).to.contain('pbver=$prebid.version$'); + }); + + it('should create one imp object per bid', function () { + expect(payload.imp.length).to.equal(bids.length); + expect(payloadSingle.imp.length).to.equal(1); + }); + + it('should save bidder request data', function () { + expect(request.bidderRequest).to.deep.equal(bidRequest); + }); + + it('should send site Id from bidder params', function () { + expect(payload.site.id).to.equal(bids[0].params.siteId); + }); + + it('should send page url from refererInfo', function () { + expect(payload.site.page).to.equal(bidRequest.refererInfo.referer); + }); + + it('should send gdpr data', function () { + expect(payload.regs).to.be.an('object').and.to.have.property('[ortb_extensions.gdpr]', 1); + expect(payload.user).to.be.an('object').and.to.have.property('[ortb_extensions.consent]', bidRequest.gdprConsent.consentString); + }); + }); + + describe('interpretResponse', function () { + const { bids, emptyResponse, serverResponse, serverResponseSingle, bidRequest, bidRequestSingle } = prepareTestData(); + const request = spec.buildRequests(bids, bidRequest); + const requestSingle = spec.buildRequests([bids[0]], bidRequestSingle); + + it('should handle nobid responses', function () { + let result = spec.interpretResponse(emptyResponse, request); + expect(result.length).to.equal(0); + }); + + it('should create bids from non-empty responses', function () { + let result = spec.interpretResponse(serverResponse, request); + let resultSingle = spec.interpretResponse(serverResponseSingle, requestSingle); + + expect(result.length).to.equal(bids.length); + expect(resultSingle.length).to.equal(1); + expect(resultSingle[0]).to.have.keys('ad', 'cpm', 'width', 'height', 'bidderCode', 'mediaType', 'meta', 'requestId', 'creativeId', 'currency', 'netRevenue', 'ttl'); + }); + + it('should handle a partial response', function () { + let resultPartial = spec.interpretResponse(serverResponseSingle, request); + expect(resultPartial.length).to.equal(1); + }); + + it('banner ad code should contain required variables', function () { + let resultSingle = spec.interpretResponse(serverResponseSingle, requestSingle); + let adcode = resultSingle[0].ad; + expect(adcode).to.be.a('string'); + expect(adcode).to.contain('window.rekid'); + expect(adcode).to.contain('window.mcad'); + expect(adcode).to.contain('window.gdpr'); + expect(adcode).to.contain('window.page'); + }) + }); + + describe('getUserSyncs', function () { + let syncResultAll = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }); + let syncResultImage = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: true }); + let syncResultNone = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: false }); + + it('should provide correct url, if frame sync is allowed', function () { + expect(syncResultAll).to.have.length(1); + expect(syncResultAll[0].url).to.be.equal(SYNC_URL); + }); + + it('should send no syncs, if frame sync is not allowed', function () { + expect(syncResultImage).to.be.undefined; + expect(syncResultNone).to.be.undefined; + }); + }); +}); diff --git a/test/spec/modules/sublimeBidAdapter_spec.js b/test/spec/modules/sublimeBidAdapter_spec.js index ae9e293a757..008f24730bc 100644 --- a/test/spec/modules/sublimeBidAdapter_spec.js +++ b/test/spec/modules/sublimeBidAdapter_spec.js @@ -149,7 +149,7 @@ describe('Sublime Adapter', function() { currency: 'USD', netRevenue: true, ttl: 600, - pbav: '0.5.2', + pbav: '0.6.0', ad: '', }, ]; @@ -191,7 +191,7 @@ describe('Sublime Adapter', function() { netRevenue: true, ttl: 600, ad: '', - pbav: '0.5.2', + pbav: '0.6.0', }; expect(result[0]).to.deep.equal(expectedResponse); @@ -241,7 +241,7 @@ describe('Sublime Adapter', function() { netRevenue: true, ttl: 600, ad: '', - pbav: '0.5.2', + pbav: '0.6.0', }; expect(result[0]).to.deep.equal(expectedResponse); diff --git a/test/spec/modules/synacormediaBidAdapter_spec.js b/test/spec/modules/synacormediaBidAdapter_spec.js index f6fa7a20594..dd40e634723 100644 --- a/test/spec/modules/synacormediaBidAdapter_spec.js +++ b/test/spec/modules/synacormediaBidAdapter_spec.js @@ -68,9 +68,13 @@ describe('synacormediaBidAdapter ', function () { }, mediaTypes: { banner: { - h: 600, - pos: 0, - w: 300, + format: [ + { + w: 300, + h: 600 + } + ], + pos: 0 } }, }; @@ -171,23 +175,29 @@ describe('synacormediaBidAdapter ', function () { } }; - let expectedDataImp1 = { - banner: { - h: 250, - pos: 0, - w: 300, + let bidderRequestWithCCPA = { + auctionId: 'xyz123', + refererInfo: { + referer: 'https://test.com/foo/bar' }, - id: 'b9876abcd-300x250', - tagid: '1234', - bidfloor: 0.5 + uspConsent: '1YYY' }; - let expectedDataImp2 = { + + let expectedDataImp1 = { banner: { - h: 600, - pos: 0, - w: 300, + format: [ + { + h: 250, + w: 300 + }, + { + h: 600, + w: 300 + } + ], + pos: 0 }, - id: 'b9876abcd-300x600', + id: 'b9876abcd', tagid: '1234', bidfloor: 0.5 }; @@ -201,7 +211,7 @@ describe('synacormediaBidAdapter ', function () { expect(req.url).to.contain('https://prebid.technoratimedia.com/openrtb/bids/prebid?'); expect(req.data).to.exist.and.to.be.an('object'); expect(req.data.id).to.equal('xyz123'); - expect(req.data.imp).to.eql([expectedDataImp1, expectedDataImp2]); + expect(req.data.imp).to.eql([expectedDataImp1]); // video test let reqVideo = spec.buildRequests([validBidRequestVideo], bidderRequestVideo); @@ -230,13 +240,17 @@ describe('synacormediaBidAdapter ', function () { expect(req).to.have.property('url'); expect(req.url).to.contain('https://prebid.technoratimedia.com/openrtb/bids/prebid?'); expect(req.data.id).to.equal('xyz123'); - expect(req.data.imp).to.eql([expectedDataImp1, expectedDataImp2, { + expect(req.data.imp).to.eql([expectedDataImp1, { banner: { - h: 600, - pos: 0, - w: 300, + format: [ + { + h: 600, + w: 300 + } + ], + pos: 0 }, - id: 'bfoobar-300x600', + id: 'bfoobar', tagid: '5678', bidfloor: 0.5 }]); @@ -255,16 +269,20 @@ describe('synacormediaBidAdapter ', function () { let req = spec.buildRequests([mismatchedSeatBidRequest, validBidRequest], bidderRequest); expect(req).to.have.property('method', 'POST'); expect(req).to.have.property('url'); - expect(req.url).to.contain('https://prebid.technoratimedia.com/openrtb/bids/somethingelse?'); + expect(req.url).to.contain('https://somethingelse.technoratimedia.com/openrtb/bids/somethingelse?'); expect(req.data.id).to.equal('xyz123'); expect(req.data.imp).to.eql([ { banner: { - h: 250, - pos: 0, - w: 300, + format: [ + { + h: 250, + w: 300 + } + ], + pos: 0 }, - id: 'bfoobar-300x250', + id: 'bfoobar', tagid: '5678', bidfloor: 0.5 } @@ -289,11 +307,15 @@ describe('synacormediaBidAdapter ', function () { expect(req.data.imp).to.eql([ { banner: { - h: 250, - pos: 0, - w: 300, + format: [ + { + h: 250, + w: 300 + } + ], + pos: 0 }, - id: 'b9876abcd-300x250', + id: 'b9876abcd', tagid: '1234', } ]); @@ -316,11 +338,15 @@ describe('synacormediaBidAdapter ', function () { expect(req.data.imp).to.eql([ { banner: { - h: 250, - pos: 0, - w: 300, + format: [ + { + h: 250, + w: 300 + } + ], + pos: 0 }, - id: 'b9876abcd-300x250', + id: 'b9876abcd', tagid: '1234', } ]); @@ -344,11 +370,15 @@ describe('synacormediaBidAdapter ', function () { expect(req.data.imp).to.eql([ { banner: { - h: 250, - w: 300, - pos: 1, + format: [ + { + h: 250, + w: 300 + } + ], + pos: 1 }, - id: 'b9876abcd-300x250', + id: 'b9876abcd', tagid: '1234' } ]); @@ -371,11 +401,15 @@ describe('synacormediaBidAdapter ', function () { expect(req.data.imp).to.eql([ { banner: { - h: 250, - w: 300, - pos: 0, + format: [ + { + h: 250, + w: 300 + } + ], + pos: 0 }, - id: 'b9876abcd-300x250', + id: 'b9876abcd', tagid: '1234' } ]); @@ -534,6 +568,18 @@ describe('synacormediaBidAdapter ', function () { } ]); }); + it('should contain the CCPA privacy string when UspConsent is in bidder request', function() { + // banner test + let req = spec.buildRequests([validBidRequest], bidderRequestWithCCPA); + expect(req).be.an('object'); + expect(req).to.have.property('method', 'POST'); + expect(req).to.have.property('url'); + expect(req.url).to.contain('https://prebid.technoratimedia.com/openrtb/bids/prebid?'); + expect(req.data).to.exist.and.to.be.an('object'); + expect(req.data.id).to.equal('xyz123'); + expect(req.data.regs.ext.us_privacy).to.equal('1YYY'); + expect(req.data.imp).to.eql([expectedDataImp1]); + }) }); describe('Bid Requests with schain object ', function() { @@ -642,21 +688,50 @@ describe('synacormediaBidAdapter ', function () { describe('interpretResponse', function () { let bidResponse = { id: '10865933907263896~9998~0', - impid: 'b9876abcd-300x250', + impid: 'b9876abcd', price: 0.13, crid: '1022-250', adm: '', - nurl: 'https://uat-net.technoratimedia.com/openrtb/tags?ID=k5JkFVQ1RJT05fSU1QX0lEPXYyZjczN&AUCTION_PRICE=${AUCTION_PRICE}' + nurl: 'https://uat-net.technoratimedia.com/openrtb/tags?ID=k5JkFVQ1RJT05fSU1QX0lEPXYyZjczN&AUCTION_PRICE=${AUCTION_PRICE}', + w: 300, + h: 250 }; let bidResponse2 = { id: '10865933907263800~9999~0', - impid: 'b9876abcd-300x600', + impid: 'b9876abcd', price: 1.99, crid: '9993-013', adm: '', - nurl: 'https://uat-net.technoratimedia.com/openrtb/tags?ID=OTk5OX4wJkFVQ1RJT05fU0VBVF9JR&AUCTION_PRICE=${AUCTION_PRICE}' + nurl: 'https://uat-net.technoratimedia.com/openrtb/tags?ID=OTk5OX4wJkFVQ1RJT05fU0VBVF9JR&AUCTION_PRICE=${AUCTION_PRICE}', + w: 300, + h: 600 }; + let bidRequest = { + data: { + id: '', + imp: [ + { + id: 'abc123', + banner: { + format: [ + { + w: 400, + h: 350 + } + ], + pos: 1 + } + } + ], + }, + method: 'POST', + options: { + contentType: 'application/json', + withCredentials: true + }, + url: 'https://prebid.technoratimedia.com/openrtb/bids/prebid?src=prebid_prebid_3.27.0-pre' + }; let serverResponse; beforeEach(function() { serverResponse = { @@ -671,6 +746,26 @@ describe('synacormediaBidAdapter ', function () { }); it('should return 1 video bid when 1 bid is in the video response', function () { + bidRequest = { + data: { + id: 'abcd1234', + imp: [ + { + video: { + w: 640, + h: 480 + }, + id: 'v2da7322b2df61f' + } + ] + }, + method: 'POST', + options: { + contentType: 'application/json', + withCredentials: true + }, + url: 'https://prebid.technoratimedia.com/openrtb/bids/prebid?src=prebid_prebid_3.27.0-pre' + }; let serverRespVideo = { body: { id: 'abcd1234', @@ -679,14 +774,16 @@ describe('synacormediaBidAdapter ', function () { bid: [ { id: '11339128001692337~9999~0', - impid: 'v2da7322b2df61f-640x480', + impid: 'v2da7322b2df61f', price: 0.45, nurl: 'https://uat-net.technoratimedia.com/openrtb/tags?ID=QVVDVElPTl9JRD1lOTBhYWU1My1hZDkwLTRkNDEtYTQxMC1lZDY1MjIxMDc0ZGMmQVVDVElPTl9CSURfSUQ9MTEzMzkxMjgwMDE2OTIzMzd-OTk5OX4wJkFVQ1RJT05fU0VBVF9JRD05OTk5JkFVQ1RJT05fSU1QX0lEPXYyZGE3MzIyYjJkZjYxZi02NDB4NDgwJkFDVE9SX1JFRj1ha2thLnRjcDovL2F3cy1lYXN0MUBhZHMxMy5jYXAtdXNlMS5zeW5hY29yLmNvbToyNTUxL3VzZXIvJGNMYmZiIy0xOTk4NTIzNTk3JlNFQVRfSUQ9cHJlYmlk&AUCTION_PRICE=${AUCTION_PRICE}', adm: '\n\n\n\nSynacor Media Ad Server - 9999\nhttps://uat-net.technoratimedia.com/openrtb/tags?ID=QVVDVElPTl9JRD1lOTBhYWU1My1hZDkwLTRkNDEtYTQxMC1lZDY1MjIxMDc0ZGMmQVVDVElPTl9CSURfSUQ9MTEzMzkxMjgwMDE2OTIzMzd-OTk5OX4wJkFVQ1RJT05fU0VBVF9JRD05OTk5JkFVQ1RJT05fSU1QX0lEPXYyZGE3MzIyYjJkZjYxZi02NDB4NDgwJkFDVE9SX1JFRj1ha2thLnRjcDovL2F3cy1lYXN0MUBhZHMxMy5jYXAtdXNlMS5zeW5hY29yLmNvbToyNTUxL3VzZXIvJGNMYmZiIy0xOTk4NTIzNTk3JlNFQVRfSUQ9cHJlYmlk&AUCTION_PRICE=${AUCTION_PRICE}\n\n\n', adomain: [ 'psacentral.org' ], cid: 'bidder-crid', crid: 'bidder-cid', - cat: [] + cat: [], + w: 640, + h: 480 } ], seat: '9999' @@ -696,7 +793,7 @@ describe('synacormediaBidAdapter ', function () { }; // serverResponse.body.seatbid[0].bid.push(bidResponse); - let resp = spec.interpretResponse(serverRespVideo); + let resp = spec.interpretResponse(serverRespVideo, bidRequest); expect(resp).to.be.an('array').to.have.lengthOf(1); expect(resp[0]).to.eql({ requestId: '2da7322b2df61f', @@ -717,7 +814,7 @@ describe('synacormediaBidAdapter ', function () { it('should return 1 bid when 1 bid is in the response', function () { serverResponse.body.seatbid[0].bid.push(bidResponse); - let resp = spec.interpretResponse(serverResponse); + let resp = spec.interpretResponse(serverResponse, bidRequest); expect(resp).to.be.an('array').to.have.lengthOf(1); expect(resp[0]).to.eql({ requestId: '9876abcd', @@ -740,7 +837,7 @@ describe('synacormediaBidAdapter ', function () { seat: '9999', bid: [bidResponse2], }); - let resp = spec.interpretResponse(serverResponse); + let resp = spec.interpretResponse(serverResponse, bidRequest); expect(resp).to.be.an('array').to.have.lengthOf(2); expect(resp[0]).to.eql({ requestId: '9876abcd', @@ -772,7 +869,7 @@ describe('synacormediaBidAdapter ', function () { }); it('should not return a bid when no bid is in the response', function () { - let resp = spec.interpretResponse(serverResponse); + let resp = spec.interpretResponse(serverResponse, bidRequest); expect(resp).to.be.an('array').that.is.empty; }); @@ -791,14 +888,16 @@ describe('synacormediaBidAdapter ', function () { bid: [ { id: '11339128001692337~9999~0', - impid: 'v2da7322b2df61f-640x480', + impid: 'v2da7322b2df61f', price: 0.45, nurl: 'https://uat-net.technoratimedia.com/openrtb/tags?ID=QVVDVElPTl9JRD1lOTBhYWU1My1hZDkwLTRkNDEtYTQxMC1lZDY1MjIxMDc0ZGMmQVVDVElPTl9CSURfSUQ9MTEzMzkxMjgwMDE2OTIzMzd-OTk5OX4wJkFVQ1RJT05fU0VBVF9JRD05OTk5JkFVQ1RJT05fSU1QX0lEPXYyZGE3MzIyYjJkZjYxZi02NDB4NDgwJkFDVE9SX1JFRj1ha2thLnRjcDovL2F3cy1lYXN0MUBhZHMxMy5jYXAtdXNlMS5zeW5hY29yLmNvbToyNTUxL3VzZXIvJGNMYmZiIy0xOTk4NTIzNTk3JlNFQVRfSUQ9cHJlYmlk&AUCTION_PRICE=${AUCTION_PRICE}', adm: '\n\n\n\nSynacor Media Ad Server - 9999\nhttps://uat-net.technoratimedia.com/openrtb/tags?ID=QVVDVElPTl9JRD1lOTBhYWU1My1hZDkwLTRkNDEtYTQxMC1lZDY1MjIxMDc0ZGMmQVVDVElPTl9CSURfSUQ9MTEzMzkxMjgwMDE2OTIzMzd-OTk5OX4wJkFVQ1RJT05fU0VBVF9JRD05OTk5JkFVQ1RJT05fSU1QX0lEPXYyZGE3MzIyYjJkZjYxZi02NDB4NDgwJkFDVE9SX1JFRj1ha2thLnRjcDovL2F3cy1lYXN0MUBhZHMxMy5jYXAtdXNlMS5zeW5hY29yLmNvbToyNTUxL3VzZXIvJGNMYmZiIy0xOTk4NTIzNTk3JlNFQVRfSUQ9cHJlYmlk&AUCTION_PRICE=${AUCTION_PRICE}\n\n\n', adomain: [ 'psacentral.org' ], cid: 'bidder-crid', crid: 'bidder-cid', - cat: [] + cat: [], + w: 640, + h: 480 } ], seat: '9999' @@ -814,10 +913,125 @@ describe('synacormediaBidAdapter ', function () { return config[key]; }); - let resp = spec.interpretResponse(serverRespVideo); + let resp = spec.interpretResponse(serverRespVideo, bidRequest); sandbox.restore(); expect(resp[0].videoCacheKey).to.not.exist; }); + + it('should use video bid request height and width if not present in response', function () { + bidRequest = { + data: { + id: 'abcd1234', + imp: [ + { + video: { + w: 300, + h: 250 + }, + id: 'v2da7322b2df61f' + } + ] + }, + method: 'POST', + options: { + contentType: 'application/json', + withCredentials: true + }, + url: 'https://prebid.technoratimedia.com/openrtb/bids/prebid?src=prebid_prebid_3.27.0-pre' + }; + + let serverRespVideo = { + body: { + id: 'abcd1234', + seatbid: [ + { + bid: [ + { + id: '11339128001692337~9999~0', + impid: 'v2da7322b2df61f', + price: 0.45, + nurl: 'https://uat-net.technoratimedia.com/openrtb/tags?ID=QVVDVElPTl9JRD1lOTBhYWU1My1hZDkwLTRkNDEtYTQxMC1lZDY1MjIxMDc0ZGMmQVVDVElPTl9CSURfSUQ9MTEzMzkxMjgwMDE2OTIzMzd-OTk5OX4wJkFVQ1RJT05fU0VBVF9JRD05OTk5JkFVQ1RJT05fSU1QX0lEPXYyZGE3MzIyYjJkZjYxZi02NDB4NDgwJkFDVE9SX1JFRj1ha2thLnRjcDovL2F3cy1lYXN0MUBhZHMxMy5jYXAtdXNlMS5zeW5hY29yLmNvbToyNTUxL3VzZXIvJGNMYmZiIy0xOTk4NTIzNTk3JlNFQVRfSUQ9cHJlYmlk&AUCTION_PRICE=${AUCTION_PRICE}', + adm: '\n\n\n\nSynacor Media Ad Server - 9999\nhttps://uat-net.technoratimedia.com/openrtb/tags?ID=QVVDVElPTl9JRD1lOTBhYWU1My1hZDkwLTRkNDEtYTQxMC1lZDY1MjIxMDc0ZGMmQVVDVElPTl9CSURfSUQ9MTEzMzkxMjgwMDE2OTIzMzd-OTk5OX4wJkFVQ1RJT05fU0VBVF9JRD05OTk5JkFVQ1RJT05fSU1QX0lEPXYyZGE3MzIyYjJkZjYxZi02NDB4NDgwJkFDVE9SX1JFRj1ha2thLnRjcDovL2F3cy1lYXN0MUBhZHMxMy5jYXAtdXNlMS5zeW5hY29yLmNvbToyNTUxL3VzZXIvJGNMYmZiIy0xOTk4NTIzNTk3JlNFQVRfSUQ9cHJlYmlk&AUCTION_PRICE=${AUCTION_PRICE}\n\n\n', + adomain: [ 'psacentral.org' ], + cid: 'bidder-crid', + crid: 'bidder-cid', + cat: [] + } + ], + seat: '9999' + } + ] + } + }; + let resp = spec.interpretResponse(serverRespVideo, bidRequest); + expect(resp).to.be.an('array').to.have.lengthOf(1); + expect(resp[0]).to.eql({ + requestId: '2da7322b2df61f', + adId: '11339128001692337-9999-0', + cpm: 0.45, + width: 300, + height: 250, + creativeId: '9999_bidder-cid', + currency: 'USD', + netRevenue: true, + mediaType: 'video', + ad: '\n\n\n\nSynacor Media Ad Server - 9999\nhttps://uat-net.technoratimedia.com/openrtb/tags?ID=QVVDVElPTl9JRD1lOTBhYWU1My1hZDkwLTRkNDEtYTQxMC1lZDY1MjIxMDc0ZGMmQVVDVElPTl9CSURfSUQ9MTEzMzkxMjgwMDE2OTIzMzd-OTk5OX4wJkFVQ1RJT05fU0VBVF9JRD05OTk5JkFVQ1RJT05fSU1QX0lEPXYyZGE3MzIyYjJkZjYxZi02NDB4NDgwJkFDVE9SX1JFRj1ha2thLnRjcDovL2F3cy1lYXN0MUBhZHMxMy5jYXAtdXNlMS5zeW5hY29yLmNvbToyNTUxL3VzZXIvJGNMYmZiIy0xOTk4NTIzNTk3JlNFQVRfSUQ9cHJlYmlk&AUCTION_PRICE=0.45\n\n\n', + ttl: 60, + videoCacheKey: 'QVVDVElPTl9JRD1lOTBhYWU1My1hZDkwLTRkNDEtYTQxMC1lZDY1MjIxMDc0ZGMmQVVDVElPTl9CSURfSUQ9MTEzMzkxMjgwMDE2OTIzMzd-OTk5OX4wJkFVQ1RJT05fU0VBVF9JRD05OTk5JkFVQ1RJT05fSU1QX0lEPXYyZGE3MzIyYjJkZjYxZi02NDB4NDgwJkFDVE9SX1JFRj1ha2thLnRjcDovL2F3cy1lYXN0MUBhZHMxMy5jYXAtdXNlMS5zeW5hY29yLmNvbToyNTUxL3VzZXIvJGNMYmZiIy0xOTk4NTIzNTk3JlNFQVRfSUQ9cHJlYmlk', + vastUrl: 'https://uat-net.technoratimedia.com/openrtb/tags?ID=QVVDVElPTl9JRD1lOTBhYWU1My1hZDkwLTRkNDEtYTQxMC1lZDY1MjIxMDc0ZGMmQVVDVElPTl9CSURfSUQ9MTEzMzkxMjgwMDE2OTIzMzd-OTk5OX4wJkFVQ1RJT05fU0VBVF9JRD05OTk5JkFVQ1RJT05fSU1QX0lEPXYyZGE3MzIyYjJkZjYxZi02NDB4NDgwJkFDVE9SX1JFRj1ha2thLnRjcDovL2F3cy1lYXN0MUBhZHMxMy5jYXAtdXNlMS5zeW5hY29yLmNvbToyNTUxL3VzZXIvJGNMYmZiIy0xOTk4NTIzNTk3JlNFQVRfSUQ9cHJlYmlk&AUCTION_PRICE=0.45' + }); + }); + + it('should use banner bid request height and width if not present in response', function () { + bidRequest = { + data: { + id: 'abc123', + imp: [ + { + banner: { + format: [{ + w: 400, + h: 350 + }] + }, + id: 'babc123' + } + ] + }, + method: 'POST', + options: { + contentType: 'application/json', + withCredentials: true + }, + url: 'https://prebid.technoratimedia.com/openrtb/bids/prebid?src=prebid_prebid_3.27.0-pre' + }; + + bidResponse = { + id: '10865933907263896~9998~0', + impid: 'babc123', + price: 0.13, + crid: '1022-250', + adm: '', + nurl: 'https://uat-net.technoratimedia.com/openrtb/tags?ID=k5JkFVQ1RJT05fSU1QX0lEPXYyZjczN&AUCTION_PRICE=${AUCTION_PRICE}', + }; + + serverResponse.body.seatbid[0].bid.push(bidResponse); + let resp = spec.interpretResponse(serverResponse, bidRequest); + expect(resp).to.be.an('array').to.have.lengthOf(1); + expect(resp[0]).to.eql({ + requestId: 'abc123', + adId: '10865933907263896-9998-0', + cpm: 0.13, + width: 400, + height: 350, + creativeId: '9998_1022-250', + currency: 'USD', + netRevenue: true, + mediaType: BANNER, + ad: '', + ttl: 60 + }); + }); }); describe('getUserSyncs', function () { it('should return a usersync when iframes is enabled', function () { diff --git a/test/spec/modules/teadsBidAdapter_spec.js b/test/spec/modules/teadsBidAdapter_spec.js index e21dce9135a..17841b271d4 100644 --- a/test/spec/modules/teadsBidAdapter_spec.js +++ b/test/spec/modules/teadsBidAdapter_spec.js @@ -166,6 +166,57 @@ describe('teadsBidAdapter', () => { expect(payload.referrer).to.deep.equal('https://example.com/page.html') }); + it('should add networkBandwidth info to payload', function () { + const request = spec.buildRequests(bidRequests, bidderResquestDefault); + const payload = JSON.parse(request.data); + + const bandwidth = window.navigator && window.navigator.connection && window.navigator.connection.downlink; + + expect(payload.networkBandwidth).to.exist; + + if (bandwidth) { + expect(payload.networkBandwidth).to.deep.equal(bandwidth.toString()); + } else { + expect(payload.networkBandwidth).to.deep.equal(''); + } + }); + + it('should add pageReferrer info to payload', function () { + const request = spec.buildRequests(bidRequests, bidderResquestDefault); + const payload = JSON.parse(request.data); + + expect(payload.pageReferrer).to.exist; + expect(payload.pageReferrer).to.deep.equal(document.referrer); + }); + + it('should add timeToFirstByte info to payload', function () { + const request = spec.buildRequests(bidRequests, bidderResquestDefault); + const payload = JSON.parse(request.data); + const performance = window.performance || window.webkitPerformance || window.msPerformance || window.mozPerformance; + + const ttfbExpectedV2 = performance && + typeof performance.getEntriesByType === 'function' && + Object.prototype.toString.call(performance.getEntriesByType) === '[object Function]' && + performance.getEntriesByType('navigation')[0] && + performance.getEntriesByType('navigation')[0].responseStart && + performance.getEntriesByType('navigation')[0].requestStart && + performance.getEntriesByType('navigation')[0].responseStart >= 0 && + performance.getEntriesByType('navigation')[0].requestStart >= 0 && + Math.round( + performance.getEntriesByType('navigation')[0].responseStart - performance.getEntriesByType('navigation')[0].requestStart + ); + + expect(payload.timeToFirstByte).to.exist; + + if (ttfbExpectedV2) { + expect(payload.timeToFirstByte).to.deep.equal(ttfbExpectedV2.toString()); + } else { + const ttfbExpectedV1 = performance.timing.responseStart - performance.timing.requestStart; + + expect(payload.timeToFirstByte).to.deep.equal(ttfbExpectedV1.toString()); + } + }); + it('should send GDPR to endpoint with 11 status', function() { let consentString = 'JRJ8RKfDeBNsERRDCSAAZ+A=='; let bidderRequest = { @@ -403,39 +454,63 @@ describe('teadsBidAdapter', () => { }); describe('interpretResponse', function() { - let bids = { - 'body': { - 'responses': [{ - 'ad': AD_SCRIPT, + it('should get correct bid responses', function() { + let bids = { + 'body': { + 'responses': [{ + 'ad': AD_SCRIPT, + 'cpm': 0.5, + 'currency': 'USD', + 'height': 250, + 'bidId': '3ede2a3fa0db94', + 'ttl': 360, + 'width': 300, + 'creativeId': 'er2ee', + 'placementId': 34 + }, { + 'ad': AD_SCRIPT, + 'cpm': 0.5, + 'currency': 'USD', + 'height': 200, + 'bidId': '4fef3b4gb1ec15', + 'ttl': 360, + 'width': 350, + 'creativeId': 'fs3ff', + 'placementId': 34, + 'dealId': 'ABC_123' + }] + } + }; + let expectedResponse = [ + { 'cpm': 0.5, - 'currency': 'USD', + 'width': 300, 'height': 250, + 'currency': 'USD', 'netRevenue': true, - 'bidId': '3ede2a3fa0db94', 'ttl': 360, - 'width': 300, + 'ad': AD_SCRIPT, + 'requestId': '3ede2a3fa0db94', 'creativeId': 'er2ee', 'placementId': 34 - }] - } - }; - - it('should get correct bid response', function() { - let expectedResponse = { - 'cpm': 0.5, - 'width': 300, - 'height': 250, - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 360, - 'ad': AD_SCRIPT, - 'requestId': '3ede2a3fa0db94', - 'creativeId': 'er2ee', - 'placementId': 34 - }; + }, { + 'cpm': 0.5, + 'width': 350, + 'height': 200, + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + 'ad': AD_SCRIPT, + 'requestId': '4fef3b4gb1ec15', + 'creativeId': 'fs3ff', + 'placementId': 34, + 'dealId': 'ABC_123' + } + ] + ; let result = spec.interpretResponse(bids); - expect(result[0]).to.deep.equal(expectedResponse); + expect(result).to.eql(expectedResponse); }); it('handles nobid responses', function() { diff --git a/test/spec/modules/telariaBidAdapter_spec.js b/test/spec/modules/telariaBidAdapter_spec.js index 9e4098d7854..25649115cc1 100644 --- a/test/spec/modules/telariaBidAdapter_spec.js +++ b/test/spec/modules/telariaBidAdapter_spec.js @@ -236,7 +236,7 @@ describe('TelariaAdapter', () => { it('should get correct bid response', () => { let expectedResponseKeys = ['bidderCode', 'width', 'height', 'statusMessage', 'adId', 'mediaType', 'source', 'getStatusCode', 'getSize', 'requestId', 'cpm', 'creativeId', 'vastXml', - 'vastUrl', 'currency', 'netRevenue', 'ttl', 'ad']; + 'vastUrl', 'currency', 'netRevenue', 'ttl', 'ad', 'meta']; let bidRequest = spec.buildRequests(stub, BIDDER_REQUEST)[0]; bidRequest.bidId = '1234'; diff --git a/test/spec/modules/tripleliftBidAdapter_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js index 675b8b6c532..797b3fab0c1 100644 --- a/test/spec/modules/tripleliftBidAdapter_spec.js +++ b/test/spec/modules/tripleliftBidAdapter_spec.js @@ -4,26 +4,31 @@ import { newBidder } from 'src/adapters/bidderFactory.js'; import { deepClone } from 'src/utils.js'; import { config } from 'src/config.js'; import prebid from '../../../package.json'; +import * as utils from 'src/utils.js'; const ENDPOINT = 'https://tlx.3lift.com/header/auction?'; const GDPR_CONSENT_STR = 'BOONm0NOONm0NABABAENAa-AAAARh7______b9_3__7_9uz_Kv_K7Vf7nnG072lPVA9LTOQ6gEaY'; describe('triplelift adapter', function () { const adapter = newBidder(tripleliftAdapterSpec); + let bid, instreamBid; + let sandbox; - describe('inherited functions', function () { - it('exists and is a function', function () { - expect(adapter.callBids).to.exist.and.to.be.a('function'); - }); - }); - - describe('isBidRequestValid', function () { - let bid = { + this.beforeEach(() => { + bid = { bidder: 'triplelift', params: { inventoryCode: '12345', floor: 1.0, }, + mediaTypes: { + banner: { + sizes: [ + [970, 250], + [1, 1] + ] + } + }, 'adUnitCode': 'adunit-code', 'sizes': [[300, 250], [300, 600]], 'bidId': '30b31c1838de1e', @@ -31,28 +36,64 @@ describe('triplelift adapter', function () { 'auctionId': '1d1a030790a475', }; + instreamBid = { + bidder: 'triplelift', + params: { + inventoryCode: 'insteam_test', + floor: 1.0, + video: { + mimes: ['video/mp4'], + maxduration: 30, + minduration: 6, + w: 640, + h: 480 + } + }, + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480] + } + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }; + }) + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { it('should return true for valid bid request', function () { expect(tripleliftAdapterSpec.isBidRequestValid(bid)).to.equal(true); }); it('should return true when required params found', function () { - let bid = Object.assign({}, bid); - delete bid.params; - bid.params = { - inventoryCode: 'another_inv_code', - floor: 0.05 - }; + bid.params.inventoryCode = 'another_inv_code'; expect(tripleliftAdapterSpec.isBidRequestValid(bid)).to.equal(true); }); + it('should return true when required params found - instream', function () { + expect(tripleliftAdapterSpec.isBidRequestValid(instreamBid)).to.equal(true); + }); + it('should return false when required params are not passed', function () { - let bid = Object.assign({}, bid); - delete bid.params; - bid.params = { - floor: 1.0 - }; + delete bid.params.inventoryCode; expect(tripleliftAdapterSpec.isBidRequestValid(bid)).to.equal(false); }); + + it('should return false when required params are not passed - instream', function () { + delete instreamBid.mediaTypes.playerSize; + delete instreamBid.params.video.w; + delete instreamBid.params.video.h; + expect(tripleliftAdapterSpec.isBidRequestValid(instreamBid)).to.equal(false); + }); }); describe('buildRequests', function () { @@ -81,6 +122,14 @@ describe('triplelift adapter', function () { inventoryCode: '12345', floor: 1.0, }, + mediaTypes: { + banner: { + sizes: [ + [970, 250], + [1, 1] + ] + } + }, adUnitCode: 'adunit-code', sizes: [[300, 250], [300, 600], [1, 1, 1], ['flex']], bidId: '30b31c1838de1e', @@ -88,6 +137,33 @@ describe('triplelift adapter', function () { auctionId: '1d1a030790a475', userId: {}, schain, + }, + { + bidder: 'triplelift', + params: { + inventoryCode: 'insteam_test', + floor: 1.0, + video: { + mimes: ['video/mp4'], + maxduration: 30, + minduration: 6, + w: 640, + h: 480 + } + }, + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480] + } + }, + adUnitCode: 'adunit-code-instream', + sizes: [[300, 250], [300, 600], [1, 1, 1], ['flex']], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + userId: {}, + schain, } ]; @@ -103,6 +179,13 @@ describe('triplelift adapter', function () { height: 250, ad: 'ad-markup', iurl: 'https://s.adroll.com/a/IYR/N36/IYRN366MFVDITBAGNNT5U6.jpg' + }, + { + imp_id: 1, + crid: '10092_76480_i2j6qm8u', + cpm: 0.01, + ad: 'The Trade Desk', + tlx_source: 'hdx' } ], refererInfo: { @@ -113,6 +196,10 @@ describe('triplelift adapter', function () { gdprApplies: true }, }; + sandbox = sinon.sandbox.create(); + }); + afterEach(() => { + sandbox.restore(); }); it('exists and is an object', function () { @@ -120,6 +207,11 @@ describe('triplelift adapter', function () { expect(request).to.exist.and.to.be.a('object'); }); + it('should be able find video object from the instream request', function () { + const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); + expect(request.data.imp[1].video).to.exist.and.to.be.a('object'); + }); + it('should only parse sizes that are of the proper length and format', function () { const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); expect(request.data.imp[0].banner.format).to.have.length(2); @@ -133,6 +225,9 @@ describe('triplelift adapter', function () { expect(payload.imp[0].tagid).to.equal('12345'); expect(payload.imp[0].floor).to.equal(1.0); expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}, {w: 300, h: 600}]); + expect(payload.imp[1].tagid).to.equal('insteam_test'); + expect(payload.imp[1].floor).to.equal(1.0); + expect(payload.imp[1].video).to.exist.and.to.be.a('object'); }); it('should add tdid to the payload if included', function () { @@ -299,71 +394,46 @@ describe('triplelift adapter', function () { const { data: payload } = request; expect(payload.ext).to.deep.equal(undefined); }); - }); - - describe('interpretResponse', function () { - let response = { - body: { - bids: [ - { - imp_id: 0, - cpm: 1.062, - width: 300, - height: 250, - ad: 'ad-markup', - iurl: 'https://s.adroll.com/a/IYR/N36/IYRN366MFVDITBAGNNT5U6.jpg', - tl_source: 'tlx', - } - ] - } - }; - let bidderRequest = { - bidderCode: 'triplelift', - auctionId: 'a7ebcd1d-66ff-4b5c-a82c-6a21a6ee5a18', - bidderRequestId: '5c55612f99bc11', - bids: [ - { - imp_id: 0, - cpm: 1.062, - width: 300, - height: 250, - ad: 'ad-markup', - iurl: 'https://s.adroll.com/a/IYR/N36/IYRN366MFVDITBAGNNT5U6.jpg', - tl_source: 'tlx', + it('should get floor from floors module if available', function() { + const floorInfo = { + currency: 'USD', + floor: 1.99 + }; + bidRequests[0].getFloor = () => floorInfo; + const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); + expect(request.data.imp[0].floor).to.equal(1.99); + }); + it('should send fpd on root level ext if kvps are available', function() { + const sens = null; + const category = ['news', 'weather', 'hurricane']; + const pmp_elig = 'true'; + const fpd = { + context: { + pmp_elig, + category, + }, + user: { + sens, } - ], - refererInfo: { - referer: 'https://examplereferer.com' - }, - gdprConsent: { - consentString: GDPR_CONSENT_STR, - gdprApplies: true } - }; - - it('should get correct bid response', function () { - let expectedResponse = [ - { - requestId: '3db3773286ee59', - cpm: 1.062, - width: 300, - height: 250, - netRevenue: true, - ad: 'ad-markup', - creativeId: 29681110, - dealId: '', - currency: 'USD', - ttl: 33, - tl_source: 'tlx', - } - ]; - let result = tripleliftAdapterSpec.interpretResponse(response, {bidderRequest}); - expect(result).to.have.length(1); - expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + sandbox.stub(config, 'getConfig').callsFake(key => { + const config = { + fpd + }; + return utils.deepAccess(config, key); + }); + const request = tripleliftAdapterSpec.buildRequests(bidRequests, bidderRequest); + const { data: payload } = request; + expect(payload.ext.fpd).to.not.haveOwnProperty('sens'); + expect(payload.ext.fpd).to.haveOwnProperty('category'); + expect(payload.ext.fpd).to.haveOwnProperty('pmp_elig'); }); + }); - it('should return multiple responses to support SRA', function () { - let response = { + describe('interpretResponse', function () { + let response, bidderRequest; + this.beforeEach(() => { + response = { body: { bids: [ { @@ -374,20 +444,19 @@ describe('triplelift adapter', function () { ad: 'ad-markup', iurl: 'https://s.adroll.com/a/IYR/N36/IYRN366MFVDITBAGNNT5U6.jpg', tl_source: 'tlx', + advertiser_name: 'fake advertiser name' }, { - imp_id: 0, - cpm: 1.9, - width: 300, - height: 600, - ad: 'ad-markup-2', - iurl: 'https://s.adroll.com/a/IYR/N36/IYRN366MFVDITBAGNNT5U6.jpg', - tl_source: 'tlx', + imp_id: 1, + crid: '10092_76480_i2j6qm8u', + cpm: 9.99, + ad: 'The Trade Desk', + tlx_source: 'hdx' } ] } }; - let bidderRequest = { + bidderRequest = { bidderCode: 'triplelift', auctionId: 'a7ebcd1d-66ff-4b5c-a82c-6a21a6ee5a18', bidderRequestId: '5c55612f99bc11', @@ -396,19 +465,33 @@ describe('triplelift adapter', function () { imp_id: 0, cpm: 1.062, width: 300, - height: 600, + height: 250, ad: 'ad-markup', iurl: 'https://s.adroll.com/a/IYR/N36/IYRN366MFVDITBAGNNT5U6.jpg', tl_source: 'tlx', + mediaTypes: { + banner: { + sizes: [ + [970, 250], + [1, 1] + ] + } + }, + bidId: '30b31c1838de1e', }, { - imp_id: 0, - cpm: 1.9, - width: 300, - height: 250, - ad: 'ad-markup-2', - iurl: 'https://s.adroll.com/a/IYR/N36/IYRN366MFVDITBAGNNT5U6.jpg', - tl_source: 'tlx', + imp_id: 1, + crid: '10092_76480_i2j6qm8u', + cpm: 9.99, + ad: 'The Trade Desk', + tlx_source: 'hdx', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480] + } + }, + bidId: '30b31c1838de1e', } ], refererInfo: { @@ -419,9 +502,57 @@ describe('triplelift adapter', function () { gdprApplies: true } }; + }) + + it('should get correct bid response', function () { + let expectedResponse = [ + { + requestId: '30b31c1838de1e', + cpm: 1.062, + width: 300, + height: 250, + netRevenue: true, + ad: 'ad-markup', + creativeId: 29681110, + dealId: '', + currency: 'USD', + ttl: 33, + tl_source: 'tlx', + meta: {} + }, + { + requestId: '30b31c1838de1e', + cpm: 1.062, + width: 300, + height: 250, + netRevenue: true, + ad: 'The Trade Desk', + creativeId: 29681110, + dealId: '', + currency: 'USD', + ttl: 33, + tl_source: 'hdx', + mediaType: 'video', + vastXml: 'The Trade Desk', + meta: {} + } + ]; + let result = tripleliftAdapterSpec.interpretResponse(response, {bidderRequest}); + expect(result).to.have.length(2); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + expect(Object.keys(result[1])).to.have.members(Object.keys(expectedResponse[1])); + }); + + it('should return multiple responses to support SRA', function () { let result = tripleliftAdapterSpec.interpretResponse(response, {bidderRequest}); expect(result).to.have.length(2); }); + + it('should include the advertiser name in the meta field if available', function () { + let result = tripleliftAdapterSpec.interpretResponse(response, {bidderRequest}); + expect(result[0].meta.advertiserName).to.equal('fake advertiser name') + expect(result[1].meta).to.not.have.key('advertiserName'); + }); }); describe('getUserSyncs', function() { diff --git a/test/spec/modules/truereachBidAdapter_spec.js b/test/spec/modules/truereachBidAdapter_spec.js new file mode 100644 index 00000000000..5fe053ceb91 --- /dev/null +++ b/test/spec/modules/truereachBidAdapter_spec.js @@ -0,0 +1,84 @@ +import { expect } from 'chai'; +import { spec } from 'modules/truereachBidAdapter.js'; + +describe('truereachBidAdapterTests', function () { + it('validate_pub_params', function () { + expect(spec.isBidRequestValid({ + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bidder: 'truereach', + params: { + site_id: '0142010a-8400-1b01-72cb-a553b9000009', + bidfloor: 0.1 + } + })).to.equal(true); + }); + + it('validate_generated_params', function () { + let bidRequestData = [{ + bidId: '34ce3f3b15190a', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bidder: 'truereach', + params: { + site_id: '0142010a-8400-1b01-72cb-a553b9000009', + bidfloor: 0.1 + }, + sizes: [[300, 250]] + }]; + + let request = spec.buildRequests(bidRequestData, {}); + let req_data = request.data; + + expect(request.method).to.equal('POST'); + expect(req_data.imp[0].id).to.equal('34ce3f3b15190a'); + expect(req_data.imp[0].banner.w).to.equal(300); + expect(req_data.imp[0].banner.h).to.equal(250); + expect(req_data.imp[0].bidfloor).to.equal(0.1); + }); + + it('validate_response_params', function () { + let serverResponse = { + body: { + 'id': '34ce3f3b15190a', + 'seatbid': [{ + 'bid': [{ + 'id': '0142010a-8400-0801-72dc-04a99e6f7fc0:1ed', + 'impid': '34ce3f3b15190a', + 'price': 2.55, + 'adm': '', + 'adid': '493', + 'adomain': ['https://www.momagic.com/'], + 'iurl': '', + 'cid': '260', + 'crid': '0142010a-8400-1b01-72cb-afb296000012', + 'w': 300, + 'h': 250 + }] + }], + 'bidid': '0142010a-8400-0801-72dc-04a99e6f7fc1', + 'cur': 'USD' + } + }; + + let bids = spec.interpretResponse(serverResponse, {}); + expect(bids).to.have.lengthOf(1); + let bid = bids[0]; + expect(bid.requestId).to.equal('34ce3f3b15190a'); + expect(bid.cpm).to.equal(2.55); + expect(bid.currency).to.equal('USD'); + expect(bid.width).to.equal(300); + expect(bid.height).to.equal(250); + expect(bid.ad).to.equal(''); + expect(bid.ttl).to.equal(180); + expect(bid.creativeId).to.equal('0142010a-8400-1b01-72cb-afb296000012'); + expect(bid.netRevenue).to.equal(false); + expect(bid.meta.advertiserDomains[0]).to.equal('https://www.momagic.com/'); + }); +}); diff --git a/test/spec/modules/ucfunnelBidAdapter_spec.js b/test/spec/modules/ucfunnelBidAdapter_spec.js index 70b273cfb8c..b5f29287f81 100644 --- a/test/spec/modules/ucfunnelBidAdapter_spec.js +++ b/test/spec/modules/ucfunnelBidAdapter_spec.js @@ -250,4 +250,22 @@ describe('ucfunnel Adapter', function () { }); }); }); + + describe('cookie sync', function () { + describe('cookie sync iframe', function () { + const result = spec.getUserSyncs({'iframeEnabled': true}); + + it('should return cookie sync iframe info', function () { + expect(result[0].type).to.equal('iframe'); + expect(result[0].url).to.equal('https://cdn.aralego.net/ucfad/cookie/sync.html'); + }); + }); + describe('cookie sync image', function () { + const result = spec.getUserSyncs({'pixelEnabled': true}); + it('should return cookie sync image info', function () { + expect(result[0].type).to.equal('image'); + expect(result[0].url).to.equal('https://sync.aralego.com/idSync'); + }); + }); + }); }); diff --git a/test/spec/modules/undertoneBidAdapter_spec.js b/test/spec/modules/undertoneBidAdapter_spec.js index e4218019e0d..e8729965c50 100644 --- a/test/spec/modules/undertoneBidAdapter_spec.js +++ b/test/spec/modules/undertoneBidAdapter_spec.js @@ -24,13 +24,49 @@ const invalidBidReq = { auctionId: '9ad1fa8d-2297-4660-a018-b39945054746' }; -const bidReq = [{ +const videoBidReq = [{ adUnitCode: 'div-gpt-ad-1460505748561-0', bidder: BIDDER_CODE, params: { placementId: '10433394', + publisherId: 12345, + video: { + id: 123, + skippable: true, + playbackMethod: 2, + maxDuration: 30 + } + }, + mediaTypes: {video: { + context: 'outstream', + playerSize: [640, 480] + }}, + sizes: [[300, 250], [300, 600]], + bidId: '263be71e91dd9d', + auctionId: '9ad1fa8d-2297-4660-a018-b39945054746' +}, +{ + adUnitCode: 'div-gpt-ad-1460505748561-1', + bidder: BIDDER_CODE, + params: { + placementId: '10433395', publisherId: 12345 }, + mediaTypes: {video: { + context: 'outstream', + playerSize: [640, 480] + }}, + sizes: [[300, 250], [300, 600]], + bidId: '263be71e91dd9d', + auctionId: '9ad1fa8d-2297-4660-a018-b39945054746' +}]; +const bidReq = [{ + adUnitCode: 'div-gpt-ad-1460505748561-0', + bidder: BIDDER_CODE, + params: { + placementId: '10433394', + publisherId: 12345, + }, sizes: [[300, 250], [300, 600]], bidId: '263be71e91dd9d', auctionId: '9ad1fa8d-2297-4660-a018-b39945054746' @@ -58,7 +94,8 @@ const bidReqUserIds = [{ userId: { idl_env: '1111', tdid: '123456', - digitrustid: {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}} + digitrustid: {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}, + id5id: { uid: '1111' } } }, { @@ -147,6 +184,20 @@ const bidResArray = [ ttl: 360 } ]; +const bidVideoResponse = [ + { + ad: '', + bidRequestId: '263be71e91dd9d', + cpm: 100, + adId: '123abc', + currency: 'USD', + mediaType: 'video', + netRevenue: true, + width: 300, + height: 250, + ttl: 360 + } +]; let element; let sandbox; @@ -241,6 +292,23 @@ describe('Undertone Adapter', () => { expect(bid2.publisherId).to.equal(12345); expect(bid2.params).to.be.an('object'); }); + it('should send video fields correctly', function () { + const request = spec.buildRequests(videoBidReq, bidderReq); + const bidVideo = JSON.parse(request.data)['x-ut-hb-params'][0]; + const bidVideo2 = JSON.parse(request.data)['x-ut-hb-params'][1]; + + expect(bidVideo.mediaType).to.equal('video'); + expect(bidVideo.video).to.be.an('object'); + expect(bidVideo.video.playerSize).to.be.an('array'); + expect(bidVideo.video.streamType).to.equal('outstream'); + expect(bidVideo.video.playbackMethod).to.equal(2); + expect(bidVideo.video.maxDuration).to.equal(30); + expect(bidVideo.video.skippable).to.equal(true); + + expect(bidVideo2.video.skippable).to.equal(null); + expect(bidVideo2.video.maxDuration).to.equal(null); + expect(bidVideo2.video.playbackMethod).to.equal(null); + }); it('should send all userIds data to server', function () { const request = spec.buildRequests(bidReqUserIds, bidderReq); const bidCommons = JSON.parse(request.data)['commons']; @@ -249,6 +317,7 @@ describe('Undertone Adapter', () => { expect(bidCommons.uids.tdid).to.equal('123456'); expect(bidCommons.uids.idl_env).to.equal('1111'); expect(bidCommons.uids.digitrustid.data.id).to.equal('DTID'); + expect(bidCommons.uids.id5id.uid).to.equal('1111'); }); it('should send page sizes sizes correctly', function () { const request = spec.buildRequests(bidReqUserIds, bidderReq); @@ -303,6 +372,13 @@ describe('Undertone Adapter', () => { it('should only use valid bid responses', () => { expect(spec.interpretResponse({ body: bidResArray }).length).to.equal(1); }); + + it('should detect video response', () => { + const videoResult = spec.interpretResponse({body: bidVideoResponse}); + const vbid = videoResult[0]; + + expect(vbid.mediaType).to.equal('video'); + }); }); describe('getUserSyncs', () => { diff --git a/test/spec/modules/userId_spec.js b/test/spec/modules/userId_spec.js index b48d0a9a98c..c4e52d9a121 100644 --- a/test/spec/modules/userId_spec.js +++ b/test/spec/modules/userId_spec.js @@ -1,11 +1,13 @@ import { attachIdSystem, auctionDelay, + coreStorage, init, requestBidsHook, + setStoredConsentData, + setStoredValue, setSubmoduleRegistry, - syncDelay, - coreStorage + syncDelay } from 'modules/userId/index.js'; import {createEidsArray} from 'modules/userId/eids.js'; import {config} from 'src/config.js'; @@ -13,21 +15,33 @@ import * as utils from 'src/utils.js'; import events from 'src/events.js'; import CONSTANTS from 'src/constants.json'; import {getGlobal} from 'src/prebidGlobal.js'; +import { + requestBidsHook as consentManagementRequestBidsHook, + resetConsentData, + setConsentConfig +} from 'modules/consentManagement.js'; import {unifiedIdSubmodule} from 'modules/unifiedIdSystem.js'; import {pubCommonIdSubmodule} from 'modules/pubCommonIdSystem.js'; import {britepoolIdSubmodule} from 'modules/britepoolIdSystem.js'; import {id5IdSubmodule} from 'modules/id5IdSystem.js'; import {identityLinkSubmodule} from 'modules/identityLinkIdSystem.js'; import {liveIntentIdSubmodule} from 'modules/liveIntentIdSystem.js'; +import {merkleIdSubmodule} from 'modules/merkleIdSystem.js'; import {netIdSubmodule} from 'modules/netIdSystem.js'; +import {intentIqIdSubmodule} from 'modules/intentIqIdSystem.js'; +import {zeotapIdPlusSubmodule} from 'modules/zeotapIdPlusIdSystem.js'; +import {sharedIdSubmodule} from 'modules/sharedIdSystem.js'; +import {haloIdSubmodule} from 'modules/haloIdSystem.js'; import {server} from 'test/mocks/xhr.js'; +import {pubProvidedIdSubmodule} from 'modules/pubProvidedSystem.js'; let assert = require('chai').assert; let expect = require('chai').expect; const EXPIRED_COOKIE_DATE = 'Thu, 01 Jan 1970 00:00:01 GMT'; +const CONSENT_LOCAL_STORAGE_NAME = '_pbjs_userid_consent_data'; -describe('User ID', function() { - function getConfigMock(configArr1, configArr2, configArr3, configArr4, configArr5, configArr6) { +describe('User ID', function () { + function getConfigMock(configArr1, configArr2, configArr3, configArr4, configArr5, configArr6, configArr7, configArr8, configArr9, configArr10) { return { userSync: { syncDelay: 0, @@ -37,16 +51,23 @@ describe('User ID', function() { (configArr3 && configArr3.length >= 3) ? getStorageMock.apply(null, configArr3) : null, (configArr4 && configArr4.length >= 3) ? getStorageMock.apply(null, configArr4) : null, (configArr5 && configArr5.length >= 3) ? getStorageMock.apply(null, configArr5) : null, - (configArr6 && configArr6.length >= 3) ? getStorageMock.apply(null, configArr6) : null - ].filter(i => i)} + (configArr6 && configArr6.length >= 3) ? getStorageMock.apply(null, configArr6) : null, + (configArr7 && configArr7.length >= 3) ? getStorageMock.apply(null, configArr7) : null, + (configArr8 && configArr8.length >= 3) ? getStorageMock.apply(null, configArr8) : null, + (configArr9 && configArr9.length >= 3) ? getStorageMock.apply(null, configArr9) : null, + (configArr10 && configArr10.length >= 3) ? getStorageMock.apply(null, configArr10) : null + ].filter(i => i) + } } } + function getStorageMock(name = 'pubCommonId', key = 'pubcid', type = 'cookie', expires = 30, refreshInSeconds) { - return { name: name, storage: { name: key, type: type, expires: expires, refreshInSeconds: refreshInSeconds } } + return {name: name, storage: {name: key, type: type, expires: expires, refreshInSeconds: refreshInSeconds}} } + function getConfigValueMock(name, value) { return { - userSync: { syncDelay: 0, userIds: [{ name: name, value: value }] } + userSync: {syncDelay: 0, userIds: [{name: name, value: value}]} } } @@ -62,21 +83,29 @@ describe('User ID', function() { function addConfig(cfg, name, value) { if (cfg && cfg.userSync && cfg.userSync.userIds) { cfg.userSync.userIds.forEach(element => { - if (element[name] !== undefined) { element[name] = Object.assign(element[name], value); } else { element[name] = value; } + if (element[name] !== undefined) { + element[name] = Object.assign(element[name], value); + } else { + element[name] = value; + } }); } return cfg; } - before(function() { + before(function () { coreStorage.setCookie('_pubcid_optout', '', EXPIRED_COOKIE_DATE); localStorage.removeItem('_pbjs_id_optout'); localStorage.removeItem('_pubcid_optout'); }); - describe('Decorate Ad Units', function() { - beforeEach(function() { + beforeEach(function () { + coreStorage.setCookie(CONSENT_LOCAL_STORAGE_NAME, '', EXPIRED_COOKIE_DATE); + }); + + describe('Decorate Ad Units', function () { + beforeEach(function () { coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('pubcid_alt', 'altpubcid200000', (new Date(Date.now() + 5000).toUTCString())); sinon.spy(coreStorage, 'setCookie'); @@ -88,7 +117,7 @@ describe('User ID', function() { coreStorage.setCookie.restore(); }); - after(function() { + after(function () { coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('pubcid_alt', '', EXPIRED_COOKIE_DATE); }); @@ -106,7 +135,9 @@ describe('User ID', function() { init(config); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'])); - requestBidsHook(config => { innerAdUnits1 = config.adUnits }, {adUnits: adUnits1}); + requestBidsHook(config => { + innerAdUnits1 = config.adUnits + }, {adUnits: adUnits1}); pubcid = coreStorage.getCookie('pubcid'); // cookies is created after requestbidHook innerAdUnits1.forEach(unit => { @@ -120,7 +151,9 @@ describe('User ID', function() { }); }); - requestBidsHook(config => { innerAdUnits2 = config.adUnits }, {adUnits: adUnits2}); + requestBidsHook(config => { + innerAdUnits2 = config.adUnits + }, {adUnits: adUnits2}); assert.deepEqual(innerAdUnits1, innerAdUnits2); }); @@ -135,7 +168,9 @@ describe('User ID', function() { setSubmoduleRegistry([pubCommonIdSubmodule]); init(config); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'])); - requestBidsHook((config) => { innerAdUnits1 = config.adUnits }, {adUnits: adUnits1}); + requestBidsHook((config) => { + innerAdUnits1 = config.adUnits + }, {adUnits: adUnits1}); pubcid1 = coreStorage.getCookie('pubcid'); // get first cookie coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); // erase cookie @@ -153,7 +188,9 @@ describe('User ID', function() { setSubmoduleRegistry([pubCommonIdSubmodule]); init(config); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'])); - requestBidsHook((config) => { innerAdUnits2 = config.adUnits }, {adUnits: adUnits2}); + requestBidsHook((config) => { + innerAdUnits2 = config.adUnits + }, {adUnits: adUnits2}); pubcid2 = coreStorage.getCookie('pubcid'); // get second cookie @@ -178,7 +215,9 @@ describe('User ID', function() { setSubmoduleRegistry([pubCommonIdSubmodule]); init(config); config.setConfig(getConfigMock(['pubCommonId', 'pubcid_alt', 'cookie'])); - requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); innerAdUnits.forEach((unit) => { unit.bids.forEach((bid) => { expect(bid).to.have.deep.nested.property('userId.pubcid'); @@ -189,8 +228,9 @@ describe('User ID', function() { }); }); }); - // Because the cookie exists already, there should be no setCookie call by default - expect(coreStorage.setCookie.callCount).to.equal(0); + // Because the cookie exists already, there should be no setCookie call by default; the only setCookie call is + // to store consent data + expect(coreStorage.setCookie.callCount).to.equal(1); }); it('Extend cookie', function () { @@ -202,7 +242,9 @@ describe('User ID', function() { setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule]); init(config); config.setConfig(customConfig); - requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); innerAdUnits.forEach((unit) => { unit.bids.forEach((bid) => { expect(bid).to.have.deep.nested.property('userId.pubcid'); @@ -213,8 +255,9 @@ describe('User ID', function() { }); }); }); - // Because extend is true, the cookie will be updated even if it exists already - expect(coreStorage.setCookie.callCount).to.equal(1); + // Because extend is true, the cookie will be updated even if it exists already. The second setCookie call + // is for storing consentData + expect(coreStorage.setCookie.callCount).to.equal(2); }); it('Disable auto create', function () { @@ -226,17 +269,20 @@ describe('User ID', function() { setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule]); init(config); config.setConfig(customConfig); - requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); innerAdUnits.forEach((unit) => { unit.bids.forEach((bid) => { expect(bid).to.not.have.deep.nested.property('userId.pubcid'); expect(bid).to.not.have.deep.nested.property('userIdAsEids'); }); }); - expect(coreStorage.setCookie.callCount).to.equal(0); + // setCookie is called once in order to store consentData + expect(coreStorage.setCookie.callCount).to.equal(1); }); - it('pbjs.getUserIds', function() { + it('pbjs.getUserIds', function () { setSubmoduleRegistry([pubCommonIdSubmodule]); init(config); config.setConfig({ @@ -251,7 +297,7 @@ describe('User ID', function() { expect((getGlobal()).getUserIds()).to.deep.equal({pubcid: '11111'}); }); - it('pbjs.getUserIdsAsEids', function() { + it('pbjs.getUserIdsAsEids', function () { setSubmoduleRegistry([pubCommonIdSubmodule]); init(config); config.setConfig({ @@ -315,7 +361,7 @@ describe('User ID', function() { }); it('handles config with no usersync object', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule]); init(config); config.setConfig({}); // usersync is undefined, and no logInfo message for 'User ID - usersync config updated' @@ -323,14 +369,14 @@ describe('User ID', function() { }); it('handles config with empty usersync object', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule]); init(config); - config.setConfig({ userSync: {} }); + config.setConfig({userSync: {}}); expect(typeof utils.logInfo.args[0]).to.equal('undefined'); }); it('handles config with usersync and userIds that are empty objs', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule]); init(config); config.setConfig({ userSync: { @@ -341,16 +387,16 @@ describe('User ID', function() { }); it('handles config with usersync and userIds with empty names or that dont match a submodule.name', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, merkleIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule]); init(config); config.setConfig({ userSync: { userIds: [{ name: '', - value: { test: '1' } + value: {test: '1'} }, { name: 'foo', - value: { test: '1' } + value: {test: '1'} }] } }); @@ -358,54 +404,67 @@ describe('User ID', function() { }); it('config with 1 configurations should create 1 submodules', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, pubProvidedIdSubmodule]); init(config); config.setConfig(getConfigMock(['unifiedId', 'unifiedid', 'cookie'])); expect(utils.logInfo.args[0][0]).to.exist.and.to.equal('User ID - usersync config updated for 1 submodules'); }); - it('config with 7 configurations should result in 7 submodules add', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, liveIntentIdSubmodule, britepoolIdSubmodule, netIdSubmodule]); + it('config with 11 configurations should result in 12 submodules add', function () { + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, liveIntentIdSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule]); init(config); config.setConfig({ userSync: { syncDelay: 0, userIds: [{ + name: 'pubProvidedId' + }, { name: 'pubCommonId', value: {'pubcid': '11111'} }, { name: 'unifiedId', - storage: { name: 'unifiedid', type: 'cookie' } + storage: {name: 'unifiedid', type: 'cookie'} }, { name: 'id5Id', - storage: { name: 'id5id', type: 'cookie' } + storage: {name: 'id5id', type: 'cookie'} }, { name: 'identityLink', - storage: { name: 'idl_env', type: 'cookie' } + storage: {name: 'idl_env', type: 'cookie'} }, { name: 'liveIntentId', - storage: { name: '_li_pbid', type: 'cookie' } + storage: {name: '_li_pbid', type: 'cookie'} }, { name: 'britepoolId', - value: { 'primaryBPID': '279c0161-5152-487f-809e-05d7f7e653fd' } + value: {'primaryBPID': '279c0161-5152-487f-809e-05d7f7e653fd'} }, { name: 'netId', - storage: { name: 'netId', type: 'cookie' } + storage: {name: 'netId', type: 'cookie'} + }, { + name: 'sharedId', + storage: {name: 'sharedid', type: 'cookie'} + }, { + name: 'intentIqId', + storage: {name: 'intentIqId', type: 'cookie'} + }, { + name: 'haloId', + storage: {name: 'haloId', type: 'cookie'} + }, { + name: 'zeotapIdPlus' }] } }); - expect(utils.logInfo.args[0][0]).to.exist.and.to.equal('User ID - usersync config updated for 7 submodules'); + expect(utils.logInfo.args[0][0]).to.exist.and.to.equal('User ID - usersync config updated for 12 submodules'); }); it('config syncDelay updates module correctly', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule]); init(config); config.setConfig({ userSync: { syncDelay: 99, userIds: [{ name: 'unifiedId', - storage: { name: 'unifiedid', type: 'cookie' } + storage: {name: 'unifiedid', type: 'cookie'} }] } }); @@ -413,14 +472,14 @@ describe('User ID', function() { }); it('config auctionDelay updates module correctly', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule]); init(config); config.setConfig({ userSync: { auctionDelay: 100, userIds: [{ name: 'unifiedId', - storage: { name: 'unifiedid', type: 'cookie' } + storage: {name: 'unifiedid', type: 'cookie'} }] } }); @@ -428,14 +487,14 @@ describe('User ID', function() { }); it('config auctionDelay defaults to 0 if not a number', function () { - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule, pubProvidedIdSubmodule]); init(config); config.setConfig({ userSync: { auctionDelay: '', userIds: [{ name: 'unifiedId', - storage: { name: 'unifiedid', type: 'cookie' } + storage: {name: 'unifiedid', type: 'cookie'} }] } }); @@ -443,16 +502,17 @@ describe('User ID', function() { }); }); - describe('auction and user sync delays', function() { + describe('auction and user sync delays', function () { let sandbox; let adUnits; let mockIdCallback; let auctionSpy; - beforeEach(function() { + beforeEach(function () { sandbox = sinon.createSandbox(); sandbox.stub(global, 'setTimeout').returns(2); sandbox.stub(events, 'on'); + sandbox.stub(coreStorage, 'getCookie'); // remove cookie coreStorage.setCookie('MOCKID', '', EXPIRED_COOKIE_DATE); @@ -463,12 +523,12 @@ describe('User ID', function() { mockIdCallback = sandbox.stub(); const mockIdSystem = { name: 'mockId', - decode: function(value) { + decode: function (value) { return { 'mid': value['MOCKID'] }; }, - getId: function() { + getId: function () { const storedId = coreStorage.getCookie('MOCKID'); if (storedId) { return {id: {'MOCKID': storedId}}; @@ -488,13 +548,13 @@ describe('User ID', function() { sandbox.restore(); }); - it('delays auction if auctionDelay is set, timing out at auction delay', function() { + it('delays auction if auctionDelay is set, timing out at auction delay', function () { config.setConfig({ userSync: { auctionDelay: 33, syncDelay: 77, userIds: [{ - name: 'mockId', storage: { name: 'MOCKID', type: 'cookie' } + name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'} }] } }); @@ -521,13 +581,13 @@ describe('User ID', function() { events.on.called.should.equal(false); }); - it('delays auction if auctionDelay is set, continuing auction if ids are fetched before timing out', function(done) { + it('delays auction if auctionDelay is set, continuing auction if ids are fetched before timing out', function (done) { config.setConfig({ userSync: { auctionDelay: 33, syncDelay: 77, userIds: [{ - name: 'mockId', storage: { name: 'MOCKID', type: 'cookie' } + name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'} }] } }); @@ -560,12 +620,12 @@ describe('User ID', function() { events.on.called.should.equal(false); }); - it('does not delay auction if not set, delays id fetch after auction ends with syncDelay', function() { + it('does not delay auction if not set, delays id fetch after auction ends with syncDelay', function () { config.setConfig({ userSync: { syncDelay: 77, userIds: [{ - name: 'mockId', storage: { name: 'MOCKID', type: 'cookie' } + name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'} }] } }); @@ -596,12 +656,12 @@ describe('User ID', function() { mockIdCallback.calledOnce.should.equal(true); }); - it('does not delay user id sync after auction ends if set to 0', function() { + it('does not delay user id sync after auction ends if set to 0', function () { config.setConfig({ userSync: { syncDelay: 0, userIds: [{ - name: 'mockId', storage: { name: 'MOCKID', type: 'cookie' } + name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'} }] } }); @@ -625,15 +685,14 @@ describe('User ID', function() { mockIdCallback.calledOnce.should.equal(true); }); - it('does not delay auction if there are no ids to fetch', function() { - coreStorage.setCookie('MOCKID', JSON.stringify({'MOCKID': '123456778'}), new Date(Date.now() + 5000).toUTCString()); - + it('does not delay auction if there are no ids to fetch', function () { + coreStorage.getCookie.withArgs('MOCKID').returns('123456778'); config.setConfig({ - usersync: { - auctionDelay: 200, + userSync: { + auctionDelay: 33, syncDelay: 77, userIds: [{ - name: 'mockId', storage: { name: 'MOCKID', type: 'cookie' } + name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'} }] } }); @@ -649,21 +708,21 @@ describe('User ID', function() { }); }); - describe('Request bids hook appends userId to bid objs in adapters', function() { + describe('Request bids hook appends userId to bid objs in adapters', function () { let adUnits; - beforeEach(function() { + beforeEach(function () { adUnits = [getAdUnitMock()]; }); - it('test hook from pubcommonid cookie', function(done) { + it('test hook from pubcommonid cookie', function (done) { coreStorage.setCookie('pubcid', 'testpubcid', (new Date(Date.now() + 100000).toUTCString())); setSubmoduleRegistry([pubCommonIdSubmodule]); init(config); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.pubcid'); @@ -679,12 +738,12 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from pubcommonid config value object', function(done) { + it('test hook from pubcommonid config value object', function (done) { setSubmoduleRegistry([pubCommonIdSubmodule]); init(config); config.setConfig(getConfigValueMock('pubCommonId', {'pubcidvalue': 'testpubcidvalue'})); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.pubcidvalue'); @@ -696,7 +755,7 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from pubcommonid html5', function(done) { + it('test hook from pubcommonid html5', function (done) { // simulate existing browser local storage values localStorage.setItem('unifiedid_alt', JSON.stringify({'TDID': 'testunifiedid_alt'})); localStorage.setItem('unifiedid_alt_exp', ''); @@ -705,14 +764,14 @@ describe('User ID', function() { init(config); config.setConfig(getConfigMock(['unifiedId', 'unifiedid_alt', 'html5'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.tdid'); expect(bid.userId.tdid).to.equal('testunifiedid_alt'); expect(bid.userIdAsEids[0]).to.deep.equal({ source: 'adserver.org', - uids: [{id: 'testunifiedid_alt', atype: 1, ext: { rtiPartner: 'TDID' }}] + uids: [{id: 'testunifiedid_alt', atype: 1, ext: {rtiPartner: 'TDID'}}] }); }); }); @@ -722,7 +781,7 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from identityLink html5', function(done) { + it('test hook from identityLink html5', function (done) { // simulate existing browser local storage values localStorage.setItem('idl_env', 'AiGNC8Z5ONyZKSpIPf'); localStorage.setItem('idl_env_exp', ''); @@ -730,7 +789,7 @@ describe('User ID', function() { setSubmoduleRegistry([identityLinkSubmodule]); init(config); config.setConfig(getConfigMock(['identityLink', 'idl_env', 'html5'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.idl_env'); @@ -747,14 +806,14 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from identityLink cookie', function(done) { + it('test hook from identityLink cookie', function (done) { coreStorage.setCookie('idl_env', 'AiGNC8Z5ONyZKSpIPf', (new Date(Date.now() + 100000).toUTCString())); setSubmoduleRegistry([identityLinkSubmodule]); init(config); config.setConfig(getConfigMock(['identityLink', 'idl_env', 'cookie'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.idl_env'); @@ -770,7 +829,7 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from liveIntentId html5', function(done) { + it('test hook from liveIntentId html5', function (done) { // simulate existing browser local storage values localStorage.setItem('_li_pbid', JSON.stringify({'unifiedId': 'random-ls-identifier'})); localStorage.setItem('_li_pbid_exp', ''); @@ -778,7 +837,7 @@ describe('User ID', function() { setSubmoduleRegistry([liveIntentIdSubmodule]); init(config); config.setConfig(getConfigMock(['liveIntentId', '_li_pbid', 'html5'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.lipb'); @@ -795,14 +854,14 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from liveIntentId cookie', function(done) { + it('test hook from liveIntentId cookie', function (done) { coreStorage.setCookie('_li_pbid', JSON.stringify({'unifiedId': 'random-cookie-identifier'}), (new Date(Date.now() + 100000).toUTCString())); setSubmoduleRegistry([liveIntentIdSubmodule]); init(config); config.setConfig(getConfigMock(['liveIntentId', '_li_pbid', 'cookie'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.lipb'); @@ -818,48 +877,231 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from id5id cookies when refresh needed', function(done) { + it('test hook from sharedId html5', function (done) { + // simulate existing browser local storage values + localStorage.setItem('sharedid', JSON.stringify({'id': 'test_sharedId', 'ts': 1590525289611})); + localStorage.setItem('sharedid_exp', ''); + + setSubmoduleRegistry([sharedIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['sharedId', 'sharedid', 'html5'])); + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.sharedid'); + expect(bid.userId.sharedid).to.have.deep.nested.property('id'); + expect(bid.userId.sharedid).to.have.deep.nested.property('third'); + expect(bid.userId.sharedid).to.deep.equal({ + id: 'test_sharedId', + third: 'test_sharedId' + }); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'sharedid.org', + uids: [{ + id: 'test_sharedId', + atype: 1, + ext: { + third: 'test_sharedId' + } + }] + }); + }); + }); + localStorage.removeItem('sharedid'); + localStorage.removeItem('sharedid_exp'); + done(); + }, {adUnits}); + }); + + it('test hook from sharedId html5 (id not synced)', function (done) { // simulate existing browser local storage values - coreStorage.setCookie('id5id', JSON.stringify({'ID5ID': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); - coreStorage.setCookie('id5id_last', (new Date(Date.now() - 7200 * 1000)).toUTCString(), (new Date(Date.now() + 5000).toUTCString())); + localStorage.setItem('sharedid', JSON.stringify({'id': 'test_sharedId', 'ns': true, 'ts': 1590525289611})); + localStorage.setItem('sharedid_exp', ''); - sinon.stub(utils, 'logError'); // getId should failed with a logError as it has no partnerId + setSubmoduleRegistry([sharedIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['sharedId', 'sharedid', 'html5'])); + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.sharedid'); + expect(bid.userId.sharedid).to.have.deep.nested.property('id'); + expect(bid.userId.sharedid).to.deep.equal({ + id: 'test_sharedId' + }); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'sharedid.org', + uids: [{ + id: 'test_sharedId', + atype: 1 + }] + }); + }); + }); + localStorage.removeItem('sharedid'); + localStorage.removeItem('sharedid_exp'); + done(); + }, {adUnits}); + }); + it('test hook from sharedId cookie', function (done) { + coreStorage.setCookie('sharedid', JSON.stringify({ + 'id': 'test_sharedId', + 'ts': 1590525289611 + }), (new Date(Date.now() + 100000).toUTCString())); - setSubmoduleRegistry([id5IdSubmodule]); + setSubmoduleRegistry([sharedIdSubmodule]); init(config); - config.setConfig(getConfigMock(['id5Id', 'id5id', 'cookie', 10, 3600])); + config.setConfig(getConfigMock(['sharedId', 'sharedid', 'cookie'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { - expect(bid).to.have.deep.nested.property('userId.id5id'); - expect(bid.userId.id5id).to.equal('testid5id'); + expect(bid).to.have.deep.nested.property('userId.sharedid'); + expect(bid.userId.sharedid).to.have.deep.nested.property('id'); + expect(bid.userId.sharedid).to.have.deep.nested.property('third'); + expect(bid.userId.sharedid).to.deep.equal({ + id: 'test_sharedId', + third: 'test_sharedId' + }); expect(bid.userIdAsEids[0]).to.deep.equal({ - source: 'id5-sync.com', - uids: [{id: 'testid5id', atype: 1}] + source: 'sharedid.org', + uids: [{ + id: 'test_sharedId', + atype: 1, + ext: { + third: 'test_sharedId' + } + }] }); }); }); - sinon.assert.calledOnce(utils.logError); - coreStorage.setCookie('id5id', '', EXPIRED_COOKIE_DATE); - utils.logError.restore(); + coreStorage.setCookie('sharedid', '', EXPIRED_COOKIE_DATE); done(); }, {adUnits}); }); + it('test hook from sharedId cookie (id not synced) ', function (done) { + coreStorage.setCookie('sharedid', JSON.stringify({ + 'id': 'test_sharedId', + 'ns': true, + 'ts': 1590525289611 + }), (new Date(Date.now() + 100000).toUTCString())); + + setSubmoduleRegistry([sharedIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['sharedId', 'sharedid', 'cookie'])); - it('test hook from id5id value-based config', function(done) { - setSubmoduleRegistry([id5IdSubmodule]); + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.sharedid'); + expect(bid.userId.sharedid).to.have.deep.nested.property('id'); + expect(bid.userId.sharedid).to.deep.equal({ + id: 'test_sharedId' + }); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'sharedid.org', + uids: [{ + id: 'test_sharedId', + atype: 1 + }] + }); + }); + }); + coreStorage.setCookie('sharedid', '', EXPIRED_COOKIE_DATE); + done(); + }, {adUnits}); + }); + + it('test hook from pubProvidedId config params', function (done) { + setSubmoduleRegistry([pubProvidedIdSubmodule]); init(config); - config.setConfig(getConfigValueMock('id5Id', {'id5id': 'testid5id'})); + config.setConfig({ + userSync: { + syncDelay: 0, + userIds: [{ + name: 'pubProvidedId', + params: { + eids: [{ + source: 'example.com', + uids: [{ + id: 'value read from cookie or local storage', + ext: { + stype: 'ppuid' + } + }] + }, { + source: 'id-partner.com', + uids: [{ + id: 'value read from cookie or local storage', + ext: { + stype: 'dmp' + } + }] + }], + eidsFunction: function () { + return [{ + source: 'provider.com', + uids: [{ + id: 'value read from cookie or local storage', + ext: { + stype: 'sha256email' + } + }] + }] + } + } + } + ] + } + }); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { - expect(bid).to.have.deep.nested.property('userId.id5id'); - expect(bid.userId.id5id).to.equal('testid5id'); + expect(bid).to.have.deep.nested.property('userId.pubProvidedId'); + expect(bid.userId.pubProvidedId).to.deep.equal([{ + source: 'example.com', + uids: [{ + id: 'value read from cookie or local storage', + ext: { + stype: 'ppuid' + } + }] + }, { + source: 'id-partner.com', + uids: [{ + id: 'value read from cookie or local storage', + ext: { + stype: 'dmp' + } + }] + }, { + source: 'provider.com', + uids: [{ + id: 'value read from cookie or local storage', + ext: { + stype: 'sha256email' + } + }] + }]); + expect(bid.userIdAsEids[0]).to.deep.equal({ - source: 'id5-sync.com', - uids: [{id: 'testid5id', atype: 1}] + source: 'example.com', + uids: [{ + id: 'value read from cookie or local storage', + ext: { + stype: 'ppuid' + } + }] + }); + expect(bid.userIdAsEids[2]).to.deep.equal({ + source: 'provider.com', + uids: [{ + id: 'value read from cookie or local storage', + ext: { + stype: 'sha256email' + } + }] }); }); }); @@ -867,7 +1109,7 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from liveIntentId html5', function(done) { + it('test hook from liveIntentId html5', function (done) { // simulate existing browser local storage values localStorage.setItem('_li_pbid', JSON.stringify({'unifiedId': 'random-ls-identifier', 'segments': ['123']})); localStorage.setItem('_li_pbid_exp', ''); @@ -875,7 +1117,7 @@ describe('User ID', function() { setSubmoduleRegistry([liveIntentIdSubmodule]); init(config); config.setConfig(getConfigMock(['liveIntentId', '_li_pbid', 'html5'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.lipb'); @@ -894,14 +1136,17 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from liveIntentId cookie', function(done) { - coreStorage.setCookie('_li_pbid', JSON.stringify({'unifiedId': 'random-cookie-identifier', 'segments': ['123']}), (new Date(Date.now() + 100000).toUTCString())); + it('test hook from liveIntentId cookie', function (done) { + coreStorage.setCookie('_li_pbid', JSON.stringify({ + 'unifiedId': 'random-cookie-identifier', + 'segments': ['123'] + }), (new Date(Date.now() + 100000).toUTCString())); setSubmoduleRegistry([liveIntentIdSubmodule]); init(config); config.setConfig(getConfigMock(['liveIntentId', '_li_pbid', 'cookie'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.lipb'); @@ -919,7 +1164,7 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from britepoolid cookies', function(done) { + it('test hook from britepoolid cookies', function (done) { // simulate existing browser local storage values coreStorage.setCookie('britepoolid', JSON.stringify({'primaryBPID': '279c0161-5152-487f-809e-05d7f7e653fd'}), (new Date(Date.now() + 5000).toUTCString())); @@ -927,7 +1172,7 @@ describe('User ID', function() { init(config); config.setConfig(getConfigMock(['britepoolId', 'britepoolid', 'cookie'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.britepoolid'); @@ -943,7 +1188,7 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook from netId cookies', function(done) { + it('test hook from netId cookies', function (done) { // simulate existing browser local storage values coreStorage.setCookie('netId', JSON.stringify({'netId': 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg'}), (new Date(Date.now() + 5000).toUTCString())); @@ -951,7 +1196,7 @@ describe('User ID', function() { init(config); config.setConfig(getConfigMock(['netId', 'netId', 'cookie'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid).to.have.deep.nested.property('userId.netId'); @@ -967,24 +1212,133 @@ describe('User ID', function() { }, {adUnits}); }); - it('test hook when pubCommonId, unifiedId, id5Id, identityLink, britepoolId and netId have data to pass', function(done) { + it('test hook from intentIqId cookies', function (done) { + // simulate existing browser local storage values + coreStorage.setCookie('intentIqId', 'abcdefghijk', (new Date(Date.now() + 5000).toUTCString())); + + setSubmoduleRegistry([intentIqIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['intentIqId', 'intentIqId', 'cookie'])); + + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.intentIqId'); + expect(bid.userId.intentIqId).to.equal('abcdefghijk'); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'intentiq.com', + uids: [{id: 'abcdefghijk', atype: 1}] + }); + }); + }); + coreStorage.setCookie('intentIqId', '', EXPIRED_COOKIE_DATE); + done(); + }, {adUnits}); + }); + + it('test hook from haloId html5', function (done) { + // simulate existing browser local storage values + localStorage.setItem('haloId', JSON.stringify({'haloId': 'random-ls-identifier'})); + localStorage.setItem('haloId_exp', ''); + + setSubmoduleRegistry([haloIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['haloId', 'haloId', 'html5'])); + + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.haloId'); + expect(bid.userId.haloId).to.equal('random-ls-identifier'); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'audigent.com', + uids: [{id: 'random-ls-identifier', atype: 1}] + }); + }); + }); + localStorage.removeItem('haloId'); + localStorage.removeItem('haloId_exp', ''); + done(); + }, {adUnits}); + }); + + it('test hook from merkleId cookies', function (done) { + // simulate existing browser local storage values + coreStorage.setCookie('merkleId', JSON.stringify({'ppid': {'id': 'testmerkleId'}}), (new Date(Date.now() + 5000).toUTCString())); + + setSubmoduleRegistry([merkleIdSubmodule]); + init(config); + config.setConfig(getConfigMock(['merkleId', 'merkleId', 'cookie'])); + + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.merkleId'); + expect(bid.userId.merkleId).to.equal('testmerkleId'); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'merkleinc.com', + uids: [{id: 'testmerkleId', atype: 1}] + }); + }); + }); + coreStorage.setCookie('merkleId', '', EXPIRED_COOKIE_DATE); + done(); + }, {adUnits}); + }); + + it('test hook from zeotapIdPlus cookies', function (done) { + // simulate existing browser local storage values + coreStorage.setCookie('IDP', btoa(JSON.stringify('abcdefghijk')), (new Date(Date.now() + 5000).toUTCString())); + + setSubmoduleRegistry([zeotapIdPlusSubmodule]); + init(config); + config.setConfig(getConfigMock(['zeotapIdPlus', 'IDP', 'cookie'])); + + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.IDP'); + expect(bid.userId.IDP).to.equal('abcdefghijk'); + expect(bid.userIdAsEids[0]).to.deep.equal({ + source: 'zeotap.com', + uids: [{id: 'abcdefghijk', atype: 1}] + }); + }); + }); + coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); + done(); + }, {adUnits}); + }); + + it('test hook when pubCommonId, unifiedId, id5Id, identityLink, britepoolId, intentIqId, zeotapIdPlus, sharedId, netId and haloId have data to pass', function (done) { coreStorage.setCookie('pubcid', 'testpubcid', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('unifiedid', JSON.stringify({'TDID': 'testunifiedid'}), (new Date(Date.now() + 5000).toUTCString())); - coreStorage.setCookie('id5id', JSON.stringify({'ID5ID': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('id5id', JSON.stringify({'universal_uid': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('idl_env', 'AiGNC8Z5ONyZKSpIPf', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('britepoolid', JSON.stringify({'primaryBPID': 'testbritepoolid'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('netId', JSON.stringify({'netId': 'testnetId'}), (new Date(Date.now() + 5000).toUTCString())); - - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule]); + coreStorage.setCookie('intentIqId', 'testintentIqId', (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('IDP', btoa(JSON.stringify('zeotapId')), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('sharedid', JSON.stringify({ + 'id': 'test_sharedId', + 'ts': 1590525289611 + }), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('haloId', JSON.stringify({'haloId': 'testHaloId'}), (new Date(Date.now() + 5000).toUTCString())); + + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule]); init(config); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'], ['unifiedId', 'unifiedid', 'cookie'], ['id5Id', 'id5id', 'cookie'], ['identityLink', 'idl_env', 'cookie'], ['britepoolId', 'britepoolid', 'cookie'], - ['netId', 'netId', 'cookie'])); + ['netId', 'netId', 'cookie'], + ['sharedId', 'sharedid', 'cookie'], + ['intentIqId', 'intentIqId', 'cookie'], + ['zeotapIdPlus', 'IDP', 'cookie'], + ['haloId', 'haloId', 'cookie'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { // verify that the PubCommonId id data was copied to bid @@ -994,8 +1348,8 @@ describe('User ID', function() { expect(bid).to.have.deep.nested.property('userId.tdid'); expect(bid.userId.tdid).to.equal('testunifiedid'); // also check that Id5Id id data was copied to bid - expect(bid).to.have.deep.nested.property('userId.id5id'); - expect(bid.userId.id5id).to.equal('testid5id'); + expect(bid).to.have.deep.nested.property('userId.id5id.uid'); + expect(bid.userId.id5id.uid).to.equal('testid5id'); // check that identityLink id data was copied to bid expect(bid).to.have.deep.nested.property('userId.idl_env'); expect(bid.userId.idl_env).to.equal('AiGNC8Z5ONyZKSpIPf'); @@ -1005,7 +1359,21 @@ describe('User ID', function() { // also check that netId id data was copied to bid expect(bid).to.have.deep.nested.property('userId.netId'); expect(bid.userId.netId).to.equal('testnetId'); - expect(bid.userIdAsEids.length).to.equal(6); + expect(bid).to.have.deep.nested.property('userId.sharedid'); + expect(bid.userId.sharedid).to.deep.equal({ + id: 'test_sharedId', + third: 'test_sharedId' + }); + // also check that intentIqId id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.intentIqId'); + expect(bid.userId.intentIqId).to.equal('testintentIqId'); + // also check that zeotapIdPlus id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.IDP'); + expect(bid.userId.IDP).to.equal('zeotapId'); + // also check that haloId id was copied to bid + expect(bid).to.have.deep.nested.property('userId.haloId'); + expect(bid.userId.haloId).to.equal('testHaloId'); + expect(bid.userIdAsEids.length).to.equal(10); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -1014,17 +1382,28 @@ describe('User ID', function() { coreStorage.setCookie('idl_env', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('britepoolid', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('netId', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('sharedid', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('intentIqId', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('haloId', '', EXPIRED_COOKIE_DATE); done(); }, {adUnits}); }); - it('test hook when pubCommonId, unifiedId, id5Id, britepoolId and netId have their modules added before and after init', function(done) { + it('test hook when pubCommonId, unifiedId, id5Id, britepoolId, intentIqId, zeotapIdPlus, sharedId, netId and haloId have their modules added before and after init', function (done) { coreStorage.setCookie('pubcid', 'testpubcid', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('unifiedid', JSON.stringify({'TDID': 'cookie-value-add-module-variations'}), new Date(Date.now() + 5000).toUTCString()); - coreStorage.setCookie('id5id', JSON.stringify({'ID5ID': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('id5id', JSON.stringify({'universal_uid': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('idl_env', 'AiGNC8Z5ONyZKSpIPf', new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('britepoolid', JSON.stringify({'primaryBPID': 'testbritepoolid'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('netId', JSON.stringify({'netId': 'testnetId'}), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('sharedid', JSON.stringify({ + 'id': 'test_sharedId', + 'ts': 1590525289611 + }), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('intentIqId', 'testintentIqId', (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('IDP', btoa(JSON.stringify('zeotapId')), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('haloId', JSON.stringify({'haloId': 'testHaloId'}), (new Date(Date.now() + 5000).toUTCString())); setSubmoduleRegistry([]); @@ -1039,15 +1418,23 @@ describe('User ID', function() { attachIdSystem(identityLinkSubmodule); attachIdSystem(britepoolIdSubmodule); attachIdSystem(netIdSubmodule); + attachIdSystem(sharedIdSubmodule); + attachIdSystem(intentIqIdSubmodule); + attachIdSystem(zeotapIdPlusSubmodule); + attachIdSystem(haloIdSubmodule); config.setConfig(getConfigMock(['pubCommonId', 'pubcid', 'cookie'], ['unifiedId', 'unifiedid', 'cookie'], ['id5Id', 'id5id', 'cookie'], ['identityLink', 'idl_env', 'cookie'], ['britepoolId', 'britepoolid', 'cookie'], - ['netId', 'netId', 'cookie'])); + ['netId', 'netId', 'cookie'], + ['sharedId', 'sharedid', 'cookie'], + ['intentIqId', 'intentIqId', 'cookie'], + ['zeotapIdPlus', 'IDP', 'cookie'], + ['haloId', 'haloId', 'cookie'])); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { // verify that the PubCommonId id data was copied to bid @@ -1057,8 +1444,8 @@ describe('User ID', function() { expect(bid).to.have.deep.nested.property('userId.tdid'); expect(bid.userId.tdid).to.equal('cookie-value-add-module-variations'); // also check that Id5Id id data was copied to bid - expect(bid).to.have.deep.nested.property('userId.id5id'); - expect(bid.userId.id5id).to.equal('testid5id'); + expect(bid).to.have.deep.nested.property('userId.id5id.uid'); + expect(bid.userId.id5id.uid).to.equal('testid5id'); // also check that identityLink id data was copied to bid expect(bid).to.have.deep.nested.property('userId.idl_env'); expect(bid.userId.idl_env).to.equal('AiGNC8Z5ONyZKSpIPf'); @@ -1068,7 +1455,22 @@ describe('User ID', function() { // also check that britepoolId id data was copied to bid expect(bid).to.have.deep.nested.property('userId.netId'); expect(bid.userId.netId).to.equal('testnetId'); - expect(bid.userIdAsEids.length).to.equal(6); + expect(bid).to.have.deep.nested.property('userId.sharedid'); + expect(bid.userId.sharedid).to.deep.equal({ + id: 'test_sharedId', + third: 'test_sharedId' + }); + // also check that intentIqId id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.intentIqId'); + expect(bid.userId.intentIqId).to.equal('testintentIqId'); + + // also check that zeotapIdPlus id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.IDP'); + expect(bid.userId.IDP).to.equal('zeotapId'); + // also check that haloId id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.haloId'); + expect(bid.userId.haloId).to.equal('testHaloId'); + expect(bid.userIdAsEids.length).to.equal(10); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -1077,39 +1479,82 @@ describe('User ID', function() { coreStorage.setCookie('idl_env', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('britepoolid', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('netId', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('sharedid', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('intentIqId', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('haloId', '', EXPIRED_COOKIE_DATE); done(); }, {adUnits}); }); - it('should add new id system ', function(done) { + it('test hook when sharedId(opted out) have their modules added before and after init', function (done) { + coreStorage.setCookie('sharedid', JSON.stringify({ + 'id': '00000000000000000000000000', + 'ts': 1590525289611 + }), (new Date(Date.now() + 5000).toUTCString())); + + setSubmoduleRegistry([]); + init(config); + + attachIdSystem(sharedIdSubmodule); + + config.setConfig(getConfigMock(['sharedId', 'sharedid', 'cookie'])); + + requestBidsHook(function () { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid.userIdAsEids).to.be.undefined; + }); + }); + coreStorage.setCookie('sharedid', '', EXPIRED_COOKIE_DATE); + done(); + }, {adUnits}); + }); + + it('should add new id system ', function (done) { coreStorage.setCookie('pubcid', 'testpubcid', (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('unifiedid', JSON.stringify({'TDID': 'cookie-value-add-module-variations'}), new Date(Date.now() + 5000).toUTCString()); - coreStorage.setCookie('id5id', JSON.stringify({'ID5ID': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('id5id', JSON.stringify({'universal_uid': 'testid5id'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('idl_env', 'AiGNC8Z5ONyZKSpIPf', new Date(Date.now() + 5000).toUTCString()); coreStorage.setCookie('britepoolid', JSON.stringify({'primaryBPID': 'testbritepoolid'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('netId', JSON.stringify({'netId': 'testnetId'}), new Date(Date.now() + 5000).toUTCString()); + coreStorage.setCookie('sharedid', JSON.stringify({ + 'id': 'test_sharedId', + 'ts': 1590525289611 + }), new Date(Date.now() + 5000).toUTCString()); + coreStorage.setCookie('intentIqId', 'testintentIqId', (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('IDP', btoa(JSON.stringify('zeotapId')), (new Date(Date.now() + 5000).toUTCString())); + coreStorage.setCookie('haloId', JSON.stringify({'haloId': 'testHaloId'}), (new Date(Date.now() + 5000).toUTCString())); coreStorage.setCookie('MOCKID', JSON.stringify({'MOCKID': '123456778'}), new Date(Date.now() + 5000).toUTCString()); - setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule]); + setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule, id5IdSubmodule, identityLinkSubmodule, britepoolIdSubmodule, netIdSubmodule, sharedIdSubmodule, intentIqIdSubmodule, zeotapIdPlusSubmodule, haloIdSubmodule]); init(config); config.setConfig({ userSync: { syncDelay: 0, userIds: [{ - name: 'pubCommonId', storage: { name: 'pubcid', type: 'cookie' } + name: 'pubCommonId', storage: {name: 'pubcid', type: 'cookie'} + }, { + name: 'unifiedId', storage: {name: 'unifiedid', type: 'cookie'} + }, { + name: 'id5Id', storage: {name: 'id5id', type: 'cookie'} + }, { + name: 'identityLink', storage: {name: 'idl_env', type: 'cookie'} }, { - name: 'unifiedId', storage: { name: 'unifiedid', type: 'cookie' } + name: 'britepoolId', storage: {name: 'britepoolid', type: 'cookie'} }, { - name: 'id5Id', storage: { name: 'id5id', type: 'cookie' } + name: 'netId', storage: {name: 'netId', type: 'cookie'} }, { - name: 'identityLink', storage: { name: 'idl_env', type: 'cookie' } + name: 'sharedId', storage: {name: 'sharedid', type: 'cookie'} }, { - name: 'britepoolId', storage: { name: 'britepoolid', type: 'cookie' } + name: 'intentIqId', storage: {name: 'intentIqId', type: 'cookie'} }, { - name: 'netId', storage: { name: 'netId', type: 'cookie' } + name: 'zeotapIdPlus' }, { - name: 'mockId', storage: { name: 'MOCKID', type: 'cookie' } + name: 'haloId', storage: {name: 'haloId', type: 'cookie'} + }, { + name: 'mockId', storage: {name: 'MOCKID', type: 'cookie'} }] } }); @@ -1117,18 +1562,18 @@ describe('User ID', function() { // Add new submodule named 'mockId' attachIdSystem({ name: 'mockId', - decode: function(value) { + decode: function (value) { return { 'mid': value['MOCKID'] }; }, - getId: function(params, storedId) { + getId: function (params, storedId) { if (storedId) return {}; return {id: {'MOCKID': '1234'}}; } }); - requestBidsHook(function() { + requestBidsHook(function () { adUnits.forEach(unit => { unit.bids.forEach(bid => { // check PubCommonId id data was copied to bid @@ -1138,8 +1583,8 @@ describe('User ID', function() { expect(bid).to.have.deep.nested.property('userId.tdid'); expect(bid.userId.tdid).to.equal('cookie-value-add-module-variations'); // also check that Id5Id id data was copied to bid - expect(bid).to.have.deep.nested.property('userId.id5id'); - expect(bid.userId.id5id).to.equal('testid5id'); + expect(bid).to.have.deep.nested.property('userId.id5id.uid'); + expect(bid.userId.id5id.uid).to.equal('testid5id'); // also check that identityLink id data was copied to bid expect(bid).to.have.deep.nested.property('userId.idl_env'); expect(bid.userId.idl_env).to.equal('AiGNC8Z5ONyZKSpIPf'); @@ -1149,10 +1594,25 @@ describe('User ID', function() { // check MockId data was copied to bid expect(bid).to.have.deep.nested.property('userId.netId'); expect(bid.userId.netId).to.equal('testnetId'); + // also check that sharedId id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.sharedid'); + expect(bid.userId.sharedid).to.deep.equal({ + id: 'test_sharedId', + third: 'test_sharedId' + }); // check MockId data was copied to bid expect(bid).to.have.deep.nested.property('userId.mid'); expect(bid.userId.mid).to.equal('123456778'); - expect(bid.userIdAsEids.length).to.equal(6);// mid is unknown for eids.js + // also check that intentIqId id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.intentIqId'); + expect(bid.userId.intentIqId).to.equal('testintentIqId'); + // also check that zeotapIdPlus id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.IDP'); + expect(bid.userId.IDP).to.equal('zeotapId'); + // also check that haloId id data was copied to bid + expect(bid).to.have.deep.nested.property('userId.haloId'); + expect(bid.userId.haloId).to.equal('testHaloId'); + expect(bid.userIdAsEids.length).to.equal(10); }); }); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -1161,14 +1621,18 @@ describe('User ID', function() { coreStorage.setCookie('idl_env', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('britepoolid', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('netId', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('sharedid', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('intentIqId', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('IDP', '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie('haloId', '', EXPIRED_COOKIE_DATE); coreStorage.setCookie('MOCKID', '', EXPIRED_COOKIE_DATE); done(); }, {adUnits}); }); }); - describe('callbacks at the end of auction', function() { - beforeEach(function() { + describe('callbacks at the end of auction', function () { + beforeEach(function () { sinon.stub(events, 'getEvents').returns([]); sinon.stub(utils, 'triggerPixel'); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -1176,7 +1640,7 @@ describe('User ID', function() { coreStorage.setCookie('_parrable_eid', '', EXPIRED_COOKIE_DATE); }); - afterEach(function() { + afterEach(function () { events.getEvents.restore(); utils.triggerPixel.restore(); coreStorage.setCookie('pubcid', '', EXPIRED_COOKIE_DATE); @@ -1193,7 +1657,9 @@ describe('User ID', function() { setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule]); init(config); config.setConfig(customCfg); - requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); expect(utils.triggerPixel.called).to.be.false; events.emit(CONSTANTS.EVENTS.AUCTION_END, {}); @@ -1209,7 +1675,9 @@ describe('User ID', function() { setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule]); init(config); config.setConfig(customCfg); - requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); expect(server.requests).to.be.empty; events.emit(CONSTANTS.EVENTS.AUCTION_END, {}); @@ -1225,87 +1693,234 @@ describe('User ID', function() { setSubmoduleRegistry([pubCommonIdSubmodule, unifiedIdSubmodule]); init(config); config.setConfig(customCfg); - requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); expect(server.requests).to.be.empty; events.emit(CONSTANTS.EVENTS.AUCTION_END, {}); expect(server.requests[0].url).to.equal('https://match.adsrvr.org/track/rid?ttd_pid=rubicon&fmt=json'); }); + }); - it('callback for submodules that always need to refresh stored id', function(done) { - let adUnits = [getAdUnitMock()]; - let innerAdUnits; - const parrableStoredId = '01.1111111111.test-eid'; - const parrableRefreshedId = '02.2222222222.test-eid'; - coreStorage.setCookie('_parrable_eid', parrableStoredId, (new Date(Date.now() + 5000).toUTCString())); - - const parrableIdSubmoduleMock = { - name: 'parrableId', - decode: function(value) { - return { 'parrableid': value }; + describe('Set cookie behavior', function () { + let coreStorageSpy; + beforeEach(function () { + coreStorageSpy = sinon.spy(coreStorage, 'setCookie'); + }); + afterEach(function () { + coreStorageSpy.restore(); + }); + it('should allow submodules to override the domain', function () { + const submodule = { + submodule: { + domainOverride: function () { + return 'foo.com' + } }, - getId: function() { - return { - callback: function(cb) { - cb(parrableRefreshedId); - } - }; + config: { + storage: { + type: 'cookie' + } } - }; + } + setStoredValue(submodule, 'bar'); + expect(coreStorage.setCookie.getCall(0).args[4]).to.equal('foo.com'); + }); - const parrableConfigMock = { - userSync: { - syncDelay: 0, - userIds: [{ - name: 'parrableId', - storage: { - type: 'cookie', - name: '_parrable_eid' - } - }] + it('should pass null for domain if submodule does not override the domain', function () { + const submodule = { + submodule: {}, + config: { + storage: { + type: 'cookie' + } } - }; + } + setStoredValue(submodule, 'bar'); + expect(coreStorage.setCookie.getCall(0).args[4]).to.equal(null); + }); + }); + + describe('Consent changes determine getId refreshes', function () { + let expStr; + let adUnits; - setSubmoduleRegistry([parrableIdSubmoduleMock]); - attachIdSystem(parrableIdSubmoduleMock); + const mockIdCookieName = 'MOCKID'; + let mockGetId = sinon.stub(); + let mockDecode = sinon.stub(); + let mockExtendId = sinon.stub(); + const mockIdSystem = { + name: 'mockId', + getId: mockGetId, + decode: mockDecode, + extendId: mockExtendId + }; + const userIdConfig = { + userSync: { + userIds: [{ + name: 'mockId', + storage: { + name: 'MOCKID', + type: 'cookie', + refreshInSeconds: 30 + } + }], + auctionDelay: 5 + } + }; + + let cmpStub; + let testConsentData; + const consentConfig = { + cmpApi: 'iab', + timeout: 7500, + allowAuctionWithoutConsent: false + }; + + const sharedBeforeFunction = function () { + // clear cookies + expStr = (new Date(Date.now() + 25000).toUTCString()); + coreStorage.setCookie(mockIdCookieName, '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie(`${mockIdCookieName}_last`, '', EXPIRED_COOKIE_DATE); + coreStorage.setCookie(CONSENT_LOCAL_STORAGE_NAME, '', EXPIRED_COOKIE_DATE); + + // init + adUnits = [getAdUnitMock()]; init(config); - config.setConfig(parrableConfigMock); - // make first bid request, should use stored id value - requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); - innerAdUnits.forEach(unit => { - unit.bids.forEach(bid => { - expect(bid).to.have.deep.nested.property('userId.parrableid'); - expect(bid.userId.parrableid).to.equal(parrableStoredId); - expect(bid.userIdAsEids[0]).to.deep.equal({ - source: 'parrable.com', - uids: [{id: parrableStoredId, atype: 1}] - }); + // init id system + attachIdSystem(mockIdSystem); + config.setConfig(userIdConfig); + } + const sharedAfterFunction = function () { + config.resetConfig(); + mockGetId.reset(); + mockDecode.reset(); + mockExtendId.reset(); + cmpStub.restore(); + resetConsentData(); + delete window.__cmp; + delete window.__tcfapi; + }; + + describe('TCF v1', function () { + testConsentData = { + gdprApplies: true, + consentData: 'xyz', + apiVersion: 1 + }; + + beforeEach(function () { + sharedBeforeFunction(); + + // init v1 consent management + window.__cmp = function () { + }; + delete window.__tcfapi; + cmpStub = sinon.stub(window, '__cmp').callsFake((...args) => { + args[2](testConsentData); }); + setConsentConfig(consentConfig); }); - // attach a handler for auction end event to run the second bid request - events.on(CONSTANTS.EVENTS.AUCTION_END, function handler(submodule) { - if (submodule === 'parrableIdSubmoduleMock') { - // make the second bid request, id should have been refreshed - requestBidsHook((config) => { innerAdUnits = config.adUnits }, {adUnits}); - innerAdUnits.forEach(unit => { - unit.bids.forEach(bid => { - expect(bid).to.have.deep.nested.property('userId.parrableid'); - expect(bid.userId.parrableid).to.equal(parrableRefreshedId); - expect(bid.userIdAsEids[0]).to.deep.equal({ - source: 'parrable.com', - uids: [{id: parrableRefreshedId, atype: 1}] - }); - }); - }); - events.off(CONSTANTS.EVENTS.AUCTION_END, handler); - done(); - } + afterEach(function () { + sharedAfterFunction(); + }); + + it('does not call getId if no stored consent data and refresh is not needed', function () { + coreStorage.setCookie(mockIdCookieName, JSON.stringify({id: '1234'}), expStr); + coreStorage.setCookie(`${mockIdCookieName}_last`, (new Date(Date.now() - 1 * 1000).toUTCString()), expStr); + + let innerAdUnits; + consentManagementRequestBidsHook(() => { + }, {}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); + + sinon.assert.notCalled(mockGetId); + sinon.assert.calledOnce(mockDecode); + sinon.assert.calledOnce(mockExtendId); + }); + + it('calls getId if no stored consent data but refresh is needed', function () { + coreStorage.setCookie(mockIdCookieName, JSON.stringify({id: '1234'}), expStr); + coreStorage.setCookie(`${mockIdCookieName}_last`, (new Date(Date.now() - 60 * 1000).toUTCString()), expStr); + + let innerAdUnits; + consentManagementRequestBidsHook(() => { + }, {}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); + + sinon.assert.calledOnce(mockGetId); + sinon.assert.calledOnce(mockDecode); + sinon.assert.notCalled(mockExtendId); + }); + + it('calls getId if empty stored consent and refresh not needed', function () { + coreStorage.setCookie(mockIdCookieName, JSON.stringify({id: '1234'}), expStr); + coreStorage.setCookie(`${mockIdCookieName}_last`, (new Date(Date.now() - 1 * 1000).toUTCString()), expStr); + + setStoredConsentData(); + + let innerAdUnits; + consentManagementRequestBidsHook(() => { + }, {}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); + + sinon.assert.calledOnce(mockGetId); + sinon.assert.calledOnce(mockDecode); + sinon.assert.notCalled(mockExtendId); + }); + + it('calls getId if stored consent does not match current consent and refresh not needed', function () { + coreStorage.setCookie(mockIdCookieName, JSON.stringify({id: '1234'}), expStr); + coreStorage.setCookie(`${mockIdCookieName}_last`, (new Date(Date.now() - 1 * 1000).toUTCString()), expStr); + + setStoredConsentData({ + gdprApplies: testConsentData.gdprApplies, + consentString: 'abc', + apiVersion: testConsentData.apiVersion + }); + + let innerAdUnits; + consentManagementRequestBidsHook(() => { + }, {}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); + + sinon.assert.calledOnce(mockGetId); + sinon.assert.calledOnce(mockDecode); + sinon.assert.notCalled(mockExtendId); }); - // emit an auction end event to run the submodule callback - events.emit(CONSTANTS.EVENTS.AUCTION_END, 'parrableIdSubmoduleMock'); + it('does not call getId if stored consent matches current consent and refresh not needed', function () { + coreStorage.setCookie(mockIdCookieName, JSON.stringify({id: '1234'}), expStr); + coreStorage.setCookie(`${mockIdCookieName}_last`, (new Date(Date.now() - 1 * 1000).toUTCString()), expStr); + + setStoredConsentData({ + gdprApplies: testConsentData.gdprApplies, + consentString: testConsentData.consentData, + apiVersion: testConsentData.apiVersion + }); + + let innerAdUnits; + consentManagementRequestBidsHook(() => { + }, {}); + requestBidsHook((config) => { + innerAdUnits = config.adUnits + }, {adUnits}); + + sinon.assert.notCalled(mockGetId); + sinon.assert.calledOnce(mockDecode); + sinon.assert.calledOnce(mockExtendId); + }); }); }); }); diff --git a/test/spec/modules/valueimpressionBidAdapter_spec.js b/test/spec/modules/valueimpressionBidAdapter_spec.js deleted file mode 100644 index 89a9657aff4..00000000000 --- a/test/spec/modules/valueimpressionBidAdapter_spec.js +++ /dev/null @@ -1,602 +0,0 @@ -import { expect } from 'chai' -import { spec } from 'modules/valueimpressionBidAdapter.js' -import { newBidder } from 'src/adapters/bidderFactory.js' -import { userSync } from '../../../src/userSync.js'; - -describe('ValueimpressionBidAdapter', function () { - const adapter = newBidder(spec) - - describe('.code', function () { - it('should return a bidder code of valueimpression', function () { - expect(spec.code).to.equal('valueimpression') - }) - }) - - describe('inherited functions', function () { - it('should exist and be a function', function () { - expect(adapter.callBids).to.exist.and.to.be.a('function') - }) - }) - - describe('.isBidRequestValid', function () { - it('should return false if there are no params', () => { - const bid = { - 'bidder': 'valueimpression', - 'adUnitCode': 'adunit-code', - 'mediaTypes': { - banner: { - sizes: [[300, 250], [300, 600]] - } - }, - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - }; - expect(spec.isBidRequestValid(bid)).to.equal(false); - }); - - it('should return false if there is no siteId param', () => { - const bid = { - 'bidder': 'valueimpression', - 'adUnitCode': 'adunit-code', - params: { - site_id: '1a2b3c4d5e6f1a2b3c4d', - }, - 'mediaTypes': { - banner: { - sizes: [[300, 250], [300, 600]] - } - }, - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - }; - expect(spec.isBidRequestValid(bid)).to.equal(false); - }); - - it('should return false if there is no mediaTypes', () => { - const bid = { - 'bidder': 'valueimpression', - 'adUnitCode': 'adunit-code', - params: { - siteId: '1a2b3c4d5e6f1a2b3c4d' - }, - 'mediaTypes': { - }, - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - }; - expect(spec.isBidRequestValid(bid)).to.equal(false); - }); - - it('should return true if the bid is valid', () => { - const bid = { - 'bidder': 'valueimpression', - 'adUnitCode': 'adunit-code', - params: { - siteId: '1a2b3c4d5e6f1a2b3c4d' - }, - 'mediaTypes': { - banner: { - sizes: [[300, 250], [300, 600]] - } - }, - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - }; - expect(spec.isBidRequestValid(bid)).to.equal(true); - }); - - describe('banner', () => { - it('should return false if there are no banner sizes', () => { - const bid = { - 'bidder': 'valueimpression', - 'adUnitCode': 'adunit-code', - params: { - siteId: '1a2b3c4d5e6f1a2b3c4d' - }, - 'mediaTypes': { - banner: { - - } - }, - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - }; - expect(spec.isBidRequestValid(bid)).to.equal(false); - }); - - it('should return true if there is banner sizes', () => { - const bid = { - 'bidder': 'valueimpression', - 'adUnitCode': 'adunit-code', - params: { - siteId: '1a2b3c4d5e6f1a2b3c4d' - }, - 'mediaTypes': { - banner: { - sizes: [[300, 250], [300, 600]] - } - }, - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - }; - expect(spec.isBidRequestValid(bid)).to.equal(true); - }); - }); - - describe('video', () => { - it('should return false if there is no playerSize defined in the video mediaType', () => { - const bid = { - 'bidder': 'valueimpression', - 'adUnitCode': 'adunit-code', - params: { - siteId: '1a2b3c4d5e6f1a2b3c4d', - sizes: [[300, 250], [300, 600]] - }, - 'mediaTypes': { - video: { - context: 'instream' - } - }, - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - }; - expect(spec.isBidRequestValid(bid)).to.equal(false); - }); - - it('should return true if there is playerSize defined on the video mediaType', () => { - const bid = { - 'bidder': 'valueimpression', - 'adUnitCode': 'adunit-code', - params: { - siteId: '1a2b3c4d5e6f1a2b3c4d', - }, - 'mediaTypes': { - video: { - context: 'instream', - playerSize: [[640, 480]] - } - }, - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - }; - expect(spec.isBidRequestValid(bid)).to.equal(true); - }); - }); - }); - - describe('.buildRequests', function () { - beforeEach(function () { - sinon.stub(userSync, 'canBidderRegisterSync'); - }); - afterEach(function () { - userSync.canBidderRegisterSync.restore(); - }); - let bidRequest = [{ - 'schain': { - 'ver': '1.0', - 'complete': 1, - 'nodes': [ - { - 'asi': 'indirectseller.com', - 'sid': '00001', - 'hp': 1 - }, - { - 'asi': 'indirectseller-2.com', - 'sid': '00002', - 'hp': 0 - }, - ] - }, - 'bidder': 'valueimpression', - 'params': { - 'siteId': '1a2b3c4d5e6f1a2b3c4d', - }, - 'adUnitCode': 'adunit-code-1', - 'sizes': [[300, 250], [300, 600]], - 'bidId': '30b31c1838de1f', - }, - { - 'bidder': 'valueimpression', - 'params': { - 'ad_unit': '/7780971/sparks_prebid_LB', - 'sizes': [[300, 250], [300, 600]], - 'referrer': 'overrides_top_window_location' - }, - 'adUnitCode': 'adunit-code-2', - 'sizes': [[120, 600], [300, 600], [160, 600]], - 'bidId': '30b31c1838de1e', - }]; - - let bidderRequests = { - 'gdprConsent': { - 'consentString': 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', - 'vendorData': {}, - 'gdprApplies': true - }, - 'refererInfo': { - 'numIframes': 0, - 'reachedTop': true, - 'referer': 'https://example.com', - 'stack': ['https://example.com'] - }, - uspConsent: 'someCCPAString' - }; - - it('should return a properly formatted request', function () { - const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.url).to.equal('https://adapter.valueimpression.com/bid') - expect(bidRequests.method).to.equal('POST') - expect(bidRequests.bidderRequests).to.eql(bidRequest); - }) - - it('should return a properly formatted request with GDPR applies set to true', function () { - const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.url).to.equal('https://adapter.valueimpression.com/bid') - expect(bidRequests.method).to.equal('POST') - expect(bidRequests.data.gdpr.gdprApplies).to.equal('true') - expect(bidRequests.data.gdpr.consentString).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A==') - }) - - it('should return a properly formatted request with GDPR applies set to false', function () { - bidderRequests.gdprConsent.gdprApplies = false; - const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.url).to.equal('https://adapter.valueimpression.com/bid') - expect(bidRequests.method).to.equal('POST') - expect(bidRequests.data.gdpr.gdprApplies).to.equal('false') - expect(bidRequests.data.gdpr.consentString).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A==') - }) - it('should return a properly formatted request with GDPR applies set to false with no consent_string param', function () { - let bidderRequests = { - 'gdprConsent': { - 'consentString': undefined, - 'vendorData': {}, - 'gdprApplies': false - }, - 'refererInfo': { - 'numIframes': 0, - 'reachedTop': true, - 'referer': 'https://example.com', - 'stack': ['https://example.com'] - } - }; - const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.url).to.equal('https://adapter.valueimpression.com/bid') - expect(bidRequests.method).to.equal('POST') - expect(bidRequests.data.gdpr.gdprApplies).to.equal('false') - expect(bidRequests.data.gdpr).to.not.include.keys('consentString') - }) - it('should return a properly formatted request with GDPR applies set to true with no consentString param', function () { - let bidderRequests = { - 'gdprConsent': { - 'consentString': undefined, - 'vendorData': {}, - 'gdprApplies': true - }, - 'refererInfo': { - 'numIframes': 0, - 'reachedTop': true, - 'referer': 'https://example.com', - 'stack': ['https://example.com'] - } - }; - const bidRequests = spec.buildRequests(bidRequest, bidderRequests) - expect(bidRequests.url).to.equal('https://adapter.valueimpression.com/bid') - expect(bidRequests.method).to.equal('POST') - expect(bidRequests.data.gdpr.gdprApplies).to.equal('true') - expect(bidRequests.data.gdpr).to.not.include.keys('consentString') - }) - it('should return a properly formatted request with schain defined', function () { - const bidRequests = spec.buildRequests(bidRequest, bidderRequests); - expect(JSON.parse(bidRequests.data.schain)).to.deep.equal(bidRequest[0].schain) - }); - it('should return a properly formatted request with us_privacy included', function () { - const bidRequests = spec.buildRequests(bidRequest, bidderRequests); - expect(bidRequests.data.us_privacy).to.equal('someCCPAString'); - }); - }); - - describe('.interpretResponse', function () { - const bidRequests = { - 'method': 'POST', - 'url': 'https://adapter.valueimpression.com/bid', - 'withCredentials': true, - 'data': { - 'device': { - 'ua': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36', - 'height': 937, - 'width': 1920, - 'dnt': 0, - 'language': 'vi' - }, - 'site': { - 'id': '343', - 'page': 'https://www.includehelp.com/?pbjs_debug=true', - 'referrer': '', - 'hostname': 'www.includehelp.com' - } - }, - 'bidderRequests': [ - { - 'bidder': 'valueimpression', - 'params': { - 'siteId': '343' - }, - 'crumbs': { - 'pubcid': 'c2b2ba08-9954-4850-8ee5-2bf4a2b35eff' - }, - 'mediaTypes': { - 'banner': { - 'sizes': [[160, 600], [120, 600]] - } - }, - 'adUnitCode': 'vi_3431035_1', - 'transactionId': '994d8404-4a28-4c43-98d8-a38dbb061910', - 'sizes': [[160, 600], [120, 600]], - 'bidId': '3000aa31c41a29c21', - 'bidderRequestId': '299926b3d3628cdd7', - 'auctionId': '22445943-a0aa-4c63-a413-4deb64fcff1c', - 'src': 'client', - 'bidRequestsCount': 41, - 'bidderRequestsCount': 41, - 'bidderWinsCount': 0, - 'schain': { - 'ver': '1.0', - 'complete': 1, - 'nodes': [ - { - 'asi': 'freegames66.com', - 'sid': '343', - 'hp': 1 - } - ] - } - }, - { - 'bidder': 'valueimpression', - 'params': { - 'siteId': '343' - }, - 'crumbs': { - 'pubcid': 'c2b2ba08-9954-4850-8ee5-2bf4a2b35eff' - }, - 'mediaTypes': { - 'banner': { - 'sizes': [[300, 250], [250, 250], [200, 200], [180, 150]] - } - }, - 'adUnitCode': 'vi_3431033_1', - 'transactionId': '800fe87e-bfec-43a5-ace0-c4e2373ff4b5', - 'sizes': [[300, 250], [250, 250], [200, 200], [180, 150]], - 'bidId': '30024615be22ef66a', - 'bidderRequestId': '299926b3d3628cdd7', - 'auctionId': '22445943-a0aa-4c63-a413-4deb64fcff1c', - 'src': 'client', - 'bidRequestsCount': 41, - 'bidderRequestsCount': 41, - 'bidderWinsCount': 0, - 'schain': { - 'ver': '1.0', - 'complete': 1, - 'nodes': [ - { - 'asi': 'freegames66.com', - 'sid': '343', - 'hp': 1 - } - ] - } - }, - { - 'bidder': 'valueimpression', - 'params': { - 'siteId': '343' - }, - 'crumbs': { - 'pubcid': 'c2b2ba08-9954-4850-8ee5-2bf4a2b35eff' - }, - 'mediaTypes': { - 'video': { - 'playerSize': [[640, 480]], - 'context': 'instream', - 'mimes': [ - 'video/mp4', - 'video/x-flv', - 'video/x-ms-wmv', - 'application/vnd.apple.mpegurl', - 'application/x-mpegurl', - 'video/3gpp', - 'video/mpeg', - 'video/ogg', - 'video/quicktime', - 'video/webm', - 'video/x-m4v', - 'video/ms-asf', - 'video/x-msvideo' - ], - 'protocols': [1, 2, 3, 4, 5, 6], - 'playbackmethod': [6], - 'maxduration': 120, - 'linearity': 1, - 'api': [2] - } - }, - 'adUnitCode': 'vi_3431909', - 'transactionId': '33d83d87-43cc-499b-aabe-5c22eb6acfbb', - 'sizes': [[640, 480]], - 'bidId': '1854b40107d6745c', - 'bidderRequestId': '1840763b6bda185d', - 'auctionId': 'df495de0-5d42-471f-a501-73bcd7254b80', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0, - 'schain': { - 'ver': '1.0', - 'complete': 1, - 'nodes': [ - { - 'asi': 'freegames66.com', - 'sid': '343', - 'hp': 1 - } - ] - } - } - ] - }; - - let serverResponse = { - 'body': { - 'bids': [ - { - 'requestId': '3000aa31c41a29c21', - 'cpm': 1.07, - 'width': 160, - 'height': 600, - 'ad': `
Valueimpression AD
`, - 'ttl': 500, - 'creativeId': '1234abcd', - 'netRevenue': true, - 'currency': 'USD', - 'dealId': 'valueimpression', - 'mediaType': 'banner' - }, - { - 'requestId': '30024615be22ef66a', - 'cpm': 1, - 'width': 300, - 'height': 250, - 'ad': `
Valueimpression AD
`, - 'ttl': 500, - 'creativeId': '1234abcd', - 'netRevenue': true, - 'currency': 'USD', - 'dealId': 'valueimpression', - 'mediaType': 'banner' - }, - { - 'requestId': '1854b40107d6745c', - 'cpm': 1.25, - 'width': 300, - 'height': 250, - 'vastXml': 'valueimpression', - 'ttl': 500, - 'creativeId': '30292e432662bd5f86d90774b944b038', - 'netRevenue': true, - 'currency': 'USD', - 'dealId': 'valueimpression', - 'mediaType': 'video' - } - ], - 'pixel': [{ - 'url': 'https://example.com/pixel.png', - 'type': 'image' - }] - } - }; - - let prebidResponse = [ - { - 'requestId': '3000aa31c41a29c21', - 'cpm': 1.07, - 'width': 160, - 'height': 600, - 'ad': `
Valueimpression AD
`, - 'ttl': 500, - 'creativeId': '1234abcd', - 'netRevenue': true, - 'currency': 'USD', - 'dealId': 'valueimpression', - 'mediaType': 'banner' - }, - { - 'requestId': '30024615be22ef66a', - 'cpm': 1, - 'width': 300, - 'height': 250, - 'ad': `
Valueimpression AD
`, - 'ttl': 500, - 'creativeId': '1234abcd', - 'netRevenue': true, - 'currency': 'USD', - 'dealId': 'valueimpression', - 'mediaType': 'banner' - }, - { - 'requestId': '1854b40107d6745c', - 'cpm': 1.25, - 'width': 300, - 'height': 250, - 'vastXml': 'valueimpression', - 'ttl': 500, - 'creativeId': '30292e432662bd5f86d90774b944b038', - 'netRevenue': true, - 'currency': 'USD', - 'dealId': 'valueimpression', - 'mediaType': 'video' - } - ]; - - it('should map bidResponse to prebidResponse', function () { - const response = spec.interpretResponse(serverResponse, bidRequests); - response.forEach((resp, i) => { - expect(resp.requestId).to.equal(prebidResponse[i].requestId); - expect(resp.cpm).to.equal(prebidResponse[i].cpm); - expect(resp.width).to.equal(prebidResponse[i].width); - expect(resp.height).to.equal(prebidResponse[i].height); - expect(resp.ttl).to.equal(prebidResponse[i].ttl); - expect(resp.creativeId).to.equal(prebidResponse[i].creativeId); - expect(resp.netRevenue).to.equal(prebidResponse[i].netRevenue); - expect(resp.currency).to.equal(prebidResponse[i].currency); - expect(resp.dealId).to.equal(prebidResponse[i].dealId); - if (resp.mediaType === 'video') { - expect(resp.vastXml.indexOf('valueimpression')).to.be.greaterThan(0); - } - if (resp.mediaType === 'banner') { - expect(resp.ad.indexOf('Valueimpression AD')).to.be.greaterThan(0); - } - }); - }); - }); - - describe('.getUserSyncs', function () { - let bidResponse = [{ - 'body': { - 'pixel': [{ - 'url': 'https://pixel-test', - 'type': 'image' - }] - } - }]; - - it('should return one sync pixel', function () { - expect(spec.getUserSyncs({ pixelEnabled: true }, bidResponse)).to.deep.equal([{ - type: 'image', - url: 'https://pixel-test' - }]); - }); - it('should return an empty array when sync is enabled but there are no bidResponses', function () { - expect(spec.getUserSyncs({ pixelEnabled: true }, [])).to.have.length(0); - }); - - it('should return an empty array when sync is enabled but no sync pixel returned', function () { - const pixel = Object.assign({}, bidResponse); - delete pixel[0].body.pixel; - expect(spec.getUserSyncs({ pixelEnabled: true }, bidResponse)).to.have.length(0); - }); - - it('should return an empty array', function () { - expect(spec.getUserSyncs({ pixelEnabled: false }, bidResponse)).to.have.length(0); - expect(spec.getUserSyncs({ pixelEnabled: true }, [])).to.have.length(0); - }); - }); -}); diff --git a/test/spec/modules/vidazooBidAdapter_spec.js b/test/spec/modules/vidazooBidAdapter_spec.js index a52669b773b..d7f20c434ca 100644 --- a/test/spec/modules/vidazooBidAdapter_spec.js +++ b/test/spec/modules/vidazooBidAdapter_spec.js @@ -1,10 +1,30 @@ -import {expect} from 'chai'; -import {spec as adapter, URL} from 'modules/vidazooBidAdapter.js'; +import { expect } from 'chai'; +import { + spec as adapter, + SUPPORTED_ID_SYSTEMS, + createDomain, + hashCode, + extractPID, + extractCID, + extractSubDomain, + getStorageItem, + setStorageItem, + tryParseJSON, + getUniqueDealId, + getNextDealId, + getVidazooSessionId, +} from 'modules/vidazooBidAdapter.js'; import * as utils from 'src/utils.js'; +import { version } from 'package.json'; +import { useFakeTimers } from 'sinon'; + +const SUB_DOMAIN = 'openrtb'; const BID = { 'bidId': '2d52001cabd527', + 'adUnitCode': 'div-gpt-ad-12345-0', 'params': { + 'subDomain': SUB_DOMAIN, 'cId': '59db6b3b4ffaa70004f45cdc', 'pId': '59ac17c192832d0011283fe3', 'bidFloor': 0.1, @@ -25,6 +45,7 @@ const BIDDER_REQUEST = { 'consentString': 'consent_string', 'gdprApplies': true }, + 'uspConsent': 'consent_string', 'refererInfo': { 'referer': 'https://www.greatsite.com' } @@ -58,10 +79,6 @@ const REQUEST = { } }; -const SYNC_OPTIONS = { - 'pixelEnabled': true -}; - describe('VidazooBidAdapter', function () { describe('validtae spec', function () { it('exists and is a function', function () { @@ -123,20 +140,29 @@ describe('VidazooBidAdapter', function () { }); it('should build request for each size', function () { + const hashUrl = hashCode(BIDDER_REQUEST.refererInfo.referer); const requests = adapter.buildRequests([BID], BIDDER_REQUEST); expect(requests).to.have.length(1); expect(requests[0]).to.deep.equal({ method: 'POST', - url: `${URL}/prebid/multi/59db6b3b4ffaa70004f45cdc`, + url: `${createDomain(SUB_DOMAIN)}/prebid/multi/59db6b3b4ffaa70004f45cdc`, data: { gdprConsent: 'consent_string', gdpr: 1, + usPrivacy: 'consent_string', sizes: ['300x250', '300x600'], url: 'https%3A%2F%2Fwww.greatsite.com', cb: 1000, bidFloor: 0.1, bidId: '2d52001cabd527', + adUnitCode: 'div-gpt-ad-12345-0', publisherId: '59ac17c192832d0011283fe3', + dealId: 1, + sessionId: '', + uniqueDealId: `${hashUrl}_${Date.now().toString()}`, + bidderVersion: adapter.version, + prebidVersion: version, + res: `${window.top.screen.width}x${window.top.screen.height}`, 'ext.param1': 'loremipsum', 'ext.param2': 'dolorsitamet', } @@ -149,19 +175,19 @@ describe('VidazooBidAdapter', function () { }); describe('getUserSyncs', function () { it('should have valid user sync with iframeEnabled', function () { - const result = adapter.getUserSyncs({iframeEnabled: true}, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({ iframeEnabled: true }, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ type: 'iframe', - url: 'https://static.cootlogix.com/basev/sync/user_sync.html' + url: 'https://prebid.cootlogix.com/api/sync/iframe/?gdpr=0&gdpr_consent=&us_privacy=' }]); }); it('should have valid user sync with pixelEnabled', function () { - const result = adapter.getUserSyncs({pixelEnabled: true}, [SERVER_RESPONSE]); + const result = adapter.getUserSyncs({ pixelEnabled: true }, [SERVER_RESPONSE]); expect(result).to.deep.equal([{ - 'url': 'https://sync.com', + 'url': 'https://prebid.cootlogix.com/api/sync/image/?gdpr=0&gdpr_consent=&us_privacy=', 'type': 'image' }]); }) @@ -174,12 +200,12 @@ describe('VidazooBidAdapter', function () { }); it('should return empty array when there is no ad', function () { - const responses = adapter.interpretResponse({price: 1, ad: ''}); + const responses = adapter.interpretResponse({ price: 1, ad: '' }); expect(responses).to.be.empty; }); it('should return empty array when there is no price', function () { - const responses = adapter.interpretResponse({price: null, ad: 'great ad'}); + const responses = adapter.interpretResponse({ price: null, ad: 'great ad' }); expect(responses).to.be.empty; }); @@ -207,4 +233,140 @@ describe('VidazooBidAdapter', function () { expect(responses[0].ttl).to.equal(300); }); }); + + describe('user id system', function () { + Object.keys(SUPPORTED_ID_SYSTEMS).forEach((idSystemProvider) => { + const id = Date.now().toString(); + const bid = utils.deepClone(BID); + + const userId = (function () { + switch (idSystemProvider) { + case 'digitrustid': return { data: { id: id } }; + case 'lipb': return { lipbid: id }; + case 'parrableId': return { eid: id }; + case 'id5id': return { uid: id }; + default: return id; + } + })(); + + bid.userId = { + [idSystemProvider]: userId + }; + + it(`should include 'uid.${idSystemProvider}' in request params`, function () { + const requests = adapter.buildRequests([bid], BIDDER_REQUEST); + expect(requests[0].data[`uid.${idSystemProvider}`]).to.equal(id); + }); + }); + }); + + describe('alternate param names extractors', function () { + it('should return undefined when param not supported', function () { + const cid = extractCID({ 'c_id': '1' }); + const pid = extractPID({ 'p_id': '1' }); + const subDomain = extractSubDomain({ 'sub_domain': 'prebid' }); + expect(cid).to.be.undefined; + expect(pid).to.be.undefined; + expect(subDomain).to.be.undefined; + }); + + it('should return value when param supported', function () { + const cid = extractCID({ 'cID': '1' }); + const pid = extractPID({ 'Pid': '2' }); + const subDomain = extractSubDomain({ 'subDOMAIN': 'prebid' }); + expect(cid).to.be.equal('1'); + expect(pid).to.be.equal('2'); + expect(subDomain).to.be.equal('prebid'); + }); + }); + + describe('vidazoo session id', function () { + it('should get undefined vidazoo session id', function () { + const sessionId = getVidazooSessionId(); + expect(sessionId).to.be.empty; + }); + + it('should get vidazoo session id from storage', function () { + const vidSid = '1234-5678'; + window.localStorage.setItem('vidSid', vidSid); + const sessionId = getVidazooSessionId(); + expect(sessionId).to.be.equal(vidSid); + }); + }); + + describe('deal id', function () { + const key = 'myDealKey'; + + it('should get the next deal id', function () { + const dealId = getNextDealId(key); + const nextDealId = getNextDealId(key); + expect(dealId).to.be.equal(1); + expect(nextDealId).to.be.equal(2); + }); + + it('should get the first deal id on expiration', function (done) { + setTimeout(function () { + const dealId = getNextDealId(key, 100); + expect(dealId).to.be.equal(1); + done(); + }, 200); + }); + }); + + describe('unique deal id', function () { + const key = 'myKey'; + let uniqueDealId; + uniqueDealId = getUniqueDealId(key); + + it('should get current unique deal id', function (done) { + // waiting some time so `now` will become past + setTimeout(() => { + const current = getUniqueDealId(key); + expect(current).to.be.equal(uniqueDealId); + done(); + }, 200); + }); + + it('should get new unique deal id on expiration', function () { + const current = getUniqueDealId(key, 100); + expect(current).to.not.be.equal(uniqueDealId); + }); + }); + + describe('storage utils', function () { + it('should get value from storage with create param', function () { + const now = Date.now(); + const clock = useFakeTimers({ + shouldAdvanceTime: true, + now + }); + setStorageItem('myKey', 2020); + const { value, created } = getStorageItem('myKey'); + expect(created).to.be.equal(now); + expect(value).to.be.equal(2020); + expect(typeof value).to.be.equal('number'); + expect(typeof created).to.be.equal('number'); + clock.restore(); + }); + + it('should get external stored value', function () { + const value = 'superman' + window.localStorage.setItem('myExternalKey', value); + const item = getStorageItem('myExternalKey'); + expect(item).to.be.equal(value); + }); + + it('should parse JSON value', function () { + const data = JSON.stringify({ event: 'send' }); + const { event } = tryParseJSON(data); + expect(event).to.be.equal('send'); + }); + + it('should get original value on parse fail', function () { + const value = 21; + const parsed = tryParseJSON(value); + expect(typeof parsed).to.be.equal('number'); + expect(parsed).to.be.equal(value); + }); + }); }); diff --git a/test/spec/modules/videofyBidAdapter_spec.js b/test/spec/modules/videofyBidAdapter_spec.js new file mode 100644 index 00000000000..270eefd1efc --- /dev/null +++ b/test/spec/modules/videofyBidAdapter_spec.js @@ -0,0 +1,253 @@ +import { spec } from 'modules/videofyBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import * as utils from '../../../src/utils.js'; + +const { expect } = require('chai'); + +describe('Videofy Bid Adapter Test', function () { + const adapter = newBidder(spec); + + describe('inherited functions', function () { + it('exists and is a function', function () { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('isBidRequestValid', function () { + let bid = { + 'bidder': 'videofy', + 'params': { + 'AV_PUBLISHERID': '123456', + 'AV_CHANNELID': '123456' + }, + 'adUnitCode': 'video1', + 'sizes': [[300, 250], [640, 480]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'requestId': 'a09c66c3-53e3-4428-b296-38fc08e7cd2a', + 'transactionId': 'd6f6b392-54a9-454c-85fb-a2fd882c4a2d', + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', function () { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + something: 'is wrong' + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + let bid2Requests = [ + { + 'bidder': 'videofy', + 'params': { + 'AV_PUBLISHERID': '123456', + 'AV_CHANNELID': '123456' + }, + 'adUnitCode': 'test1', + 'sizes': [[300, 250], [640, 480]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'requestId': 'a09c66c3-53e3-4428-b296-38fc08e7cd2a', + 'transactionId': 'd6f6b392-54a9-454c-85fb-a2fd882c4a2d', + } + ]; + let bid1Request = [ + { + 'bidder': 'videofy', + 'params': { + 'AV_PUBLISHERID': '123456', + 'AV_CHANNELID': '123456' + }, + 'adUnitCode': 'test1', + 'sizes': [640, 480], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'requestId': 'a09c66c3-53e3-4428-b296-38fc08e7cd2a', + 'transactionId': 'd6f6b392-54a9-454c-85fb-a2fd882c4a2d', + } + ]; + + it('Test 2 requests', function () { + const requests = spec.buildRequests(bid2Requests); + expect(requests.length).to.equal(2); + const r1 = requests[0]; + const d1 = requests[0].data; + expect(d1).to.have.property('AV_PUBLISHERID'); + expect(d1.AV_PUBLISHERID).to.equal('123456'); + expect(d1).to.have.property('AV_CHANNELID'); + expect(d1.AV_CHANNELID).to.equal('123456'); + expect(d1).to.have.property('AV_WIDTH'); + expect(d1.AV_WIDTH).to.equal(300); + expect(d1).to.have.property('AV_HEIGHT'); + expect(d1.AV_HEIGHT).to.equal(250); + expect(d1).to.have.property('AV_URL'); + expect(d1).to.have.property('cb'); + expect(d1).to.have.property('s2s'); + expect(d1.s2s).to.equal('1'); + expect(d1).to.have.property('pbjs'); + expect(d1.pbjs).to.equal(1); + expect(r1).to.have.property('url'); + expect(r1.url).to.contain('https://servx.srv-mars.com/api/adserver/vast3/'); + const r2 = requests[1]; + const d2 = requests[1].data; + expect(d2).to.have.property('AV_PUBLISHERID'); + expect(d2.AV_PUBLISHERID).to.equal('123456'); + expect(d2).to.have.property('AV_CHANNELID'); + expect(d2.AV_CHANNELID).to.equal('123456'); + expect(d2).to.have.property('AV_WIDTH'); + expect(d2.AV_WIDTH).to.equal(640); + expect(d2).to.have.property('AV_HEIGHT'); + expect(d2.AV_HEIGHT).to.equal(480); + expect(d2).to.have.property('AV_URL'); + expect(d2).to.have.property('cb'); + expect(d2).to.have.property('s2s'); + expect(d2.s2s).to.equal('1'); + expect(d2).to.have.property('pbjs'); + expect(d2.pbjs).to.equal(1); + expect(r2).to.have.property('url'); + expect(r2.url).to.contain('https://servx.srv-mars.com/api/adserver/vast3/'); + }); + + it('Test 1 request', function () { + const requests = spec.buildRequests(bid1Request); + expect(requests.length).to.equal(1); + const r = requests[0]; + const d = requests[0].data; + expect(d).to.have.property('AV_PUBLISHERID'); + expect(d.AV_PUBLISHERID).to.equal('123456'); + expect(d).to.have.property('AV_CHANNELID'); + expect(d.AV_CHANNELID).to.equal('123456'); + expect(d).to.have.property('AV_WIDTH'); + expect(d.AV_WIDTH).to.equal(640); + expect(d).to.have.property('AV_HEIGHT'); + expect(d.AV_HEIGHT).to.equal(480); + expect(d).to.have.property('AV_URL'); + expect(d).to.have.property('cb'); + expect(d).to.have.property('s2s'); + expect(d.s2s).to.equal('1'); + expect(d).to.have.property('pbjs'); + expect(d.pbjs).to.equal(1); + expect(r).to.have.property('url'); + expect(r.url).to.contain('https://servx.srv-mars.com/api/adserver/vast3/'); + }); + }); + + describe('interpretResponse', function () { + let bidRequest = { + 'url': 'https://servx.srv-mars.com/api/adserver/vast3/', + 'data': { + 'bidId': '253dcb69fb2577', + AV_PUBLISHERID: '55b78633181f4603178b4568', + AV_CHANNELID: '55b7904d181f46410f8b4568', + } + }; + let serverResponse = {}; + serverResponse.body = 'FORDFORD00:00:15'; + + it('Check bid interpretResponse', function () { + const BIDDER_CODE = 'videofy'; + let bidResponses = spec.interpretResponse(serverResponse, bidRequest); + expect(bidResponses.length).to.equal(1); + let bidResponse = bidResponses[0]; + expect(bidResponse.requestId).to.equal(bidRequest.data.bidId); + expect(bidResponse.bidderCode).to.equal(BIDDER_CODE); + expect(bidResponse.cpm).to.equal('2'); + expect(bidResponse.ttl).to.equal(600); + expect(bidResponse.currency).to.equal('USD'); + expect(bidResponse.netRevenue).to.equal(true); + expect(bidResponse.mediaType).to.equal('video'); + }); + + it('safely handles XML parsing failure from invalid bid response', function () { + let invalidServerResponse = {}; + invalidServerResponse.body = ''; + + let result = spec.interpretResponse(invalidServerResponse, bidRequest); + expect(result.length).to.equal(0); + }); + + it('handles nobid responses', function () { + let nobidResponse = {}; + nobidResponse.body = ''; + + let result = spec.interpretResponse(nobidResponse, bidRequest); + expect(result.length).to.equal(0); + }); + }); + + describe('getUserSyncs', function () { + it('Check get sync pixels from response', function () { + let pixelUrl = 'https://sync.pixel.url/sync'; + let pixelEvent = 'inventory'; + let pixelType = '3'; + let pixelStr = '{"url":"' + pixelUrl + '", "e":"' + pixelEvent + '", "t":' + pixelType + '}'; + let bidResponse = 'FORDFORD00:00:15'; + let serverResponse = [ + {body: bidResponse} + ]; + let syncPixels = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, serverResponse); + expect(syncPixels.length).to.equal(1); + let pixel = syncPixels[0]; + expect(pixel.url).to.equal(pixelUrl); + expect(pixel.type).to.equal('iframe'); + }); + }); + + describe('on bidWon', function () { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + it('exists and is a function', () => { + expect(spec.onBidWon).to.exist.and.to.be.a('function'); + }); + it('should return nothing', function () { + var response = spec.onBidWon({}); + expect(response).to.be.an('undefined') + expect(utils.triggerPixel.called).to.equal(true); + }); + }); + + describe('on Timeout', function () { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + it('exists and is a function', () => { + expect(spec.onTimeout).to.exist.and.to.be.a('function'); + }); + it('should return nothing', function () { + var response = spec.onTimeout({}); + expect(response).to.be.an('undefined') + expect(utils.triggerPixel.called).to.equal(true); + }); + }); + + describe('on Set Targeting', function () { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + it('exists and is a function', () => { + expect(spec.onSetTargeting).to.exist.and.to.be.a('function'); + }); + it('should return nothing', function () { + var response = spec.onSetTargeting({}); + expect(response).to.be.an('undefined') + expect(utils.triggerPixel.called).to.equal(true); + }); + }); +}); diff --git a/test/spec/modules/visxBidAdapter_spec.js b/test/spec/modules/visxBidAdapter_spec.js index 7720bb2a3e4..a06f530e145 100755 --- a/test/spec/modules/visxBidAdapter_spec.js +++ b/test/spec/modules/visxBidAdapter_spec.js @@ -231,7 +231,7 @@ describe('VisxAdapter', function () { const schainBidRequests = [ Object.assign({userId: { tdid: '111', - id5id: '222', + id5id: { uid: '222' }, digitrustid: {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}} }}, bidRequests[0]), bidRequests[1], @@ -282,7 +282,6 @@ describe('VisxAdapter', function () { 'width': 300, 'height': 250, 'ad': '
test content 1
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, @@ -339,7 +338,6 @@ describe('VisxAdapter', function () { 'width': 300, 'height': 250, 'ad': '
test content 1
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, @@ -352,7 +350,6 @@ describe('VisxAdapter', function () { 'width': 300, 'height': 600, 'ad': '
test content 2
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, @@ -365,7 +362,6 @@ describe('VisxAdapter', function () { 'width': 728, 'height': 90, 'ad': '
test content 3
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, @@ -401,7 +397,6 @@ describe('VisxAdapter', function () { 'width': 300, 'height': 250, 'ad': '
test content 1
', - 'bidderCode': 'visx', 'currency': 'PLN', 'netRevenue': true, 'ttl': 360, @@ -531,7 +526,6 @@ describe('VisxAdapter', function () { 'width': 300, 'height': 250, 'ad': '
test content 1
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, @@ -544,7 +538,6 @@ describe('VisxAdapter', function () { 'width': 300, 'height': 600, 'ad': '
test content 2
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, @@ -557,7 +550,6 @@ describe('VisxAdapter', function () { 'width': 728, 'height': 90, 'ad': '
test content 3
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, @@ -570,7 +562,6 @@ describe('VisxAdapter', function () { 'width': 300, 'height': 600, 'ad': '
test content 4
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, @@ -583,7 +574,6 @@ describe('VisxAdapter', function () { 'width': 350, 'height': 600, 'ad': '
test content 5
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, @@ -644,7 +634,6 @@ describe('VisxAdapter', function () { 'width': 300, 'height': 250, 'ad': '
test content 1
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, @@ -657,7 +646,6 @@ describe('VisxAdapter', function () { 'width': 300, 'height': 250, 'ad': '
test content 2
', - 'bidderCode': 'visx', 'currency': 'EUR', 'netRevenue': true, 'ttl': 360, diff --git a/test/spec/modules/waardexBidAdapter_spec.js b/test/spec/modules/waardexBidAdapter_spec.js new file mode 100644 index 00000000000..8732b2bd51f --- /dev/null +++ b/test/spec/modules/waardexBidAdapter_spec.js @@ -0,0 +1,183 @@ +import {expect} from 'chai'; +import {spec} from '../../../modules/waardexBidAdapter.js'; +import { auctionManager } from 'src/auctionManager.js'; +import { deepClone } from 'src/utils.js'; + +describe('waardexBidAdapter', () => { + const validBid = { + bidId: '112435ry', + bidder: 'waardex', + params: { + placementId: 1, + traffic: 'banner', + zoneId: 1, + } + }; + + describe('isBidRequestValid', () => { + it('Should return true. bidId and params such as placementId and zoneId are present', () => { + expect(spec.isBidRequestValid(validBid)).to.be.true; + }); + it('Should return false. bidId is not present in bid object', () => { + const invalidBid = deepClone(validBid); + delete invalidBid.bidId; + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + it('Should return false. zoneId is not present in bid.params object', () => { + const invalidBid = deepClone(validBid); + delete invalidBid.params.zoneId; + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + }); + + describe('buildRequests', () => { + let getAdUnitsStub; + const validBidRequests = [{ + bidId: 'fergr675ujgh', + mediaTypes: { + banner: { + sizes: [[300, 600], [300, 250]] + } + }, + params: { + bidfloor: 1.5, + position: 1, + instl: 1, + zoneId: 100 + }, + }]; + + const bidderRequest = { + refererInfo: { + referer: 'https://www.google.com/?some_param=some_value' + }, + }; + + beforeEach(() => getAdUnitsStub = sinon.stub(auctionManager, 'getAdUnits').callsFake(() => [])); + afterEach(() => getAdUnitsStub.restore()); + + it('should return valid build request object', () => { + const request = spec.buildRequests(validBidRequests, bidderRequest); + const { + data: payload, + url, + method, + } = request; + + expect(payload.bidRequests[0]).deep.equal({ + bidId: validBidRequests[0].bidId, + bidfloor: validBidRequests[0].params.bidfloor, + position: validBidRequests[0].params.position, + instl: validBidRequests[0].params.instl, + banner: { + sizes: [ + { + width: validBidRequests[0].mediaTypes.banner.sizes[0][0], + height: validBidRequests[0].mediaTypes.banner.sizes[0][1] + }, + { + width: validBidRequests[0].mediaTypes.banner.sizes[1][0], + height: validBidRequests[0].mediaTypes.banner.sizes[1][1] + }, + ], + } + }); + const ENDPOINT = `https://hb.justbidit.xyz:8843/prebid?pubId=${validBidRequests[0].params.zoneId}`; + expect(url).to.equal(ENDPOINT); + expect(method).to.equal('POST'); + }); + }); + + describe('interpretResponse', () => { + const serverResponse = { + body: { + seatbid: [{ + bid: [{ + id: 'someId', + price: 3.3, + w: 250, + h: 300, + crid: 'dspCreativeIdHere', + adm: 'html markup here', + dealId: '123456789', + cid: 'dsp campaign id', + adomain: 'advertisers domain', + ext: { + mediaType: 'banner', + }, + }], + }], + }, + }; + + it('bid response is valid', () => { + const result = spec.interpretResponse(serverResponse); + const expected = [{ + requestId: serverResponse.body.seatbid[0].bid[0].id, + cpm: serverResponse.body.seatbid[0].bid[0].price, + currency: 'USD', + width: serverResponse.body.seatbid[0].bid[0].w, + height: serverResponse.body.seatbid[0].bid[0].h, + creativeId: serverResponse.body.seatbid[0].bid[0].crid, + netRevenue: true, + ttl: 3000, + ad: serverResponse.body.seatbid[0].bid[0].adm, + dealId: serverResponse.body.seatbid[0].bid[0].dealid, + meta: { + cid: serverResponse.body.seatbid[0].bid[0].cid, + adomain: serverResponse.body.seatbid[0].bid[0].adomain, + mediaType: serverResponse.body.seatbid[0].bid[0].ext.mediaType, + }, + }]; + expect(result).deep.equal(expected); + }); + + it('invalid bid response. requestId is not exists in bid response', () => { + const invalidServerResponse = deepClone(serverResponse); + delete invalidServerResponse.body.seatbid[0].bid[0].id; + + const result = spec.interpretResponse(invalidServerResponse); + expect(result).deep.equal([]); + }); + + it('invalid bid response. cpm is not exists in bid response', () => { + const invalidServerResponse = deepClone(serverResponse); + delete invalidServerResponse.body.seatbid[0].bid[0].price; + + const result = spec.interpretResponse(invalidServerResponse); + expect(result).deep.equal([]); + }); + + it('invalid bid response. creativeId is not exists in bid response', () => { + const invalidServerResponse = deepClone(serverResponse); + delete invalidServerResponse.body.seatbid[0].bid[0].crid; + + const result = spec.interpretResponse(invalidServerResponse); + expect(result).deep.equal([]); + }); + + it('invalid bid response. width is not exists in bid response', () => { + const invalidServerResponse = deepClone(serverResponse); + delete invalidServerResponse.body.seatbid[0].bid[0].w; + + const result = spec.interpretResponse(invalidServerResponse); + expect(result).deep.equal([]); + }); + + it('invalid bid response. height is not exists in bid response', () => { + const invalidServerResponse = deepClone(serverResponse); + delete invalidServerResponse.body.seatbid[0].bid[0].h; + + const result = spec.interpretResponse(invalidServerResponse); + expect(result).deep.equal([]); + }); + + it('invalid bid response. ad is not exists in bid response', () => { + const invalidServerResponse = deepClone(serverResponse); + delete invalidServerResponse.body.seatbid[0].bid[0].adm; + + const result = spec.interpretResponse(invalidServerResponse); + expect(result).deep.equal([]); + }); + }); +}); diff --git a/test/spec/modules/welectBidAdapter_spec.js b/test/spec/modules/welectBidAdapter_spec.js new file mode 100644 index 00000000000..5f047904c76 --- /dev/null +++ b/test/spec/modules/welectBidAdapter_spec.js @@ -0,0 +1,205 @@ +import {expect} from 'chai'; +import {spec as adapter} from 'modules/welectBidAdapter.js'; + +describe('WelectAdapter', function () { + describe('Check methods existance', function () { + it('exists and is a function', function () { + expect(adapter.isBidRequestValid).to.exist.and.to.be.a('function'); + }); + it('exists and is a function', function () { + expect(adapter.buildRequests).to.exist.and.to.be.a('function'); + }); + it('exists and is a function', function () { + expect(adapter.interpretResponse).to.exist.and.to.be.a('function'); + }); + }); + + describe('Check method isBidRequestValid return', function () { + let bid = { + bidder: 'welect', + params: { + placementId: 'exampleAlias', + domain: 'www.welect.de' + }, + sizes: [[640, 360]], + mediaTypes: { + video: { + context: 'instream' + } + }, + }; + let bid2 = { + bidder: 'welect', + params: { + domain: 'www.welect.de' + }, + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 360] + } + }, + }; + + it('should be true', function () { + expect(adapter.isBidRequestValid(bid)).to.be.true; + }); + + it('should be false because the placementId is missing', function () { + expect(adapter.isBidRequestValid(bid2)).to.be.false; + }); + }); + + describe('Check buildRequests method', function () { + // Bids to be formatted + let bid1 = { + bidder: 'welect', + params: { + placementId: 'exampleAlias' + }, + sizes: [[640, 360]], + mediaTypes: { + video: { + context: 'instream' + } + }, + bidId: 'abdc' + }; + let bid2 = { + bidder: 'welect', + params: { + placementId: 'exampleAlias', + domain: 'www.welect2.de' + }, + sizes: [[640, 360]], + mediaTypes: { + video: { + context: 'instream' + } + }, + bidId: 'abdc', + gdprConsent: { + gdprApplies: 1, + gdprConsent: 'some_string' + } + }; + + let data1 = { + bid_id: 'abdc', + width: 640, + height: 360 + } + + let data2 = { + bid_id: 'abdc', + width: 640, + height: 360, + gdpr_consent: { + gdprApplies: 1, + tcString: 'some_string' + } + } + + // Formatted requets + let request1 = { + method: 'POST', + url: 'https://www.welect.de/api/v2/preflight/by_alias/exampleAlias', + data: data1, + options: { + contentType: 'application/json', + withCredentials: false, + crossOrigin: true, + } + }; + + let request2 = { + method: 'POST', + url: 'https://www.welect2.de/api/v2/preflight/by_alias/exampleAlias', + data: data2, + options: { + contentType: 'application/json', + withCredentials: false, + crossOrigin: true, + } + } + + it('defaults to www.welect.de, without gdpr object', function () { + expect(adapter.buildRequests([bid1])).to.deep.equal([request1]); + }) + + it('must return the right formatted requests, with gdpr object', function () { + expect(adapter.buildRequests([bid2])).to.deep.equal([request2]); + }); + }); + + describe('Check interpretResponse method return', function () { + // invalid server response + let unavailableResponse = { + body: { + available: false + } + }; + + let availableResponse = { + body: { + available: true, + bidResponse: { + ad: { + video: 'some vast url' + }, + cpm: 17, + creativeId: 'svmpreview', + currency: 'EUR', + netRevenue: true, + requestId: 'some bid id', + ttl: 120, + vastUrl: 'some vast url', + height: 640, + width: 320 + } + } + } + // bid Request + let bid = { + data: { + bid_id: 'some bid id', + width: 640, + height: 320, + gdpr_consent: { + gdprApplies: 1, + tcString: 'some_string' + } + }, + method: 'POST', + url: 'https://www.welect.de/api/v2/preflight/by_alias/exampleAlias', + options: { + contentType: 'application/json', + withCredentials: false, + crossOrigin: true, + } + }; + // Formatted reponse + let result = { + ad: { + video: 'some vast url' + }, + cpm: 17, + creativeId: 'svmpreview', + currency: 'EUR', + height: 640, + netRevenue: true, + requestId: 'some bid id', + ttl: 120, + vastUrl: 'some vast url', + width: 320 + } + + it('if response reflects unavailability, should be empty', function () { + expect(adapter.interpretResponse(unavailableResponse, bid)).to.deep.equal([]); + }); + + it('if response reflects availability, should equal result', function() { + expect(adapter.interpretResponse(availableResponse, bid)).to.deep.equal([result]) + }) + }); +}); diff --git a/test/spec/modules/yieldlabBidAdapter_spec.js b/test/spec/modules/yieldlabBidAdapter_spec.js index 5dcd112228a..90fa26fa823 100644 --- a/test/spec/modules/yieldlabBidAdapter_spec.js +++ b/test/spec/modules/yieldlabBidAdapter_spec.js @@ -10,7 +10,12 @@ const REQUEST = { 'adSize': '728x90', 'targeting': { 'key1': 'value1', - 'key2': 'value2' + 'key2': 'value2', + 'notDoubleEncoded': 'value3,value4' + }, + 'customParams': { + 'extraParam': true, + 'foo': 'bar' }, 'extId': 'abc' }, @@ -25,7 +30,24 @@ const REQUEST = { 'id': 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg', 'atype': 1 }] - }] + }], + 'schain': { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'indirectseller.com', + 'sid': '1', + 'hp': 1 + }, + { + 'asi': 'indirectseller2.com', + 'name': 'indirectseller2 name with comma , and bang !', + 'sid': '2', + 'hp': 1 + } + ] + } } const RESPONSE = { @@ -42,6 +64,16 @@ const VIDEO_RESPONSE = Object.assign({}, RESPONSE, { 'adtype': 'VIDEO' }) +const REQPARAMS = { + json: true, + ts: 1234567890 +} + +const REQPARAMS_GDPR = Object.assign({}, REQPARAMS, { + gdpr: true, + consent: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA' +}) + describe('yieldlabBidAdapter', function () { const adapter = newBidder(spec) @@ -80,14 +112,36 @@ describe('yieldlabBidAdapter', function () { expect(request.validBidRequests).to.eql([REQUEST]) }) - it('passes targeting to bid request', function () { - expect(request.url).to.include('t=key1%3Dvalue1%26key2%3Dvalue2') + it('passes single-encoded targeting to bid request', function () { + expect(request.url).to.include('t=key1%3Dvalue1%26key2%3Dvalue2%26notDoubleEncoded%3Dvalue3%2Cvalue4') }) it('passes userids to bid request', function () { expect(request.url).to.include('ids=netid.de%3AfH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg') }) + it('passes extra params to bid request', function () { + expect(request.url).to.include('extraParam=true&foo=bar') + }) + + it('passes unencoded schain string to bid request', function () { + expect(request.url).to.include('schain=1.0,1!indirectseller.com,1,1,,,,!indirectseller2.com,2,1,,indirectseller2%20name%20with%20comma%20%2C%20and%20bang%20%21,,') + }) + + const refererRequest = spec.buildRequests(bidRequests, { + refererInfo: { + canonicalUrl: undefined, + numIframes: 0, + reachedTop: true, + referer: 'https://www.yieldlab.de/test?with=querystring', + stack: ['https://www.yieldlab.de/test?with=querystring'] + } + }) + + it('passes encoded referer to bid request', function () { + expect(refererRequest.url).to.include('pubref=https%3A%2F%2Fwww.yieldlab.de%2Ftest%3Fwith%3Dquerystring') + }) + const gdprRequest = spec.buildRequests(bidRequests, { gdprConsent: { consentString: 'BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA', @@ -108,7 +162,7 @@ describe('yieldlabBidAdapter', function () { }) it('should get correct bid response', function () { - const result = spec.interpretResponse({body: [RESPONSE]}, {validBidRequests: [REQUEST]}) + const result = spec.interpretResponse({body: [RESPONSE]}, {validBidRequests: [REQUEST], queryParams: REQPARAMS}) expect(result[0].requestId).to.equal('2d925f27f5079f') expect(result[0].cpm).to.equal(0.01) @@ -124,6 +178,13 @@ describe('yieldlabBidAdapter', function () { expect(result[0].ad).to.include('&id=abc') }) + it('should append gdpr parameters to adtag', function () { + const result = spec.interpretResponse({body: [RESPONSE]}, {validBidRequests: [REQUEST], queryParams: REQPARAMS_GDPR}) + + expect(result[0].ad).to.include('&gdpr=true') + expect(result[0].ad).to.include('&consent=BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA') + }) + it('should get correct bid response when passing more than one size', function () { const REQUEST2 = Object.assign({}, REQUEST, { 'sizes': [ @@ -132,7 +193,7 @@ describe('yieldlabBidAdapter', function () { [970, 90], ] }) - const result = spec.interpretResponse({body: [RESPONSE]}, {validBidRequests: [REQUEST2]}) + const result = spec.interpretResponse({body: [RESPONSE]}, {validBidRequests: [REQUEST2], queryParams: REQPARAMS}) expect(result[0].requestId).to.equal('2d925f27f5079f') expect(result[0].cpm).to.equal(0.01) @@ -156,7 +217,7 @@ describe('yieldlabBidAdapter', function () { } } }) - const result = spec.interpretResponse({body: [VIDEO_RESPONSE]}, {validBidRequests: [VIDEO_REQUEST]}) + const result = spec.interpretResponse({body: [VIDEO_RESPONSE]}, {validBidRequests: [VIDEO_REQUEST], queryParams: REQPARAMS}) expect(result[0].requestId).to.equal('2d925f27f5079f') expect(result[0].cpm).to.equal(0.01) @@ -165,6 +226,20 @@ describe('yieldlabBidAdapter', function () { expect(result[0].vastUrl).to.include('&id=abc') }) + it('should append gdpr parameters to vastUrl', function () { + const VIDEO_REQUEST = Object.assign({}, REQUEST, { + 'mediaTypes': { + 'video': { + 'context': 'instream' + } + } + }) + const result = spec.interpretResponse({body: [VIDEO_RESPONSE]}, {validBidRequests: [VIDEO_REQUEST], queryParams: REQPARAMS_GDPR}) + + expect(result[0].vastUrl).to.include('&gdpr=true') + expect(result[0].vastUrl).to.include('&consent=BN5lERiOMYEdiAKAWXEND1AAAAE6DABACMA') + }) + it('should add renderer if outstream context', function () { const OUTSTREAM_REQUEST = Object.assign({}, REQUEST, { 'mediaTypes': { @@ -174,7 +249,7 @@ describe('yieldlabBidAdapter', function () { } } }) - const result = spec.interpretResponse({body: [VIDEO_RESPONSE]}, {validBidRequests: [OUTSTREAM_REQUEST]}) + const result = spec.interpretResponse({body: [VIDEO_RESPONSE]}, {validBidRequests: [OUTSTREAM_REQUEST], queryParams: REQPARAMS}) expect(result[0].renderer.id).to.equal('2d925f27f5079f') expect(result[0].renderer.url).to.equal('https://ad2.movad.net/dynamic.ad?a=o193092&ma_loadEvent=ma-start-event') diff --git a/test/spec/modules/yieldmoBidAdapter_spec.js b/test/spec/modules/yieldmoBidAdapter_spec.js index 6858fead750..caeb26266fe 100644 --- a/test/spec/modules/yieldmoBidAdapter_spec.js +++ b/test/spec/modules/yieldmoBidAdapter_spec.js @@ -90,7 +90,7 @@ describe('YieldmoAdapter', function () { it('should place bid information into the p parameter of data', function () { let placementInfo = spec.buildRequests(bidArray, bidderRequest).data.p; expect(placementInfo).to.equal( - encodeURIComponent('[{"placement_id":"adunit-code","callback_id":"30b31c1838de1e","sizes":[[300,250],[300,600]],"bidFloor":0.1}]') + '[{"placement_id":"adunit-code","callback_id":"30b31c1838de1e","sizes":[[300,250],[300,600]],"bidFloor":0.1}]' ); bidArray.push({ bidder: 'yieldmo', @@ -117,20 +117,20 @@ describe('YieldmoAdapter', function () { // multiple placements placementInfo = spec.buildRequests(bidArray, bidderRequest).data.p; expect(placementInfo).to.equal( - encodeURIComponent('[{"placement_id":"adunit-code","callback_id":"30b31c1838de1e","sizes":[[300,250],[300,600]],"bidFloor":0.1},{"placement_id":"adunit-code-1","callback_id":"123456789","sizes":[[300,250],[300,600]],"bidFloor":0.2}]') + '[{"placement_id":"adunit-code","callback_id":"30b31c1838de1e","sizes":[[300,250],[300,600]],"bidFloor":0.1},{"placement_id":"adunit-code-1","callback_id":"123456789","sizes":[[300,250],[300,600]],"bidFloor":0.2}]' ); }); it('should add placement id if given', function () { bidArray[0].params.placementId = 'ym_1293871298'; let placementInfo = spec.buildRequests(bidArray, bidderRequest).data.p; - expect(placementInfo).to.include(encodeURIComponent('"ym_placement_id":"ym_1293871298"')); - expect(placementInfo).not.to.include(encodeURIComponent('"ym_placement_id":"ym_0987654321"')); + expect(placementInfo).to.include('"ym_placement_id":"ym_1293871298"'); + expect(placementInfo).not.to.include('"ym_placement_id":"ym_0987654321"'); bidArray[1].params.placementId = 'ym_0987654321'; placementInfo = spec.buildRequests(bidArray, bidderRequest).data.p; - expect(placementInfo).to.include(encodeURIComponent('"ym_placement_id":"ym_1293871298"')); - expect(placementInfo).to.include(encodeURIComponent('"ym_placement_id":"ym_0987654321"')); + expect(placementInfo).to.include('"ym_placement_id":"ym_1293871298"'); + expect(placementInfo).to.include('"ym_placement_id":"ym_0987654321"'); }); it('should add additional information to data parameter of request', function () { @@ -140,12 +140,13 @@ describe('YieldmoAdapter', function () { expect(data.hasOwnProperty('pr')).to.be.true; expect(data.hasOwnProperty('scrd')).to.be.true; expect(data.dnt).to.be.false; - expect(data.e).to.equal(90); expect(data.hasOwnProperty('description')).to.be.true; expect(data.hasOwnProperty('title')).to.be.true; expect(data.hasOwnProperty('h')).to.be.true; expect(data.hasOwnProperty('w')).to.be.true; expect(data.hasOwnProperty('pubcid')).to.be.true; + expect(data.userConsent).to.equal('{"gdprApplies":"","cmp":""}'); + expect(data.us_privacy).to.equal(''); }); it('should add pubcid as parameter of request', function () { @@ -230,10 +231,10 @@ describe('YieldmoAdapter', function () { }; const data = spec.buildRequests(bidArray, bidderRequest).data; expect(data.userConsent).equal( - encodeURIComponent(JSON.stringify({ + JSON.stringify({ gdprApplies: true, cmp: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', - })) + }) ); }); @@ -252,7 +253,7 @@ describe('YieldmoAdapter', function () { }; bidArray[0].schain = schain; const request = spec.buildRequests([bidArray[0]], bidderRequest); - expect(request.data.schain).equal(encodeURIComponent(JSON.stringify(schain))); + expect(request.data.schain).equal(JSON.stringify(schain)); }); }); diff --git a/test/spec/modules/yieldoneAnalyticsAdapter_spec.js b/test/spec/modules/yieldoneAnalyticsAdapter_spec.js index bc1001cc6c1..81a6365bba2 100644 --- a/test/spec/modules/yieldoneAnalyticsAdapter_spec.js +++ b/test/spec/modules/yieldoneAnalyticsAdapter_spec.js @@ -219,14 +219,6 @@ describe('Yieldone Prebid Analytic', function () { { eventType: constants.EVENTS.BID_TIMEOUT, params: Object.assign(request[2]) - }, - { - eventType: constants.EVENTS.AUCTION_END, - params: { - auctionId: auctionId, - adServerTargeting: fakeTargeting, - bidsReceived: preparedResponses.slice(0, 3) - } } ]; const expectedResult = { diff --git a/test/spec/modules/yuktamediaAnalyticsAdapter_spec.js b/test/spec/modules/yuktamediaAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..e8eb4ab73be --- /dev/null +++ b/test/spec/modules/yuktamediaAnalyticsAdapter_spec.js @@ -0,0 +1,713 @@ +import yuktamediaAnalyticsAdapter from 'modules/yuktamediaAnalyticsAdapter.js'; +import { expect } from 'chai'; +let events = require('src/events'); +let constants = require('src/constants.json'); + +let prebidAuction = { + 'auctionInit': { + 'auctionId': 'ca421611-0bc0-4164-a69c-fe4158c68954', + 'timestamp': 1595850680304, + }, + 'bidRequested': { + 'bidderCode': 'appnexus', + 'auctionId': 'ca421611-0bc0-4164-a69c-fe4158c68954', + 'bidderRequestId': '181df4d465699c', + 'bids': [ + { + 'bidder': 'appnexus', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ], + [ + 300, + 600 + ] + ] + } + }, + 'userId': { + 'id5id': { uid: 'ID5-ZHMOxXeRXPe3inZKGD-Lj0g7y8UWdDbsYXQ_n6aWMQ' }, + 'parrableid': '01.1595590997.46d951017bdc272ca50b88dbcfb0545cfc636bec3e3d8c02091fb1b413328fb2fd3baf65cb4114b3f782895fd09f82f02c9042b85b42c4654d08ba06dc77f0ded936c8ea3fc4085b4a99', + 'pubcid': '100a8bc9-f588-4c22-873e-a721cb68bc34' + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'sizes': [ + [ + 300, + 250 + ], + [ + 300, + 600 + ] + ], + 'bidId': '2bccebeda7fbe4', + 'bidderRequestId': '181df4d465699c', + 'auctionId': 'ca421611-0bc0-4164-a69c-fe4158c68954', + 'src': 'client', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 1, + 'bidderWinsCount': 0 + } + ], + 'auctionStart': 1595850680304, + 'timeout': 1100, + 'start': 1595850680307 + }, + 'noBid': {}, + 'bidTimeout': [], + 'bidResponse': { + 'bidderCode': 'appnexus', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'getStatusCode': function () { return 1; }, + 'adId': '3ade442375213f', + 'requestId': '2bccebeda7fbe4', + 'mediaType': 'banner', + 'source': 'client', + 'cpm': 0.5, + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 300, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'auctionId': 'ca421611-0bc0-4164-a69c-fe4158c68954', + 'responseTimestamp': 1595850681254, + 'requestTimestamp': 1595850680307, + 'bidder': 'appnexus', + 'timeToRespond': 947, + 'size': '300x250', + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_adid': '3ade442375213f', + 'hb_pb': '0.50', + 'hb_size': '300x250', + 'hb_source': 'client', + 'hb_format': 'banner' + } + }, + 'auctionEnd': { + 'auctionId': 'ca421611-0bc0-4164-a69c-fe4158c68954' + }, + 'bidWon': { + 'bidderCode': 'appnexus', + 'width': 300, + 'height': 250, + 'requestId': '2bccebeda7fbe4', + 'mediaType': 'banner', + 'source': 'client', + 'cpm': 0.5, + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 300, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'auctionId': 'ca421611-0bc0-4164-a69c-fe4158c68954', + 'responseTimestamp': 1595850681254, + 'requestTimestamp': 1595850680307, + 'bidder': 'appnexus', + 'timeToRespond': 947, + 'size': '300x250', + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_adid': '3ade442375213f', + 'hb_pb': '0.50', + 'hb_size': '300x250', + 'hb_source': 'client', + 'hb_format': 'banner' + }, + 'status': 'rendered' + } +}; + +let prebidNativeAuction = { + 'auctionInit': { + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128', + 'timestamp': 1595589742100, + }, + 'bidRequested': { + 'bidderCode': 'appnexus', + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128', + 'tid': 'f9c220eb-e44f-412b-92ff-8c24085ca675', + 'bids': [ + { + 'bidder': 'appnexus', + 'bid_id': '19a879bd73bc8d', + 'nativeParams': { + 'title': { + 'required': true, + 'len': 800 + }, + 'image': { + 'required': true, + 'sizes': [ + 989, + 742 + ] + }, + 'sponsoredBy': { + 'required': true + } + }, + 'mediaTypes': { + 'native': { + 'title': { + 'required': true, + 'len': 800 + }, + 'image': { + 'required': true, + 'sizes': [ + 989, + 742 + ] + }, + 'sponsoredBy': { + 'required': true + } + } + }, + 'adUnitCode': '/19968336/prebid_native_example_1', + 'sizes': [], + 'bidId': '19a879bd73bc8d', + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128', + 'src': 's2s', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 0, + 'bidderWinsCount': 0 + }, + { + 'bidder': 'appnexus', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ], + [ + 300, + 600 + ] + ] + } + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'sizes': [ + [ + 300, + 250 + ], + [ + 300, + 600 + ] + ], + 'bidId': '28f8cc7d10f2db', + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128', + 'src': 's2s', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 2, + 'bidderWinsCount': 0 + } + ], + 'auctionStart': 1595589742100, + 'timeout': 1000, + 'src': 's2s', + 'start': 1595589742108 + }, + 'bidRequested1': { + 'bidderCode': 'ix', + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128', + 'bidderRequestId': '5e64168f3654af', + 'bids': [ + { + 'bidder': 'ix', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ] + ] + } + }, + 'adUnitCode': 'dfp-ad-rightrail_top', + 'sizes': [[300, 250]], + 'bidId': '9424dea605368f', + 'bidderRequestId': '5e64168f3654af', + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128', + 'src': 's2s' + } + ], + 'auctionStart': 1595589742100, + 'timeout': 1000, + 'src': 's2s', + 'start': 1595589742108 + }, + 'noBid': { + 'bidder': 'ix', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 300, + 250 + ] + ] + } + }, + 'adUnitCode': 'dfp-ad-rightrail_top', + 'transactionId': 'd99d90e0-663a-459d-8c87-4c92ce6a527c', + 'sizes': [[300, 250]], + 'bidId': '9424dea605368f', + 'bidderRequestId': '5e64168f3654af', + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128', + 'src': 's2s', + 'bidRequestsCount': 1, + 'bidderRequestsCount': 4, + 'bidderWinsCount': 0 + }, + 'bidTimeout': [ + { + 'bidId': '28f8cc7d10f2db', + 'bidder': 'appnexus', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128' + } + ], + 'bidResponse': { + 'bidderCode': 'appnexus', + 'statusMessage': 'Bid available', + 'source': 's2s', + 'getStatusCode': function () { return 1; }, + 'cpm': 10, + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_pb': '10.00', + 'hb_adid': '4e756c72ee9044', + 'hb_size': 'undefinedxundefined', + 'hb_source': 's2s', + 'hb_format': 'native', + 'hb_native_linkurl': 'some_long_url', + 'hb_native_title': 'This is a Prebid Native Creative', + 'hb_native_brand': 'Prebid.org' + }, + 'native': { + 'clickUrl': { + 'url': 'some_long_url' + }, + 'impressionTrackers': [ + 'some_long_url' + ], + 'javascriptTrackers': [], + 'image': { + 'url': 'some_long_image_path', + 'width': 989, + 'height': 742 + }, + 'title': 'This is a Prebid Native Creative', + 'sponsoredBy': 'Prebid.org' + }, + 'currency': 'USD', + 'ttl': 60, + 'netRevenue': true, + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128', + 'responseTimestamp': 1595589742827, + 'requestTimestamp': 1595589742108, + 'bidder': 'appnexus', + 'adUnitCode': '/19968336/prebid_native_example_1', + 'timeToRespond': 719, + 'size': 'undefinedxundefined' + }, + 'auctionEnd': { + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128' + }, + 'bidWon': { + 'bidderCode': 'appnexus', + 'mediaType': 'native', + 'source': 's2s', + 'getStatusCode': function () { return 1; }, + 'cpm': 10, + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_pb': '10.00', + 'hb_adid': '4e756c72ee9044', + 'hb_size': 'undefinedxundefined', + 'hb_source': 's2s', + 'hb_format': 'native', + 'hb_native_linkurl': 'some_long_url', + 'hb_native_title': 'This is a Prebid Native Creative', + 'hb_native_brand': 'Prebid.org' + }, + 'native': { + 'clickUrl': { + 'url': 'some_long_url' + }, + 'impressionTrackers': [ + 'some_long_url' + ], + 'javascriptTrackers': [], + 'image': { + 'url': 'some_long_image_path', + 'width': 989, + 'height': 742 + }, + 'title': 'This is a Prebid Native Creative', + 'sponsoredBy': 'Prebid.org' + }, + 'currency': 'USD', + 'ttl': 60, + 'netRevenue': true, + 'auctionId': '86e005fa-1900-4782-b6df-528500f09128', + 'responseTimestamp': 1595589742827, + 'requestTimestamp': 1595589742108, + 'bidder': 'appnexus', + 'adUnitCode': '/19968336/prebid_native_example_1', + 'timeToRespond': 719, + 'size': 'undefinedxundefined', + 'status': 'rendered' + } +} + +describe('yuktamedia analytics adapter', function () { + beforeEach(() => { + sinon.stub(events, 'getEvents').returns([]); + }); + afterEach(() => { + events.getEvents.restore(); + }); + + describe('enableAnalytics', function () { + beforeEach(() => { + sinon.spy(yuktamediaAnalyticsAdapter, 'track'); + }); + afterEach(() => { + yuktamediaAnalyticsAdapter.disableAnalytics(); + yuktamediaAnalyticsAdapter.track.restore(); + }); + + it('should catch all events 1', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.AUCTION_INIT, prebidAuction[constants.EVENTS.AUCTION_INIT]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch all events 2', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.BID_REQUESTED, prebidAuction[constants.EVENTS.BID_REQUESTED]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch all events 3', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.NO_BID, prebidAuction[constants.EVENTS.NO_BID]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch all events 4', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.BID_TIMEOUT, prebidAuction[constants.EVENTS.BID_TIMEOUT]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch all events 5', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.BID_RESPONSE, prebidAuction[constants.EVENTS.BID_RESPONSE]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch all events 6', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.AUCTION_END, prebidAuction[constants.EVENTS.AUCTION_END]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch no events if no pubKey and pubId', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + } + }); + + events.emit(constants.EVENTS.AUCTION_INIT, {}); + events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(constants.EVENTS.BID_REQUESTED, {}); + events.emit(constants.EVENTS.BID_RESPONSE, {}); + events.emit(constants.EVENTS.BID_WON, {}); + + sinon.assert.callCount(yuktamediaAnalyticsAdapter.track, 0); + }); + + it('should catch nobid, timeout and bidwon event events one of eight', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.AUCTION_INIT, prebidNativeAuction[constants.EVENTS.AUCTION_INIT]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch nobid, timeout and bidwon event events two of eight', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.BID_REQUESTED, prebidNativeAuction[constants.EVENTS.BID_REQUESTED]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch nobid, timeout and bidwon event events three of eight', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.BID_REQUESTED, prebidNativeAuction[constants.EVENTS.BID_REQUESTED + '1']); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch nobid, timeout and bidwon event events four of eight', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.NO_BID, prebidNativeAuction[constants.EVENTS.NO_BID]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch nobid, timeout and bidwon event events five of eight', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.BID_TIMEOUT, prebidNativeAuction[constants.EVENTS.BID_TIMEOUT]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch nobid, timeout and bidwon event events six of eight', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.BID_RESPONSE, prebidNativeAuction[constants.EVENTS.BID_RESPONSE]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch nobid, timeout and bidwon event events seven of eight', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.AUCTION_END, prebidNativeAuction[constants.EVENTS.AUCTION_END]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + + it('should catch nobid, timeout and bidwon event events eight of eight', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.AUCTION_END, prebidNativeAuction[constants.EVENTS.BID_WON]); + sinon.assert.called(yuktamediaAnalyticsAdapter.track); + }); + }); + + describe('build utm tag data', function () { + beforeEach(function () { + localStorage.setItem('yuktamediaAnalytics_utm_source', 'prebid'); + localStorage.setItem('yuktamediaAnalytics_utm_medium', 'ad'); + localStorage.setItem('yuktamediaAnalytics_utm_campaign', ''); + localStorage.setItem('yuktamediaAnalytics_utm_term', ''); + localStorage.setItem('yuktamediaAnalytics_utm_content', ''); + localStorage.setItem('yuktamediaAnalytics_utm_timeout', Date.now()); + }); + + afterEach(function () { + localStorage.clear(); + }); + + it('should build utm data from local storage', function () { + let utmTagData = yuktamediaAnalyticsAdapter.buildUtmTagData({ + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + }); + expect(utmTagData.utm_source).to.equal('prebid'); + expect(utmTagData.utm_medium).to.equal('ad'); + expect(utmTagData.utm_campaign).to.equal(''); + expect(utmTagData.utm_term).to.equal(''); + expect(utmTagData.utm_content).to.equal(''); + }); + + it('should return empty object for disabled utm setting', function () { + let utmTagData = yuktamediaAnalyticsAdapter.buildUtmTagData({ + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: false, + enableSession: true, + enableUserIdCollection: true + }); + expect(utmTagData).deep.equal({}); + }); + }); + + describe('build session information', function () { + beforeEach(() => { + sinon.spy(yuktamediaAnalyticsAdapter, 'track'); + localStorage.clear(); + }); + afterEach(() => { + yuktamediaAnalyticsAdapter.disableAnalytics(); + yuktamediaAnalyticsAdapter.track.restore(); + localStorage.clear(); + }); + + it('should create session id in local storage if enabled', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: true, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.AUCTION_INIT, prebidAuction[constants.EVENTS.AUCTION_INIT]); + events.emit(constants.EVENTS.BID_REQUESTED, prebidAuction[constants.EVENTS.BID_REQUESTED]); + events.emit(constants.EVENTS.NO_BID, prebidAuction[constants.EVENTS.NO_BID]); + events.emit(constants.EVENTS.BID_TIMEOUT, prebidAuction[constants.EVENTS.BID_TIMEOUT]); + events.emit(constants.EVENTS.BID_RESPONSE, prebidAuction[constants.EVENTS.BID_RESPONSE]); + events.emit(constants.EVENTS.AUCTION_END, prebidAuction[constants.EVENTS.AUCTION_END]); + expect(localStorage.getItem('yuktamediaAnalytics_session_id')).to.not.equal(null); + }); + + it('should not create session id in local storage if disabled', function () { + yuktamediaAnalyticsAdapter.enableAnalytics({ + provider: 'yuktamedia', + options: { + pubId: '1', + pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==', + enableUTMCollection: true, + enableSession: false, + enableUserIdCollection: true + } + }); + events.emit(constants.EVENTS.AUCTION_INIT, prebidAuction[constants.EVENTS.AUCTION_INIT]); + events.emit(constants.EVENTS.BID_REQUESTED, prebidAuction[constants.EVENTS.BID_REQUESTED]); + events.emit(constants.EVENTS.NO_BID, prebidAuction[constants.EVENTS.NO_BID]); + events.emit(constants.EVENTS.BID_TIMEOUT, prebidAuction[constants.EVENTS.BID_TIMEOUT]); + events.emit(constants.EVENTS.BID_RESPONSE, prebidAuction[constants.EVENTS.BID_RESPONSE]); + events.emit(constants.EVENTS.AUCTION_END, prebidAuction[constants.EVENTS.AUCTION_END]); + expect(localStorage.getItem('yuktamediaAnalytics_session_id')).to.equal(null); + }); + }); +}); diff --git a/test/spec/modules/yuktamediaAnalyticsAdaptor_spec.js b/test/spec/modules/yuktamediaAnalyticsAdaptor_spec.js deleted file mode 100644 index 24a524c85c7..00000000000 --- a/test/spec/modules/yuktamediaAnalyticsAdaptor_spec.js +++ /dev/null @@ -1,788 +0,0 @@ -import yuktamediaAnalyticsAdapter from 'modules/yuktamediaAnalyticsAdapter.js'; -import { expect } from 'chai'; -import adapterManager from 'src/adapterManager.js'; -import * as utils from 'src/utils.js'; -import { server } from 'test/mocks/xhr.js'; - -let events = require('src/events'); -let constants = require('src/constants.json'); - -describe('yuktamedia analytics adapter', function () { - beforeEach(function () { - sinon.stub(events, 'getEvents').returns([]); - }); - - afterEach(function () { - events.getEvents.restore(); - }); - - describe('track', function () { - let initOptions = { - pubId: '1', - pubKey: 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==' - }; - - let prebidEvent = { - 'addAdUnits': {}, - 'requestBids': {}, - 'auctionInit': { - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'timestamp': 1576823893836, - 'auctionStatus': 'inProgress', - 'adUnits': [ - { - 'code': 'div-gpt-ad-1460505748561-0', - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ] - } - }, - 'bids': [ - { - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 - }, - 'crumbs': { - 'pubcid': 'ff4002c4-ce05-4a61-b4ef-45a3cd93991a' - } - } - ], - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'transactionId': '6d275806-1943-4f3e-9cd5-624cbd05ad98' - } - ], - 'adUnitCodes': [ - 'div-gpt-ad-1460505748561-0' - ], - 'bidderRequests': [ - { - 'bidderCode': 'appnexus', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'bidderRequestId': '155975c76e13b1', - 'bids': [ - { - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 - }, - 'crumbs': { - 'pubcid': 'ff4002c4-ce05-4a61-b4ef-45a3cd93991a' - }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ] - } - }, - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'transactionId': '6d275806-1943-4f3e-9cd5-624cbd05ad98', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '263efc09896d0c', - 'bidderRequestId': '155975c76e13b1', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - } - ], - 'auctionStart': 1576823893836, - 'timeout': 1000, - 'refererInfo': { - 'referer': 'http://observer.com/integrationExamples/gpt/hello_world.html', - 'reachedTop': true, - 'numIframes': 0, - 'stack': [ - 'http://observer.com/integrationExamples/gpt/hello_world.html' - ] - }, - 'start': 1576823893838 - } - ], - 'noBids': [], - 'bidsReceived': [], - 'winningBids': [], - 'timeout': 1000 - }, - 'bidRequested': { - 'bidderCode': 'appnexus', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'bidderRequestId': '155975c76e13b1', - 'bids': [ - { - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 - }, - 'crumbs': { - 'pubcid': 'ff4002c4-ce05-4a61-b4ef-45a3cd93991a' - }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ] - } - }, - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'transactionId': '6d275806-1943-4f3e-9cd5-624cbd05ad98', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '263efc09896d0c', - 'bidderRequestId': '155975c76e13b1', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - } - ], - 'auctionStart': 1576823893836, - 'timeout': 1000, - 'refererInfo': { - 'referer': 'http://observer.com/integrationExamples/gpt/hello_world.html', - 'reachedTop': true, - 'numIframes': 0, - 'stack': [ - 'http://observer.com/integrationExamples/gpt/hello_world.html' - ] - }, - 'start': 1576823893838 - }, - 'bidAdjustment': { - 'bidderCode': 'appnexus', - 'width': 300, - 'height': 250, - 'statusMessage': 'Bid available', - 'adId': '393976d8770041', - 'requestId': '263efc09896d0c', - 'mediaType': 'banner', - 'source': 'client', - 'cpm': 0.5, - 'creativeId': 96846035, - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 300, - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'appnexus': { - 'buyerMemberId': 9325 - }, - 'meta': { - 'advertiserId': 2529885 - }, - 'ad': '', - 'originalCpm': 0.5, - 'originalCurrency': 'USD', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'responseTimestamp': 1576823894050, - 'requestTimestamp': 1576823893838, - 'bidder': 'appnexus', - 'timeToRespond': 212 - }, - 'bidTimeout': [ - ], - 'bidResponse': { - 'bidderCode': 'appnexus', - 'width': 300, - 'height': 250, - 'statusMessage': 'Bid available', - 'adId': '393976d8770041', - 'requestId': '263efc09896d0c', - 'mediaType': 'banner', - 'source': 'client', - 'cpm': 0.5, - 'creativeId': 96846035, - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 300, - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'appnexus': { - 'buyerMemberId': 9325 - }, - 'meta': { - 'advertiserId': 2529885 - }, - 'ad': '', - 'originalCpm': 0.5, - 'originalCurrency': 'USD', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'responseTimestamp': 1576823894050, - 'requestTimestamp': 1576823893838, - 'bidder': 'appnexus', - 'timeToRespond': 212, - 'pbLg': '0.50', - 'pbMg': '0.50', - 'pbHg': '0.50', - 'pbAg': '0.50', - 'pbDg': '0.50', - 'pbCg': '', - 'size': '300x250', - 'adserverTargeting': { - 'hb_bidder': 'appnexus', - 'hb_adid': '393976d8770041', - 'hb_pb': '0.50', - 'hb_size': '300x250', - 'hb_source': 'client', - 'hb_format': 'banner' - } - }, - 'auctionEnd': { - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'timestamp': 1576823893836, - 'auctionEnd': 1576823894054, - 'auctionStatus': 'completed', - 'adUnits': [ - { - 'code': 'div-gpt-ad-1460505748561-0', - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ] - } - }, - 'bids': [ - { - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 - }, - 'crumbs': { - 'pubcid': 'ff4002c4-ce05-4a61-b4ef-45a3cd93991a' - } - } - ], - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'transactionId': '6d275806-1943-4f3e-9cd5-624cbd05ad98' - } - ], - 'adUnitCodes': [ - 'div-gpt-ad-1460505748561-0' - ], - 'bidderRequests': [ - { - 'bidderCode': 'appnexus', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'bidderRequestId': '155975c76e13b1', - 'bids': [ - { - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 - }, - 'crumbs': { - 'pubcid': 'ff4002c4-ce05-4a61-b4ef-45a3cd93991a' - }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ] - } - }, - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'transactionId': '6d275806-1943-4f3e-9cd5-624cbd05ad98', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '263efc09896d0c', - 'bidderRequestId': '155975c76e13b1', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - } - ], - 'auctionStart': 1576823893836, - 'timeout': 1000, - 'refererInfo': { - 'referer': 'http://observer.com/integrationExamples/gpt/hello_world.html', - 'reachedTop': true, - 'numIframes': 0, - 'stack': [ - 'http://observer.com/integrationExamples/gpt/hello_world.html' - ] - }, - 'start': 1576823893838 - } - ], - 'noBids': [], - 'bidsReceived': [ - { - 'bidderCode': 'appnexus', - 'width': 300, - 'height': 250, - 'statusMessage': 'Bid available', - 'adId': '393976d8770041', - 'requestId': '263efc09896d0c', - 'mediaType': 'banner', - 'source': 'client', - 'cpm': 0.5, - 'creativeId': 96846035, - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 300, - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'appnexus': { - 'buyerMemberId': 9325 - }, - 'meta': { - 'advertiserId': 2529885 - }, - 'ad': '', - 'originalCpm': 0.5, - 'originalCurrency': 'USD', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'responseTimestamp': 1576823894050, - 'requestTimestamp': 1576823893838, - 'bidder': 'appnexus', - 'timeToRespond': 212, - 'pbLg': '0.50', - 'pbMg': '0.50', - 'pbHg': '0.50', - 'pbAg': '0.50', - 'pbDg': '0.50', - 'pbCg': '', - 'size': '300x250', - 'adserverTargeting': { - 'hb_bidder': 'appnexus', - 'hb_adid': '393976d8770041', - 'hb_pb': '0.50', - 'hb_size': '300x250', - 'hb_source': 'client', - 'hb_format': 'banner' - } - } - ], - 'winningBids': [], - 'timeout': 1000 - }, - 'setTargeting': { - 'div-gpt-ad-1460505748561-0': { - 'hb_format': 'banner', - 'hb_source': 'client', - 'hb_size': '300x250', - 'hb_pb': '0.50', - 'hb_adid': '393976d8770041', - 'hb_bidder': 'appnexus', - 'hb_format_appnexus': 'banner', - 'hb_source_appnexus': 'client', - 'hb_size_appnexus': '300x250', - 'hb_pb_appnexus': '0.50', - 'hb_adid_appnexus': '393976d8770041', - 'hb_bidder_appnexus': 'appnexus' - } - }, - 'bidderDone': { - 'bidderCode': 'appnexus', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'bidderRequestId': '155975c76e13b1', - 'bids': [ - { - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 - }, - 'crumbs': { - 'pubcid': 'ff4002c4-ce05-4a61-b4ef-45a3cd93991a' - }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ] - } - }, - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'transactionId': '6d275806-1943-4f3e-9cd5-624cbd05ad98', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '263efc09896d0c', - 'bidderRequestId': '155975c76e13b1', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - } - ], - 'auctionStart': 1576823893836, - 'timeout': 1000, - 'refererInfo': { - 'referer': 'http://observer.com/integrationExamples/gpt/hello_world.html', - 'reachedTop': true, - 'numIframes': 0, - 'stack': [ - 'http://observer.com/integrationExamples/gpt/hello_world.html' - ] - }, - 'start': 1576823893838 - }, - 'bidWon': { - 'bidderCode': 'appnexus', - 'width': 300, - 'height': 250, - 'statusMessage': 'Bid available', - 'adId': '393976d8770041', - 'requestId': '263efc09896d0c', - 'mediaType': 'banner', - 'source': 'client', - 'cpm': 0.5, - 'creativeId': 96846035, - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 300, - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'appnexus': { - 'buyerMemberId': 9325 - }, - 'meta': { - 'advertiserId': 2529885 - }, - 'ad': '', - 'originalCpm': 0.5, - 'originalCurrency': 'USD', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'responseTimestamp': 1576823894050, - 'requestTimestamp': 1576823893838, - 'bidder': 'appnexus', - 'timeToRespond': 212, - 'pbLg': '0.50', - 'pbMg': '0.50', - 'pbHg': '0.50', - 'pbAg': '0.50', - 'pbDg': '0.50', - 'pbCg': '', - 'size': '300x250', - 'adserverTargeting': { - 'hb_bidder': 'appnexus', - 'hb_adid': '393976d8770041', - 'hb_pb': '0.50', - 'hb_size': '300x250', - 'hb_source': 'client', - 'hb_format': 'banner' - }, - 'status': 'rendered', - 'params': [ - { - 'placementId': 13144370 - } - ] - } - }; - let location = utils.getWindowLocation(); - - let expectedAfterBid = { - 'bids': [ - { - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'bidId': '263efc09896d0c', - 'bidderCode': 'appnexus', - 'cpm': 0.5, - 'creativeId': 96846035, - 'currency': 'USD', - 'mediaType': 'banner', - 'netRevenue': true, - 'renderStatus': 2, - 'requestId': '155975c76e13b1', - 'requestTimestamp': 1576823893838, - 'responseTimestamp': 1576823894050, - 'sizes': '300x250,300x600', - 'statusMessage': 'Bid available', - 'timeToRespond': 212 - } - ], - 'auctionInit': { - 'host': location.host, - 'path': location.pathname, - 'search': location.search, - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'timestamp': 1576823893836, - 'auctionStatus': 'inProgress', - 'adUnits': [ - { - 'code': 'div-gpt-ad-1460505748561-0', - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ] - } - }, - 'bids': [ - { - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 - }, - 'crumbs': { - 'pubcid': 'ff4002c4-ce05-4a61-b4ef-45a3cd93991a' - } - } - ], - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'transactionId': '6d275806-1943-4f3e-9cd5-624cbd05ad98' - } - ], - 'adUnitCodes': [ - 'div-gpt-ad-1460505748561-0' - ], - 'bidderRequests': [ - { - 'bidderCode': 'appnexus', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'bidderRequestId': '155975c76e13b1', - 'bids': [ - { - 'bidder': 'appnexus', - 'params': { - 'placementId': 13144370 - }, - 'crumbs': { - 'pubcid': 'ff4002c4-ce05-4a61-b4ef-45a3cd93991a' - }, - 'mediaTypes': { - 'banner': { - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ] - } - }, - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'transactionId': '6d275806-1943-4f3e-9cd5-624cbd05ad98', - 'sizes': [ - [ - 300, - 250 - ], - [ - 300, - 600 - ] - ], - 'bidId': '263efc09896d0c', - 'bidderRequestId': '155975c76e13b1', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'src': 'client', - 'bidRequestsCount': 1, - 'bidderRequestsCount': 1, - 'bidderWinsCount': 0 - } - ], - 'auctionStart': 1576823893836, - 'timeout': 1000, - 'refererInfo': { - 'referer': 'http://observer.com/integrationExamples/gpt/hello_world.html', - 'reachedTop': true, - 'numIframes': 0, - 'stack': [ - 'http://observer.com/integrationExamples/gpt/hello_world.html' - ] - }, - 'start': 1576823893838 - } - ], - 'noBids': [], - 'bidsReceived': [], - 'winningBids': [], - 'timeout': 1000, - 'config': initOptions - }, - 'initOptions': initOptions - }; - - let expectedAfterBidWon = { - 'bidWon': { - 'bidderCode': 'appnexus', - 'bidId': '263efc09896d0c', - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'auctionId': 'db377024-d866-4a24-98ac-5e430f881313', - 'creativeId': 96846035, - 'currency': 'USD', - 'cpm': 0.5, - 'netRevenue': true, - 'renderedSize': '300x250', - 'mediaType': 'banner', - 'statusMessage': 'Bid available', - 'status': 'rendered', - 'renderStatus': 4, - 'timeToRespond': 212, - 'requestTimestamp': 1576823893838, - 'responseTimestamp': 1576823894050 - }, - 'initOptions': { - 'pubId': '1', - 'pubKey': 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuT==' - } - } - - adapterManager.registerAnalyticsAdapter({ - code: 'yuktamedia', - adapter: yuktamediaAnalyticsAdapter - }); - - beforeEach(function () { - adapterManager.enableAnalytics({ - provider: 'yuktamedia', - options: initOptions - }); - }); - - afterEach(function () { - yuktamediaAnalyticsAdapter.disableAnalytics(); - }); - - it('builds and sends auction data', function () { - // Step 1: Send auction init event - events.emit(constants.EVENTS.AUCTION_INIT, prebidEvent['auctionInit']); - - // Step 2: Send bid requested event - events.emit(constants.EVENTS.BID_REQUESTED, prebidEvent['bidRequested']); - - // Step 3: Send bid response event - events.emit(constants.EVENTS.BID_RESPONSE, prebidEvent['bidResponse']); - - // Step 4: Send bid time out event - events.emit(constants.EVENTS.BID_TIMEOUT, prebidEvent['bidTimeout']); - - // Step 5: Send auction end event - events.emit(constants.EVENTS.AUCTION_END, prebidEvent['auctionEnd']); - - expect(server.requests.length).to.equal(1); - - let realAfterBid = JSON.parse(server.requests[0].requestBody); - - expect(realAfterBid).to.deep.equal(expectedAfterBid); - - // Step 6: Send auction bid won event - events.emit(constants.EVENTS.BID_WON, prebidEvent['bidWon']); - - expect(server.requests.length).to.equal(2); - - let winEventData = JSON.parse(server.requests[1].requestBody); - - expect(winEventData).to.deep.equal(expectedAfterBidWon); - }); - }); -}); diff --git a/test/spec/modules/zedoBidAdapter_spec.js b/test/spec/modules/zedoBidAdapter_spec.js new file mode 100644 index 00000000000..8e5a789656e --- /dev/null +++ b/test/spec/modules/zedoBidAdapter_spec.js @@ -0,0 +1,354 @@ +import { expect } from 'chai'; +import { spec } from 'modules/zedoBidAdapter'; + +describe('The ZEDO bidding adapter', function () { + describe('isBidRequestValid', function () { + it('should return false when given an invalid bid', function () { + const bid = { + bidder: 'zedo', + }; + const isValid = spec.isBidRequestValid(bid); + expect(isValid).to.equal(false); + }); + + it('should return true when given a channelcode bid', function () { + const bid = { + bidder: 'zedo', + params: { + channelCode: 20000000, + dimId: 9 + }, + }; + const isValid = spec.isBidRequestValid(bid); + expect(isValid).to.equal(true); + }); + }); + + describe('buildRequests', function () { + const bidderRequest = { + timeout: 3000, + }; + + it('should properly build a channelCode request for dim Id with type not defined', function () { + const bidRequests = [ + { + bidder: 'zedo', + adUnitCode: 'p12345', + transactionId: '12345667', + sizes: [[300, 200]], + params: { + channelCode: 20000000, + dimId: 10, + pubId: 1 + }, + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.url).to.match(/^https:\/\/saxp.zedo.com\/asw\/fmh.json/); + expect(request.method).to.equal('GET'); + const zedoRequest = request.data; + expect(zedoRequest).to.equal('g={"placements":[{"network":20,"channel":0,"publisher":1,"width":300,"height":200,"dimension":10,"version":"$prebid.version$","keyword":"","transactionId":"12345667","renderers":[{"name":"display"}]}]}'); + }); + + it('should properly build a channelCode request for video with type defined', function () { + const bidRequests = [ + { + bidder: 'zedo', + adUnitCode: 'p12345', + transactionId: '12345667', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'instream', + }, + }, + params: { + channelCode: 20000000, + dimId: 85 + }, + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.url).to.match(/^https:\/\/saxp.zedo.com\/asw\/fmh.json/); + expect(request.method).to.equal('GET'); + const zedoRequest = request.data; + expect(zedoRequest).to.equal('g={"placements":[{"network":20,"channel":0,"publisher":0,"width":640,"height":480,"dimension":85,"version":"$prebid.version$","keyword":"","transactionId":"12345667","renderers":[{"name":"Inarticle"}]}]}'); + }); + + describe('buildGDPRRequests', function () { + let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; + const bidderRequest = { + timeout: 3000, + gdprConsent: { + 'consentString': consentString, + 'gdprApplies': true + } + }; + + it('should properly build request with gdpr consent', function () { + const bidRequests = [ + { + bidder: 'zedo', + adUnitCode: 'p12345', + transactionId: '12345667', + sizes: [[300, 200]], + params: { + channelCode: 20000000, + dimId: 10 + }, + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.method).to.equal('GET'); + const zedoRequest = request.data; + expect(zedoRequest).to.equal('g={"placements":[{"network":20,"channel":0,"publisher":0,"width":300,"height":200,"dimension":10,"version":"$prebid.version$","keyword":"","transactionId":"12345667","renderers":[{"name":"display"}]}],"gdpr":1,"gdpr_consent":"BOJ8RZsOJ8RZsABAB8AAAAAZ+A=="}'); + }); + }); + }); + describe('interpretResponse', function () { + it('should return an empty array when there is bid response', function () { + const response = {}; + const request = { bidRequests: [] }; + const bids = spec.interpretResponse(response, request); + expect(bids).to.have.lengthOf(0); + }); + + it('should properly parse a bid response with no valid creative', function () { + const response = { + body: { + ad: [ + { + 'slotId': 'ad1d762', + 'network': '2000', + 'creatives': [ + { + 'adId': '12345', + 'height': '600', + 'width': '160', + 'isFoc': true, + 'creativeDetails': { + 'type': 'StdBanner', + 'adContent': { + 'focImage': { + 'url': 'https://c13.zedo.com/OzoDB/0/0/0/blank.gif', + 'target': '_blank', + } + } + }, + 'cpm': '0' + } + ] + } + ] + } + }; + const request = { + bidRequests: [{ + bidder: 'zedo', + adUnitCode: 'p12345', + bidId: 'test-bidId', + params: { + channelCode: 2000000, + dimId: 9 + } + }] + }; + const bids = spec.interpretResponse(response, request); + expect(bids).to.have.lengthOf(0); + }); + + it('should properly parse a bid response with valid display creative', function () { + const response = { + body: { + ad: [ + { + 'slotId': 'ad1d762', + 'network': '2000', + 'creatives': [ + { + 'adId': '12345', + 'height': '600', + 'width': '160', + 'isFoc': true, + 'creativeDetails': { + 'type': 'StdBanner', + 'adContent': '' + }, + 'bidCpm': '720000' + } + ] + } + ] + } + }; + const request = { + bidRequests: [{ + bidder: 'zedo', + adUnitCode: 'test-requestId', + bidId: 'test-bidId', + params: { + channelCode: 2000000, + dimId: 9 + }, + }] + }; + const bids = spec.interpretResponse(response, request); + expect(bids).to.have.lengthOf(1); + expect(bids[0].requestId).to.equal('ad1d762'); + expect(bids[0].cpm).to.equal(0.72); + expect(bids[0].width).to.equal('160'); + expect(bids[0].height).to.equal('600'); + }); + + it('should properly parse a bid response with valid video creative', function () { + const response = { + body: { + ad: [ + { + 'slotId': 'ad1d762', + 'network': '2000', + 'creatives': [ + { + 'adId': '12345', + 'height': '480', + 'width': '640', + 'isFoc': true, + 'creativeDetails': { + 'type': 'VAST', + 'adContent': '' + }, + 'bidCpm': '780000' + } + ] + } + ] + } + }; + const request = { + bidRequests: [{ + bidder: 'zedo', + adUnitCode: 'test-requestId', + bidId: 'test-bidId', + params: { + channelCode: 2000000, + dimId: 85 + }, + }] + }; + + const bids = spec.interpretResponse(response, request); + expect(bids).to.have.lengthOf(1); + expect(bids[0].requestId).to.equal('ad1d762'); + expect(bids[0].cpm).to.equal(0.78); + expect(bids[0].width).to.equal('640'); + expect(bids[0].height).to.equal('480'); + expect(bids[0].adType).to.equal('VAST'); + expect(bids[0].vastXml).to.not.equal(''); + expect(bids[0].ad).to.be.an('undefined'); + expect(bids[0].renderer).not.to.be.an('undefined'); + }); + }); + + describe('user sync', function () { + it('should register the iframe sync url', function () { + let syncs = spec.getUserSyncs({ + iframeEnabled: true + }); + expect(syncs).to.not.be.an('undefined'); + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('iframe'); + }); + + it('should pass gdpr params', function () { + let syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, { + gdprApplies: false, consentString: 'test' + }); + expect(syncs).to.not.be.an('undefined'); + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.contains('gdpr=0'); + }); + }); + + describe('bid events', function () { + it('should trigger a win pixel', function () { + const bid = { + 'bidderCode': 'zedo', + 'width': '300', + 'height': '250', + 'statusMessage': 'Bid available', + 'adId': '148018fe5e', + 'cpm': 0.5, + 'ad': 'dummy data', + 'ad_id': '12345', + 'sizeId': '15', + 'adResponse': + { + 'creatives': [ + { + 'adId': '12345', + 'height': '480', + 'width': '640', + 'isFoc': true, + 'creativeDetails': { + 'type': 'VAST', + 'adContent': '' + }, + 'seeder': { + 'network': 1234, + 'servedChan': 1234567, + }, + 'cpm': '1200000', + 'servedChan': 1234, + }] + }, + 'params': [{ + 'channelCode': '123456', + 'dimId': '85' + }], + 'requestTimestamp': 1540401686, + 'responseTimestamp': 1540401687, + 'timeToRespond': 6253, + 'pbLg': '0.50', + 'pbMg': '0.50', + 'pbHg': '0.53', + 'adUnitCode': '/123456/header-bid-tag-0', + 'bidder': 'zedo', + 'size': '300x250', + 'adserverTargeting': { + 'hb_bidder': 'zedo', + 'hb_adid': '148018fe5e', + 'hb_pb': '10.00', + } + }; + spec.onBidWon(bid); + spec.onTimeout(bid); + }); + it('should trigger a timeout pixel', function () { + const bid = { + 'bidderCode': 'zedo', + 'width': '300', + 'height': '250', + 'statusMessage': 'Bid available', + 'adId': '148018fe5e', + 'cpm': 0.5, + 'ad': 'dummy data', + 'ad_id': '12345', + 'sizeId': '15', + 'params': [{ + 'channelCode': '123456', + 'dimId': '85' + }], + 'timeout': 1, + 'requestTimestamp': 1540401686, + 'responseTimestamp': 1540401687, + 'timeToRespond': 6253, + 'adUnitCode': '/123456/header-bid-tag-0', + 'bidder': 'zedo', + 'size': '300x250', + }; + spec.onBidWon(bid); + spec.onTimeout(bid); + }); + }); +}); diff --git a/test/spec/modules/zeotapIdPlusIdSystem_spec.js b/test/spec/modules/zeotapIdPlusIdSystem_spec.js new file mode 100644 index 00000000000..54082618120 --- /dev/null +++ b/test/spec/modules/zeotapIdPlusIdSystem_spec.js @@ -0,0 +1,128 @@ +import { expect } from 'chai'; +import find from 'core-js-pure/features/array/find.js'; +import { config } from 'src/config.js'; +import { init, requestBidsHook, setSubmoduleRegistry } from 'modules/userId/index.js'; +import { storage, zeotapIdPlusSubmodule } from 'modules/zeotapIdPlusIdSystem.js'; + +const ZEOTAP_COOKIE_NAME = 'IDP'; +const ZEOTAP_COOKIE = 'THIS-IS-A-DUMMY-COOKIE'; +const ENCODED_ZEOTAP_COOKIE = btoa(JSON.stringify(ZEOTAP_COOKIE)); + +function getConfigMock() { + return { + userSync: { + syncDelay: 0, + userIds: [{ + name: 'zeotapIdPlus' + }] + } + } +} + +function getAdUnitMock(code = 'adUnit-code') { + return { + code, + mediaTypes: {banner: {}, native: {}}, + sizes: [ + [300, 200], + [300, 600] + ], + bids: [{ + bidder: 'sampleBidder', + params: { placementId: 'banner-only-bidder' } + }] + }; +} + +describe('Zeotap ID System', function() { + let getDataFromLocalStorageStub, localStorageIsEnabledStub; + let getCookieStub, cookiesAreEnabledStub; + beforeEach(function () { + getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); + localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled'); + getCookieStub = sinon.stub(storage, 'getCookie'); + cookiesAreEnabledStub = sinon.stub(storage, 'cookiesAreEnabled'); + }); + + afterEach(function () { + getDataFromLocalStorageStub.restore(); + localStorageIsEnabledStub.restore(); + getCookieStub.restore(); + cookiesAreEnabledStub.restore(); + }); + + describe('test method: getId', function() { + it('provides the stored Zeotap id if a cookie exists', function() { + getCookieStub.withArgs(ZEOTAP_COOKIE_NAME).returns(ENCODED_ZEOTAP_COOKIE); + let id = zeotapIdPlusSubmodule.getId(); + expect(id).to.deep.equal({ + id: ENCODED_ZEOTAP_COOKIE + }); + }); + + it('provides the stored Zeotap id if cookie is absent but present in local storage', function() { + getDataFromLocalStorageStub.withArgs(ZEOTAP_COOKIE_NAME).returns(ENCODED_ZEOTAP_COOKIE); + let id = zeotapIdPlusSubmodule.getId(); + expect(id).to.deep.equal({ + id: ENCODED_ZEOTAP_COOKIE + }); + }); + + it('returns undefined if both cookie and local storage are empty', function() { + let id = zeotapIdPlusSubmodule.getId(); + expect(id).to.be.undefined + }) + }); + + describe('test method: decode', function() { + it('provides the Zeotap ID (IDP) from a stored object', function() { + let zeotapId = { + id: ENCODED_ZEOTAP_COOKIE, + }; + + expect(zeotapIdPlusSubmodule.decode(zeotapId)).to.deep.equal({ + IDP: ZEOTAP_COOKIE + }); + }); + + it('provides the Zeotap ID (IDP) from a stored string', function() { + let zeotapId = ENCODED_ZEOTAP_COOKIE; + + expect(zeotapIdPlusSubmodule.decode(zeotapId)).to.deep.equal({ + IDP: ZEOTAP_COOKIE + }); + }); + }); + + describe('requestBids hook', function() { + let adUnits; + + beforeEach(function() { + adUnits = [getAdUnitMock()]; + setSubmoduleRegistry([zeotapIdPlusSubmodule]); + init(config); + config.setConfig(getConfigMock()); + getCookieStub.withArgs(ZEOTAP_COOKIE_NAME).returns(ENCODED_ZEOTAP_COOKIE); + }); + + it('when a stored Zeotap ID exists it is added to bids', function(done) { + requestBidsHook(function() { + adUnits.forEach(unit => { + unit.bids.forEach(bid => { + expect(bid).to.have.deep.nested.property('userId.IDP'); + expect(bid.userId.IDP).to.equal(ZEOTAP_COOKIE); + const zeotapIdAsEid = find(bid.userIdAsEids, e => e.source == 'zeotap.com'); + expect(zeotapIdAsEid).to.deep.equal({ + source: 'zeotap.com', + uids: [{ + id: ZEOTAP_COOKIE, + atype: 1, + }] + }); + }); + }); + done(); + }, { adUnits }); + }); + }); +}); diff --git a/test/spec/refererDetection_spec.js b/test/spec/refererDetection_spec.js index 90892d915fe..46990ae841f 100644 --- a/test/spec/refererDetection_spec.js +++ b/test/spec/refererDetection_spec.js @@ -1,87 +1,357 @@ import { detectReferer } from 'src/refererDetection.js'; import { expect } from 'chai'; -var mocks = { - createFakeWindow: function (referrer, href) { - return { - document: { - referrer: referrer - }, - location: { - href: href, - // TODO: add ancestorOrigins to increase test coverage - }, - parent: null, - top: null - }; +/** + * Build a walkable linked list of window-like objects for testing. + * + * @param {Array} urls Array of URL strings starting from the top window. + * @param {string} [topReferrer] + * @param {string} [canonicalUrl] + * @param {boolean} [ancestorOrigins] + * @returns {Object} + */ +function buildWindowTree(urls, topReferrer = '', canonicalUrl = null, ancestorOrigins = false) { + /** + * Find the origin from a given fully-qualified URL. + * + * @param {string} url The fully qualified URL + * @returns {string|null} + */ + function getOrigin(url) { + const originRegex = new RegExp('^(https?://[^/]+/?)'); + + const result = originRegex.exec(url); + + if (result && result[0]) { + return result[0]; + } + + return null; } -} -describe('referer detection', () => { - it('should return referer details in nested friendly iframes', function() { - // Fake window object to test friendly iframes - // - Main page http://example.com/page.html - // - - Iframe1 http://example.com/iframe1.html - // - - - Iframe2 http://example.com/iframe2.html - let mockIframe2WinObject = mocks.createFakeWindow('http://example.com/iframe1.html', 'http://example.com/iframe2.html'); - let mockIframe1WinObject = mocks.createFakeWindow('http://example.com/page.html', 'http://example.com/iframe1.html'); - let mainWinObject = mocks.createFakeWindow('http://example.com/page.html', 'http://example.com/page.html'); - mainWinObject.document.querySelector = function() { - return { - href: 'http://prebid.org' + let previousWindow; + const myOrigin = getOrigin(urls[urls.length - 1]); + + const windowList = urls.map((url, index) => { + const theirOrigin = getOrigin(url), + sameOrigin = (myOrigin === theirOrigin); + + const win = {}; + + if (sameOrigin) { + win.location = { + href: url + }; + + if (ancestorOrigins) { + win.location.ancestorOrigins = urls.slice(0, index).reverse().map(getOrigin); + } + + if (index === 0) { + win.document = { + referrer: topReferrer + }; + + if (canonicalUrl) { + win.document.querySelector = function(selector) { + if (selector === "link[rel='canonical']") { + return { + href: canonicalUrl + }; + } + + return null; + }; + } + } else { + win.document = { + referrer: urls[index - 1] + }; } } - mockIframe2WinObject.parent = mockIframe1WinObject; - mockIframe2WinObject.top = mainWinObject; - mockIframe1WinObject.parent = mainWinObject; - mockIframe1WinObject.top = mainWinObject; - mainWinObject.top = mainWinObject; - - const getRefererInfo = detectReferer(mockIframe2WinObject); - let result = getRefererInfo(); - let expectedResult = { - referer: 'http://example.com/page.html', - reachedTop: true, - numIframes: 2, - stack: [ - 'http://example.com/page.html', - 'http://example.com/iframe1.html', - 'http://example.com/iframe2.html' - ], - canonicalUrl: 'http://prebid.org' - }; - expect(result).to.deep.equal(expectedResult); + + previousWindow = win; + + return win; + }); + + const topWindow = windowList[0]; + + previousWindow = null; + + windowList.forEach((win) => { + win.top = topWindow; + win.parent = previousWindow || topWindow; + previousWindow = win; + }); + + return windowList[windowList.length - 1]; +} + +describe('Referer detection', () => { + describe('Non cross-origin scenarios', () => { + describe('No iframes', () => { + it('Should return the current window location and no canonical URL', () => { + const testWindow = buildWindowTree(['https://example.com/some/page'], 'https://othersite.com/'), + result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page', + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: ['https://example.com/some/page'], + canonicalUrl: null + }); + }); + + it('Should return the current window location and a canonical URL', () => { + const testWindow = buildWindowTree(['https://example.com/some/page'], 'https://othersite.com/', 'https://example.com/canonical/page'), + result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page', + reachedTop: true, + isAmp: false, + numIframes: 0, + stack: ['https://example.com/some/page'], + canonicalUrl: 'https://example.com/canonical/page' + }); + }); + }); + + describe('Friendly iframes', () => { + it('Should return the top window location and no canonical URL', () => { + const testWindow = buildWindowTree(['https://example.com/some/page', 'https://example.com/other/page', 'https://example.com/third/page'], 'https://othersite.com/'), + result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page', + reachedTop: true, + isAmp: false, + numIframes: 2, + stack: [ + 'https://example.com/some/page', + 'https://example.com/other/page', + 'https://example.com/third/page' + ], + canonicalUrl: null + }); + }); + + it('Should return the top window location and a canonical URL', () => { + const testWindow = buildWindowTree(['https://example.com/some/page', 'https://example.com/other/page', 'https://example.com/third/page'], 'https://othersite.com/', 'https://example.com/canonical/page'), + result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page', + reachedTop: true, + isAmp: false, + numIframes: 2, + stack: [ + 'https://example.com/some/page', + 'https://example.com/other/page', + 'https://example.com/third/page' + ], + canonicalUrl: 'https://example.com/canonical/page' + }); + }); + }); }); - it('should return referer details in nested cross domain iframes', function() { - // Fake window object to test cross domain iframes. - // - Main page http://example.com/page.html - // - - Iframe1 http://aaa.com/iframe1.html - // - - - Iframe2 http://bbb.com/iframe2.html - let mockIframe2WinObject = mocks.createFakeWindow('http://aaa.com/iframe1.html', 'http://bbb.com/iframe2.html'); - // Sinon cannot throw exception when accessing a propery so passing null to create cross domain - // environment for refererDetection module - let mockIframe1WinObject = mocks.createFakeWindow(null, null); - let mainWinObject = mocks.createFakeWindow(null, null); - mockIframe2WinObject.parent = mockIframe1WinObject; - mockIframe2WinObject.top = mainWinObject; - mockIframe1WinObject.parent = mainWinObject; - mockIframe1WinObject.top = mainWinObject; - mainWinObject.top = mainWinObject; - - const getRefererInfo = detectReferer(mockIframe2WinObject); - let result = getRefererInfo(); - let expectedResult = { - referer: 'http://aaa.com/iframe1.html', - reachedTop: false, - numIframes: 2, - stack: [ - null, - 'http://aaa.com/iframe1.html', - 'http://bbb.com/iframe2.html' - ], - canonicalUrl: undefined - }; - expect(result).to.deep.equal(expectedResult); + describe('Cross-origin scenarios', () => { + it('Should return the top URL and no canonical URL with one cross-origin iframe', () => { + const testWindow = buildWindowTree(['https://example.com/some/page', 'https://safe.frame/ad'], 'https://othersite.com/', 'https://canonical.example.com/'), + result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page', + reachedTop: true, + isAmp: false, + numIframes: 1, + stack: [ + 'https://example.com/some/page', + 'https://safe.frame/ad' + ], + canonicalUrl: null + }); + }); + + it('Should return the top URL and no canonical URL with one cross-origin iframe and one friendly iframe', () => { + const testWindow = buildWindowTree(['https://example.com/some/page', 'https://safe.frame/ad', 'https://safe.frame/ad'], 'https://othersite.com/', 'https://canonical.example.com/'), + result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page', + reachedTop: true, + isAmp: false, + numIframes: 2, + stack: [ + 'https://example.com/some/page', + 'https://safe.frame/ad', + 'https://safe.frame/ad' + ], + canonicalUrl: null + }); + }); + + it('Should return the second iframe location with three cross-origin windows and no ancessorOrigins', () => { + const testWindow = buildWindowTree(['https://example.com/some/page', 'https://safe.frame/ad', 'https://otherfr.ame/ad'], 'https://othersite.com/', 'https://canonical.example.com/'), + result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://safe.frame/ad', + reachedTop: false, + isAmp: false, + numIframes: 2, + stack: [ + null, + 'https://safe.frame/ad', + 'https://otherfr.ame/ad' + ], + canonicalUrl: null + }); + }); + + it('Should return the top window origin with three cross-origin windows with ancessorOrigins', () => { + const testWindow = buildWindowTree(['https://example.com/some/page', 'https://safe.frame/ad', 'https://otherfr.ame/ad'], 'https://othersite.com/', 'https://canonical.example.com/', true), + result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/', + reachedTop: false, + isAmp: false, + numIframes: 2, + stack: [ + 'https://example.com/', + 'https://safe.frame/ad', + 'https://otherfr.ame/ad' + ], + canonicalUrl: null + }); + }); + }); + + describe('Cross-origin AMP page scenarios', () => { + it('Should return the AMP page source and canonical URLs in an amp-ad iframe for a non-cached AMP page', () => { + const testWindow = buildWindowTree(['https://example.com/some/page/amp/', 'https://ad-iframe.ampproject.org/ad']); + + testWindow.context = { + sourceUrl: 'https://example.com/some/page/amp/', + canonicalUrl: 'https://example.com/some/page/' + }; + + const result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page/amp/', + reachedTop: true, + isAmp: true, + numIframes: 1, + stack: [ + 'https://example.com/some/page/amp/', + 'https://ad-iframe.ampproject.org/ad' + ], + canonicalUrl: 'https://example.com/some/page/' + }); + }); + + it('Should return the AMP page source and canonical URLs in an amp-ad iframe for a cached AMP page on top', () => { + const testWindow = buildWindowTree(['https://example-com.amp-cache.example.com/some/page/amp/', 'https://ad-iframe.ampproject.org/ad']); + + testWindow.context = { + sourceUrl: 'https://example.com/some/page/amp/', + canonicalUrl: 'https://example.com/some/page/' + }; + + const result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page/amp/', + reachedTop: true, + isAmp: true, + numIframes: 1, + stack: [ + 'https://example.com/some/page/amp/', + 'https://ad-iframe.ampproject.org/ad' + ], + canonicalUrl: 'https://example.com/some/page/' + }); + }); + + describe('Cached AMP page in iframed search result', () => { + it('Should return the AMP source and canonical URLs but with a null top-level stack location Without ancesorOrigins', () => { + const testWindow = buildWindowTree(['https://google.com/amp/example-com/some/page/amp/', 'https://example-com.amp-cache.example.com/some/page/amp/', 'https://ad-iframe.ampproject.org/ad']); + + testWindow.context = { + sourceUrl: 'https://example.com/some/page/amp/', + canonicalUrl: 'https://example.com/some/page/' + }; + + const result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page/amp/', + reachedTop: false, + isAmp: true, + numIframes: 2, + stack: [ + null, + 'https://example.com/some/page/amp/', + 'https://ad-iframe.ampproject.org/ad' + ], + canonicalUrl: 'https://example.com/some/page/' + }); + }); + + it('Should return the AMP source and canonical URLs and include the top window origin in the stack with ancesorOrigins', () => { + const testWindow = buildWindowTree(['https://google.com/amp/example-com/some/page/amp/', 'https://example-com.amp-cache.example.com/some/page/amp/', 'https://ad-iframe.ampproject.org/ad'], null, null, true); + + testWindow.context = { + sourceUrl: 'https://example.com/some/page/amp/', + canonicalUrl: 'https://example.com/some/page/' + }; + + const result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page/amp/', + reachedTop: false, + isAmp: true, + numIframes: 2, + stack: [ + 'https://google.com/', + 'https://example.com/some/page/amp/', + 'https://ad-iframe.ampproject.org/ad' + ], + canonicalUrl: 'https://example.com/some/page/' + }); + }); + + it('Should return the AMP source and canonical URLs and include the top window origin in the stack with ancesorOrigins and a friendly iframe under the amp-ad iframe', () => { + const testWindow = buildWindowTree(['https://google.com/amp/example-com/some/page/amp/', 'https://example-com.amp-cache.example.com/some/page/amp/', 'https://ad-iframe.ampproject.org/ad', 'https://ad-iframe.ampproject.org/ad'], null, null, true); + + testWindow.parent.context = { + sourceUrl: 'https://example.com/some/page/amp/', + canonicalUrl: 'https://example.com/some/page/' + }; + + const result = detectReferer(testWindow)(); + + expect(result).to.deep.equal({ + referer: 'https://example.com/some/page/amp/', + reachedTop: false, + isAmp: true, + numIframes: 3, + stack: [ + 'https://google.com/', + 'https://example.com/some/page/amp/', + 'https://ad-iframe.ampproject.org/ad', + 'https://ad-iframe.ampproject.org/ad' + ], + canonicalUrl: 'https://example.com/some/page/' + }); + }); + }); }); }); diff --git a/test/spec/renderer_spec.js b/test/spec/renderer_spec.js index 2688c6437fe..9bf551f35e8 100644 --- a/test/spec/renderer_spec.js +++ b/test/spec/renderer_spec.js @@ -126,10 +126,36 @@ describe('Renderer', function () { id: 1, adUnitCode: 'video1' }); + testRenderer.setRender(() => {}) + + testRenderer.render() expect(utilsSpy.callCount).to.equal(1); }); - it('should call loadExternalScript() for script not defined on adUnit', function() { + it('should load renderer adunit renderer when backupOnly', function() { + $$PREBID_GLOBAL$$.adUnits = [{ + code: 'video1', + renderer: { + url: 'http://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js', + backupOnly: true, + render: sinon.spy() + } + }] + + let testRenderer = Renderer.install({ + url: 'https://httpbin.org/post', + config: { test: 'config1' }, + id: 1, + adUnitCode: 'video1' + + }); + testRenderer.setRender(() => {}) + + testRenderer.render() + expect(loadExternalScript.called).to.be.true; + }); + + it('should call loadExternalScript() for script not defined on adUnit, only when .render() is called', function() { $$PREBID_GLOBAL$$.adUnits = [{ code: 'video1', renderer: { @@ -143,6 +169,9 @@ describe('Renderer', function () { id: 1, adUnitCode: undefined }); + expect(loadExternalScript.called).to.be.false; + + testRenderer.render() expect(loadExternalScript.called).to.be.true; }); }); diff --git a/test/spec/unit/core/bidderFactory_spec.js b/test/spec/unit/core/bidderFactory_spec.js index 6d0595ba4d8..692cf9a6475 100644 --- a/test/spec/unit/core/bidderFactory_spec.js +++ b/test/spec/unit/core/bidderFactory_spec.js @@ -401,8 +401,12 @@ describe('bidders created by newBidder', function () { adUnitCode: 'mock/placement', currency: 'USD', netRevenue: true, - ttl: 300 + ttl: 300, + bidderCode: 'sampleBidder', + sampleBidder: {advertiserId: '12345', networkId: '111222'} }; + const bidderRequest = Object.assign({}, MOCK_BIDS_REQUEST); + bidderRequest.bids[0].bidder = 'sampleBidder'; spec.isBidRequestValid.returns(true); spec.buildRequests.returns({ method: 'POST', @@ -413,7 +417,7 @@ describe('bidders created by newBidder', function () { spec.interpretResponse.returns(bid); - bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); + bidder.callBids(bidderRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); expect(addBidResponseStub.calledOnce).to.equal(true); expect(addBidResponseStub.firstCall.args[0]).to.equal('mock/placement'); @@ -423,6 +427,8 @@ describe('bidders created by newBidder', function () { expect(bidObject.originalCurrency).to.equal(bid.currency); expect(doneStub.calledOnce).to.equal(true); expect(logErrorSpy.callCount).to.equal(0); + expect(bidObject.meta).to.exist; + expect(bidObject.meta).to.deep.equal({advertiserId: '12345', networkId: '111222'}); }); it('should call spec.getUserSyncs() with the response', function () { @@ -645,6 +651,28 @@ describe('registerBidder', function () { expect(registerBidAdapterStub.secondCall.args[1]).to.equal('foo') expect(registerBidAdapterStub.thirdCall.args[1]).to.equal('bar') }); + + it('should register alias with their gvlid', function() { + const aliases = [ + { + code: 'foo', + gvlid: 1 + }, + { + code: 'bar', + gvlid: 2 + }, + { + code: 'baz' + } + ] + const thisSpec = Object.assign(newEmptySpec(), { aliases: aliases }); + registerBidder(thisSpec); + + expect(registerBidAdapterStub.getCall(1).args[0].getSpec().gvlid).to.equal(1); + expect(registerBidAdapterStub.getCall(2).args[0].getSpec().gvlid).to.equal(2); + expect(registerBidAdapterStub.getCall(3).args[0].getSpec().gvlid).to.equal(undefined); + }) }) describe('validate bid response: ', function () { @@ -841,42 +869,32 @@ describe('preload mapping url hook', function() { let fakeTranslationServer; let getLocalStorageStub; let adapterManagerStub; + let adUnits = [{ + code: 'midroll_1', + mediaTypes: { + video: { + context: 'adpod' + } + }, + bids: [ + { + bidder: 'sampleBidder1', + params: { + placementId: 14542875, + } + } + ] + }]; beforeEach(function () { fakeTranslationServer = server; getLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); adapterManagerStub = sinon.stub(adapterManager, 'getBidAdapter'); - }); - - afterEach(function() { - getLocalStorageStub.restore(); - adapterManagerStub.restore(); - config.resetConfig(); - }); - - it('should preload mapping url file', function() { config.setConfig({ 'adpod': { 'brandCategoryExclusion': true } }); - let adUnits = [{ - code: 'midroll_1', - mediaTypes: { - video: { - context: 'adpod' - } - }, - bids: [ - { - bidder: 'sampleBidder1', - params: { - placementId: 14542875, - } - } - ] - }]; - getLocalStorageStub.returns(null); adapterManagerStub.withArgs('sampleBidder1').returns({ getSpec: function() { return { @@ -890,16 +908,21 @@ describe('preload mapping url hook', function() { } } }); + }); + + afterEach(function() { + getLocalStorageStub.restore(); + adapterManagerStub.restore(); + config.resetConfig(); + }); + + it('should preload mapping url file', function() { + getLocalStorageStub.returns(null); preloadBidderMappingFile(sinon.spy(), adUnits); expect(fakeTranslationServer.requests.length).to.equal(1); }); it('should preload mapping url file for all bidders', function() { - config.setConfig({ - 'adpod': { - 'brandCategoryExclusion': true - } - }); let adUnits = [{ code: 'midroll_1', mediaTypes: { @@ -923,19 +946,6 @@ describe('preload mapping url hook', function() { ] }]; getLocalStorageStub.returns(null); - adapterManagerStub.withArgs('sampleBidder1').returns({ - getSpec: function() { - return { - 'getMappingFileInfo': function() { - return { - url: 'http://sample.com', - refreshInDays: 7, - key: `sampleBidder1MappingFile` - } - } - } - } - }); adapterManagerStub.withArgs('sampleBidder2').returns({ getSpec: function() { return { @@ -960,4 +970,30 @@ describe('preload mapping url hook', function() { preloadBidderMappingFile(sinon.spy(), adUnits); expect(fakeTranslationServer.requests.length).to.equal(2); }); + + it('should make ajax call to update mapping file if data found in localstorage is expired', function() { + let clock = sinon.useFakeTimers(utils.timestamp()); + getLocalStorageStub.returns(JSON.stringify({ + lastUpdated: utils.timestamp() - 8 * 24 * 60 * 60 * 1000, + mapping: { + 'iab-1': '1' + } + })); + preloadBidderMappingFile(sinon.spy(), adUnits); + expect(fakeTranslationServer.requests.length).to.equal(1); + clock.restore(); + }); + + it('should not make ajax call to update mapping file if data found in localstorage and is not expired', function () { + let clock = sinon.useFakeTimers(utils.timestamp()); + getLocalStorageStub.returns(JSON.stringify({ + lastUpdated: utils.timestamp(), + mapping: { + 'iab-1': '1' + } + })); + preloadBidderMappingFile(sinon.spy(), adUnits); + expect(fakeTranslationServer.requests.length).to.equal(0); + clock.restore(); + }); }); diff --git a/test/spec/unit/core/storageManager_spec.js b/test/spec/unit/core/storageManager_spec.js index 0b406242f90..de09df5b196 100644 --- a/test/spec/unit/core/storageManager_spec.js +++ b/test/spec/unit/core/storageManager_spec.js @@ -42,5 +42,32 @@ describe('storage manager', function() { storage.setCookie('foo1', 'baz1'); expect(deviceAccessSpy.calledOnce).to.equal(true); deviceAccessSpy.restore(); + }); + + describe('localstorage forbidden access in 3rd-party context', function() { + let errorLogSpy; + const originalLocalStorage = { get: () => window.localStorage }; + const localStorageMock = { get: () => { throw Error } }; + + beforeEach(function() { + Object.defineProperty(window, 'localStorage', localStorageMock); + errorLogSpy = sinon.spy(utils, 'logError'); + }); + + afterEach(function() { + Object.defineProperty(window, 'localStorage', originalLocalStorage); + errorLogSpy.restore(); + }) + + it('should not throw if the localstorage is not accessible when setting/getting/removing from localstorage', function() { + const coreStorage = getStorageManager(); + + coreStorage.setDataInLocalStorage('key', 'value'); + const val = coreStorage.getDataFromLocalStorage('key'); + coreStorage.removeDataFromLocalStorage('key'); + + expect(val).to.be.null; + sinon.assert.calledThrice(errorLogSpy); + }) }) }); diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js index a5da1c904f0..5d43ed48266 100644 --- a/test/spec/unit/core/targeting_spec.js +++ b/test/spec/unit/core/targeting_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { targeting as targetingInstance, filters, sortByDealAndPriceBucketOrCpm } from 'src/targeting.js'; +import { targeting as targetingInstance, filters, getHighestCpmBidsFromBidPool, sortByDealAndPriceBucketOrCpm } from 'src/targeting.js'; import { config } from 'src/config.js'; import { getAdUnits, createBidReceived } from 'test/fixtures/fixtures.js'; import CONSTANTS from 'src/constants.json'; @@ -338,11 +338,44 @@ describe('targeting tests', function () { bid4 = utils.deepClone(bid1); bid4.adserverTargeting['hb_bidder'] = bid4.bidder = bid4.bidderCode = 'appnexus'; bid4.cpm = 2.25; + bid4.adId = '8383838'; enableSendAllBids = true; bidsReceived.push(bid4); }); + it('when sendBidsControl.bidLimit is set greater than 0 in getHighestCpmBidsFromBidPool', function () { + config.setConfig({ + sendBidsControl: { + bidLimit: 2, + dealPrioritization: true + } + }); + + const bids = getHighestCpmBidsFromBidPool(bidsReceived, utils.getHighestCpm, 2); + + expect(bids.length).to.equal(3); + expect(bids[0].adId).to.equal('8383838'); + expect(bids[1].adId).to.equal('148018fe5e'); + expect(bids[2].adId).to.equal('48747745'); + }); + + it('when sendBidsControl.bidLimit is set greater than 0 and deal priortization is false in getHighestCpmBidsFromBidPool', function () { + config.setConfig({ + sendBidsControl: { + bidLimit: 2, + dealPrioritization: false + } + }); + + const bids = getHighestCpmBidsFromBidPool(bidsReceived, utils.getHighestCpm, 2); + + expect(bids.length).to.equal(3); + expect(bids[0].adId).to.equal('8383838'); + expect(bids[1].adId).to.equal('148018fe5e'); + expect(bids[2].adId).to.equal('48747745'); + }); + it('selects the top n number of bids when enableSendAllBids is true and and bitLimit is set', function () { config.setConfig({ sendBidsControl: { @@ -369,7 +402,7 @@ describe('targeting tests', function () { expect(limitedBids.length).to.equal(2); }); - it('Sends all bids when enableSendAllBids is true and and bitLimit is set to 0', function () { + it('Sends all bids when enableSendAllBids is true and and bidLimit is set to 0', function () { config.setConfig({ sendBidsControl: { bidLimit: 0 @@ -383,6 +416,46 @@ describe('targeting tests', function () { }); }); + describe('targetingControls.allowTargetingKeys', function () { + let bid4; + + beforeEach(function() { + bid4 = utils.deepClone(bid1); + bid4.adserverTargeting = { + hb_deal: '4321', + hb_pb: '0.1', + hb_adid: '567891011', + hb_bidder: 'appnexus', + }; + bid4.bidder = bid4.bidderCode = 'appnexus'; + bid4.cpm = 0.1; // losing bid so not included if enableSendAllBids === false + bid4.dealId = '4321'; + enableSendAllBids = true; + config.setConfig({ + targetingControls: { + allowTargetingKeys: ['BIDDER', 'AD_ID', 'PRICE_BUCKET'] + } + }); + bidsReceived.push(bid4); + }); + + it('targeting should include custom keys', function () { + const targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']); + expect(targeting['/123456/header-bid-tag-0']).to.include.all.keys('foobar'); + }); + + it('targeting should include keys prefixed by allowed default targeting keys', function () { + const targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']); + expect(targeting['/123456/header-bid-tag-0']).to.include.all.keys('hb_bidder_rubicon', 'hb_adid_rubicon', 'hb_pb_rubicon'); + expect(targeting['/123456/header-bid-tag-0']).to.include.all.keys('hb_bidder_appnexus', 'hb_adid_appnexus', 'hb_pb_appnexus'); + }); + + it('targeting should not include keys prefixed by disallowed default targeting keys', function () { + const targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']); + expect(targeting['/123456/header-bid-tag-0']).to.not.have.all.keys(['hb_deal_appnexus', 'hb_deal_rubicon']); + }); + }); + describe('targetingControls.alwaysIncludeDeals', function () { let bid4; @@ -690,171 +763,171 @@ describe('targeting tests', function () { describe('sortByDealAndPriceBucketOrCpm', function() { it('will properly sort bids when some bids have deals and some do not', function () { let bids = [{ - adUnitTargeting: { + adserverTargeting: { hb_adid: 'abc', hb_pb: '1.00', hb_deal: '1234' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'def', hb_pb: '0.50', } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'ghi', hb_pb: '20.00', hb_deal: '4532' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'jkl', hb_pb: '9.00', hb_deal: '9864' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'mno', hb_pb: '50.00', } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'pqr', hb_pb: '100.00', } }]; bids.sort(sortByDealAndPriceBucketOrCpm()); - expect(bids[0].adUnitTargeting.hb_adid).to.equal('ghi'); - expect(bids[1].adUnitTargeting.hb_adid).to.equal('jkl'); - expect(bids[2].adUnitTargeting.hb_adid).to.equal('abc'); - expect(bids[3].adUnitTargeting.hb_adid).to.equal('pqr'); - expect(bids[4].adUnitTargeting.hb_adid).to.equal('mno'); - expect(bids[5].adUnitTargeting.hb_adid).to.equal('def'); + expect(bids[0].adserverTargeting.hb_adid).to.equal('ghi'); + expect(bids[1].adserverTargeting.hb_adid).to.equal('jkl'); + expect(bids[2].adserverTargeting.hb_adid).to.equal('abc'); + expect(bids[3].adserverTargeting.hb_adid).to.equal('pqr'); + expect(bids[4].adserverTargeting.hb_adid).to.equal('mno'); + expect(bids[5].adserverTargeting.hb_adid).to.equal('def'); }); it('will properly sort bids when all bids have deals', function () { let bids = [{ - adUnitTargeting: { + adserverTargeting: { hb_adid: 'abc', hb_pb: '1.00', hb_deal: '1234' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'def', hb_pb: '0.50', hb_deal: '4321' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'ghi', hb_pb: '2.50', hb_deal: '4532' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'jkl', hb_pb: '2.00', hb_deal: '9864' } }]; bids.sort(sortByDealAndPriceBucketOrCpm()); - expect(bids[0].adUnitTargeting.hb_adid).to.equal('ghi'); - expect(bids[1].adUnitTargeting.hb_adid).to.equal('jkl'); - expect(bids[2].adUnitTargeting.hb_adid).to.equal('abc'); - expect(bids[3].adUnitTargeting.hb_adid).to.equal('def'); + expect(bids[0].adserverTargeting.hb_adid).to.equal('ghi'); + expect(bids[1].adserverTargeting.hb_adid).to.equal('jkl'); + expect(bids[2].adserverTargeting.hb_adid).to.equal('abc'); + expect(bids[3].adserverTargeting.hb_adid).to.equal('def'); }); it('will properly sort bids when no bids have deals', function () { let bids = [{ - adUnitTargeting: { + adserverTargeting: { hb_adid: 'abc', hb_pb: '1.00' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'def', hb_pb: '0.10' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'ghi', hb_pb: '10.00' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'jkl', hb_pb: '10.01' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'mno', hb_pb: '1.00' } }, { - adUnitTargeting: { + adserverTargeting: { hb_adid: 'pqr', hb_pb: '100.00' } }]; bids.sort(sortByDealAndPriceBucketOrCpm()); - expect(bids[0].adUnitTargeting.hb_adid).to.equal('pqr'); - expect(bids[1].adUnitTargeting.hb_adid).to.equal('jkl'); - expect(bids[2].adUnitTargeting.hb_adid).to.equal('ghi'); - expect(bids[3].adUnitTargeting.hb_adid).to.equal('abc'); - expect(bids[4].adUnitTargeting.hb_adid).to.equal('mno'); - expect(bids[5].adUnitTargeting.hb_adid).to.equal('def'); + expect(bids[0].adserverTargeting.hb_adid).to.equal('pqr'); + expect(bids[1].adserverTargeting.hb_adid).to.equal('jkl'); + expect(bids[2].adserverTargeting.hb_adid).to.equal('ghi'); + expect(bids[3].adserverTargeting.hb_adid).to.equal('abc'); + expect(bids[4].adserverTargeting.hb_adid).to.equal('mno'); + expect(bids[5].adserverTargeting.hb_adid).to.equal('def'); }); it('will properly sort bids when some bids have deals and some do not and by cpm when flag is set to true', function () { let bids = [{ cpm: 1.04, - adUnitTargeting: { + adserverTargeting: { hb_adid: 'abc', hb_pb: '1.00', hb_deal: '1234' } }, { cpm: 0.50, - adUnitTargeting: { + adserverTargeting: { hb_adid: 'def', hb_pb: '0.50', hb_deal: '4532' } }, { cpm: 0.53, - adUnitTargeting: { + adserverTargeting: { hb_adid: 'ghi', hb_pb: '0.50', hb_deal: '4532' } }, { cpm: 9.04, - adUnitTargeting: { + adserverTargeting: { hb_adid: 'jkl', hb_pb: '9.00', hb_deal: '9864' } }, { cpm: 50.00, - adUnitTargeting: { + adserverTargeting: { hb_adid: 'mno', hb_pb: '50.00', } }, { cpm: 100.00, - adUnitTargeting: { + adserverTargeting: { hb_adid: 'pqr', hb_pb: '100.00', } }]; bids.sort(sortByDealAndPriceBucketOrCpm(true)); - expect(bids[0].adUnitTargeting.hb_adid).to.equal('jkl'); - expect(bids[1].adUnitTargeting.hb_adid).to.equal('abc'); - expect(bids[2].adUnitTargeting.hb_adid).to.equal('ghi'); - expect(bids[3].adUnitTargeting.hb_adid).to.equal('def'); - expect(bids[4].adUnitTargeting.hb_adid).to.equal('pqr'); - expect(bids[5].adUnitTargeting.hb_adid).to.equal('mno'); + expect(bids[0].adserverTargeting.hb_adid).to.equal('jkl'); + expect(bids[1].adserverTargeting.hb_adid).to.equal('abc'); + expect(bids[2].adserverTargeting.hb_adid).to.equal('ghi'); + expect(bids[3].adserverTargeting.hb_adid).to.equal('def'); + expect(bids[4].adserverTargeting.hb_adid).to.equal('pqr'); + expect(bids[5].adserverTargeting.hb_adid).to.equal('mno'); }); }); diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 7b4061850cb..960ccf08c92 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -959,12 +959,12 @@ describe('Unit: Prebid Module', function () { adUnitCode: config.adUnitCodes[0], }; - const remoteDomain = '*'; - const source = { - postMessage: sinon.stub() + const event = { + source: { postMessage: sinon.stub() }, + origin: 'origin.sf.com' }; - _sendAdToCreative(mockAdObject, remoteDomain, source); + _sendAdToCreative(mockAdObject, event); expect(slots[0].spyGetSlotElementId.called).to.equal(false); expect(slots[1].spyGetSlotElementId.called).to.equal(true); @@ -1770,8 +1770,6 @@ describe('Unit: Prebid Module', function () { }); describe('multiformat requests', function () { - let spyCallBids; - let createAuctionStub; let adUnits; beforeEach(function () { @@ -1791,14 +1789,10 @@ describe('Unit: Prebid Module', function () { }]; adUnitCodes = ['adUnit-code']; configObj.setConfig({maxRequestsPerOrigin: Number.MAX_SAFE_INTEGER || 99999999}); - let auction = auctionModule.newAuction({adUnits, adUnitCodes, callback: function() {}, cbTimeout: timeout}); - spyCallBids = sinon.spy(adapterManager, 'callBids'); - createAuctionStub = sinon.stub(auctionModule, 'newAuction'); - createAuctionStub.returns(auction); + sinon.spy(adapterManager, 'callBids'); }) afterEach(function () { - auctionModule.newAuction.restore(); adapterManager.callBids.restore(); }); @@ -1821,7 +1815,6 @@ describe('Unit: Prebid Module', function () { const spyArgs = adapterManager.callBids.getCall(0); const biddersCalled = spyArgs.args[0][0].bids; - // only appnexus supports native expect(biddersCalled.length).to.equal(1); }); diff --git a/test/spec/unit/secureCreatives_spec.js b/test/spec/unit/secureCreatives_spec.js index 97dfa119193..566154f0003 100644 --- a/test/spec/unit/secureCreatives_spec.js +++ b/test/spec/unit/secureCreatives_spec.js @@ -30,14 +30,14 @@ describe('secureCreatives', () => { cpm: '1.00', adUnitCode: 'some_dom_id' }; - const remoteDomain = '*'; - const source = { - postMessage: sinon.stub() + const event = { + source: { postMessage: sinon.stub() }, + origin: 'origin.sf.com' }; - _sendAdToCreative(mockAdObject, remoteDomain, source); - expect(JSON.parse(source.postMessage.args[0][0]).ad).to.equal(''); - expect(JSON.parse(source.postMessage.args[0][0]).adUrl).to.equal('http://creative.prebid.org/1.00'); + _sendAdToCreative(mockAdObject, event); + expect(JSON.parse(event.source.postMessage.args[0][0]).ad).to.equal(''); + expect(JSON.parse(event.source.postMessage.args[0][0]).adUrl).to.equal('http://creative.prebid.org/1.00'); window.googletag = oldVal; window.apntag = oldapntag; }); diff --git a/test/spec/utils_spec.js b/test/spec/utils_spec.js index 4dbb40557af..6494ead78e7 100644 --- a/test/spec/utils_spec.js +++ b/test/spec/utils_spec.js @@ -1115,4 +1115,87 @@ describe('Utils', function () { }); }); }); + + describe('deepEqual', function() { + it('should return "true" if comparing the same object', function() { + const obj1 = { + banner: { + sizeConfig: [ + { minViewPort: [0, 0], sizes: [] }, + { minViewPort: [1000, 0], sizes: [[1000, 300], [1000, 90], [970, 250], [970, 90], [728, 90]] }, + ], + }, + }; + const obj2 = obj1; + expect(utils.deepEqual(obj1, obj2)).to.equal(true); + }); + it('should return "true" if two deeply nested objects are equal', function() { + const obj1 = { + banner: { + sizeConfig: [ + { minViewPort: [0, 0], sizes: [] }, + { minViewPort: [1000, 0], sizes: [[1000, 300], [1000, 90], [970, 250], [970, 90], [728, 90]] }, + ], + }, + }; + const obj2 = { + banner: { + sizeConfig: [ + { minViewPort: [0, 0], sizes: [] }, + { minViewPort: [1000, 0], sizes: [[1000, 300], [1000, 90], [970, 250], [970, 90], [728, 90]] }, + ], + }, + }; + expect(utils.deepEqual(obj1, obj2)).to.equal(true); + }); + it('should return "true" if comparting the same primitive values', function() { + const primitive1 = 'Prebid.js'; + const primitive2 = 'Prebid.js'; + expect(utils.deepEqual(primitive1, primitive2)).to.equal(true); + }); + it('should return "false" if comparing two different primitive values', function() { + const primitive1 = 12; + const primitive2 = 123; + expect(utils.deepEqual(primitive1, primitive2)).to.equal(false); + }); + it('should return "false" if comparing two different deeply nested objects', function() { + const obj1 = { + banner: { + sizeConfig: [ + { minViewPort: [0, 0], sizes: [] }, + { minViewPort: [1000, 0], sizes: [[1000, 300], [1000, 90], [970, 250], [970, 90], [728, 90]] }, + ], + }, + }; + const obj2 = { + banner: { + sizeConfig: [ + { minViewPort: [0, 0], sizes: [] }, + { minViewPort: [1000, 0], sizes: [[1000, 300], [728, 90]] }, + ], + }, + } + expect(utils.deepEqual(obj1, obj2)).to.equal(false); + }); + + describe('cyrb53Hash', function() { + it('should return the same hash for the same string', function() { + const stringOne = 'string1'; + expect(utils.cyrb53Hash(stringOne)).to.equal(utils.cyrb53Hash(stringOne)); + }); + it('should return a different hash for the same string with different seeds', function() { + const stringOne = 'string1'; + expect(utils.cyrb53Hash(stringOne, 1)).to.not.equal(utils.cyrb53Hash(stringOne, 2)); + }); + it('should return a different hash for different strings with the same seed', function() { + const stringOne = 'string1'; + const stringTwo = 'string2'; + expect(utils.cyrb53Hash(stringOne)).to.not.equal(utils.cyrb53Hash(stringTwo)); + }); + it('should return a string value, not a number', function() { + const stringOne = 'string1'; + expect(typeof utils.cyrb53Hash(stringOne)).to.equal('string'); + }); + }); + }); }); diff --git a/test/spec/videoCache_spec.js b/test/spec/videoCache_spec.js index 7d706947416..6bb214af8a0 100644 --- a/test/spec/videoCache_spec.js +++ b/test/spec/videoCache_spec.js @@ -5,6 +5,50 @@ import { server } from 'test/mocks/xhr.js'; const should = chai.should(); +function getMockBid(bidder, auctionId, bidderRequestId) { + return { + 'bidder': bidder, + 'params': { + 'placementId': '10433394', + 'member': 123, + 'keywords': { + 'foo': ['bar', 'baz'], + 'fizz': ['buzz'] + } + }, + 'bid_id': '12345abc', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + } + }, + 'transactionId': '4ef956ad-fd83-406d-bd35-e4bb786ab86c', + 'sizes': [300, 250], + 'bidId': '123', + 'bidderRequestId': bidderRequestId, + 'auctionId': auctionId, + 'storedAuctionResponse': 11111 + }; +} + +function getMockBidRequest(bidder = 'appnexus', auctionId = '173afb6d132ba3', bidderRequestId = '3d1063078dfcc8') { + return { + 'bidderCode': bidder, + 'auctionId': auctionId, + 'bidderRequestId': bidderRequestId, + 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', + 'bids': [getMockBid(bidder, auctionId, bidderRequestId)], + 'auctionStart': 1510852447530, + 'timeout': 5000, + 'src': 's2s', + 'doneCbCallCount': 0, + 'refererInfo': { + 'referer': 'http://mytestpage.com' + } + } +} + describe('The video cache', function () { function assertError(callbackSpy) { callbackSpy.calledOnce.should.equal(true); @@ -192,6 +236,61 @@ describe('The video cache', function () { JSON.parse(request.requestBody).should.deep.equal(payload); }); + it('should include additional params in request payload should config.cache.vasttrack be true and bidderRequest argument was defined', () => { + config.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache', + vasttrack: true + } + }); + + const customKey1 = 'vasttrack_123'; + const customKey2 = 'vasttrack_abc'; + const vastXml1 = 'testvast1'; + const vastXml2 = 'testvast2'; + + const bids = [{ + vastXml: vastXml1, + ttl: 25, + customCacheKey: customKey1, + requestId: '12345abc', + bidder: 'appnexus' + }, { + vastXml: vastXml2, + ttl: 25, + customCacheKey: customKey2, + requestId: 'cba54321', + bidder: 'rubicon' + }]; + + store(bids, function () { }, getMockBidRequest()); + const request = server.requests[0]; + request.method.should.equal('POST'); + request.url.should.equal('https://prebid.adnxs.com/pbc/v1/cache'); + request.requestHeaders['Content-Type'].should.equal('text/plain;charset=utf-8'); + let payload = { + puts: [{ + type: 'xml', + value: vastXml1, + ttlseconds: 25, + key: customKey1, + bidid: '12345abc', + bidder: 'appnexus', + timestamp: 1510852447530 + }, { + type: 'xml', + value: vastXml2, + ttlseconds: 25, + key: customKey2, + bidid: 'cba54321', + bidder: 'rubicon', + timestamp: 1510852447530 + }] + }; + + JSON.parse(request.requestBody).should.deep.equal(payload); + }); + function assertRequestMade(bid, expectedValue) { store([bid], function () { }); diff --git a/wdio.conf.js b/wdio.conf.js index dd94e82cf90..4d93f3d88d3 100644 --- a/wdio.conf.js +++ b/wdio.conf.js @@ -9,22 +9,24 @@ function getCapabilities() { return platformMap[os]; } - // only Edge 16, Chrome 74 & Firefox 66 run as part of functional tests + // only IE 11, Chrome 80 & Firefox 73 run as part of functional tests // rest of the browsers are discarded. - delete browsers['bs_ie_11_windows_10']; - delete browsers['bs_edge_17_windows_10']; - delete browsers['bs_chrome_75_windows_10']; - delete browsers['bs_firefox_67_windows_10']; - delete browsers['bs_safari_11_mac_high_sierra']; + delete browsers['bs_chrome_79_windows_10']; + delete browsers['bs_firefox_72_windows_10']; + delete browsers['bs_safari_11_mac_catalina']; delete browsers['bs_safari_12_mac_mojave']; + // disable all edge browsers due to wdio bug for switchToFrame: https://github.com/webdriverio/webdriverio/issues/3880 + delete browsers['bs_edge_18_windows_10']; + delete browsers['bs_edge_17_windows_10']; let capabilities = [] Object.keys(browsers).forEach(key => { let browser = browsers[key]; capabilities.push({ browserName: browser.browser, - platform: getPlatform(browser.os), - version: browser.browser_version, + os: getPlatform(browser.os), + os_version: browser.os_version, + browser_version: browser.browser_version, acceptSslCerts: true, 'browserstack.networkLogs': true, 'browserstack.console': 'verbose', @@ -35,27 +37,29 @@ function getCapabilities() { } exports.config = { - specs: [ - './test/spec/e2e/**/*.spec.js' - ], - services: ['browserstack'], - user: process.env.BROWSERSTACK_USERNAME, - key: process.env.BROWSERSTACK_ACCESS_KEY, - browserstackLocal: true, - // Do not increase this, since we have only 5 parallel tests in browserstack account - maxInstances: 5, - capabilities: getCapabilities(), - logLevel: 'silent', // Level of logging verbosity: silent | verbose | command | data | result | error - coloredLogs: true, - waitforTimeout: 60000, // Default timeout for all waitFor* commands. - connectionRetryTimeout: 60000, // Default timeout in milliseconds for request if Selenium Grid doesn't send response - connectionRetryCount: 3, // Default request retries count - framework: 'mocha', - mochaOpts: { - ui: 'bdd', - timeout: 60000, - compilers: ['js:babel-register'], - }, - // if you see error, update this to spec reporter and logLevel above to get detailed report. - reporters: ['concise'] -}; + specs: [ + './test/spec/e2e/**/*.spec.js' + ], + services: [ + ['browserstack', { + browserstackLocal: true + }] + ], + user: process.env.BROWSERSTACK_USERNAME, + key: process.env.BROWSERSTACK_ACCESS_KEY, + maxInstances: 5, // Do not increase this, since we have only 5 parallel tests in browserstack account + capabilities: getCapabilities(), + logLevel: 'silent', // put option here: info | trace | debug | warn| error | silent + bail: 0, + waitforTimeout: 60000, // Default timeout for all waitFor* commands. + connectionRetryTimeout: 60000, // Default timeout in milliseconds for request if Selenium Grid doesn't send response + connectionRetryCount: 3, // Default request retries count + framework: 'mocha', + mochaOpts: { + ui: 'bdd', + timeout: 60000, + compilers: ['js:babel-register'], + }, + // if you see error, update this to spec reporter and logLevel above to get detailed report. + reporters: ['concise'] +}