diff --git a/.circleci/config.yml b/.circleci/config.yml index 0d48ec13fa1..5ea5e87218c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,7 +7,7 @@ aliases: - &environment docker: # specify the version you desire here - - image: circleci/node:8.9.0 + - image: circleci/node:12.16.1 # Specify service dependencies here if necessary # CircleCI maintains a library of pre-built images @@ -92,3 +92,6 @@ workflows: - master jobs: - e2etest + +experimental: + pipelines: true \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 65019123c2e..c64ab379c52 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,7 +15,8 @@ module.exports = { }, "extends": "standard", "plugins": [ - "prebid" + "prebid", + "import" ], "globals": { "$$PREBID_GLOBAL$$": false @@ -27,6 +28,7 @@ module.exports = { "comma-dangle": "off", "semi": "off", "space-before-function-paren": "off", + "import/extensions": ["error", "ignorePackages"], // Exceptions below this line are temporary, so that eslint can be added into the CI process. // Violations of these styles should be fixed, and the exceptions removed over time. @@ -37,6 +39,7 @@ module.exports = { "no-throw-literal": "off", "no-undef": 2, "no-useless-escape": "off", + "no-console": "error" }, "overrides": Object.keys(allowedModules).map((key) => ({ "files": key + "/**/*.js", 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 36fd2895702..016f4055216 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,6 +51,7 @@ When you are adding code to Prebid.js, or modifying code that isn't covered by a - If you need to check `adloader.loadExternalScript` in a test, use a `stub` rather than a `spy`. `spy`s trigger a network call which can result in a `script error` and cause unrelated unit tests to fail. `stub`s will let you gather information about the `adloader.loadExternalScript` call without affecting external resources - If your test makes ajax requests, use the global xhr stub in `test/mocks/xhr`. Do not use your own `sinon.useFakeXMLHttpRequest()` or `sinon.createFakeServer()`. - When writing tests you may use ES2015 syntax if desired +- If your test relies on `Window` or `global` object, do not mutate that object directly. Instead, create a separate copy of that object and perform operations on that new copy. ### Test Examples Prebid.js already has many tests. Read them to see how Prebid.js is tested, and for inspiration: diff --git a/PR_REVIEW.md b/PR_REVIEW.md index 64635b7fc03..dac50593d6e 100644 --- a/PR_REVIEW.md +++ b/PR_REVIEW.md @@ -15,12 +15,15 @@ For modules and core platform updates, the initial reviewer should request an ad - 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` + - If they support the GDPR consentManagement module and TCF1, add `gdpr_supported: true` + - If they support the GDPR consentManagement module and TCF2, add `tcf2_supported: true` + - If they support the US Privacy consentManagementUsp module, add `usp_supported: true` + - If they support one or more userId modules, add `userId: (list of supported vendors)` + - If they support video and/or native mediaTypes add `media_types: video, native`. Note that display is added by default. If you don't support display, add "no-display" as the first entry, e.g. `media_types: no-display, native` + - If they support COPPA, add `coppa_supported: true` + - If they support SChain, add `schain_supported: true` + - If their bidder doesn't work well with safeframed creatives, add `safeframes_ok: false`. This will alert publishers to not use safeframed creatives when creating the ad server entries for their bidder. + - If they're a member of Prebid.org, add `prebid_member: true` - If all above is good, add a `LGTM` comment and request 1 additional core member to review. - Once there is 2 `LGTM` on the PR, merge to master - Ask the submitter to add a PR for documentation if applicable. @@ -46,11 +49,16 @@ For modules and core platform updates, the initial reviewer should request an ad ## Ticket Coordinator -Each week, Prebid Org assigns one person to keep an eye on incoming issues and PRs. That person should: +Each week, Prebid Org assigns one person to keep an eye on incoming issues and PRs. Every Monday morning a reminder is +sent to the prebid-js slack channel with a link to the spreadsheet. If you're on rotation, please check that list each +Monday to see if you're on-duty. + +When on-duty: - Review issues and PRs at least once per weekday for new items. Encourage a 48 "SLA" on PRs/issues assigned. Aim for touchpoint once every 48/hours. -- For PRs: assign PRs to individuals on the PR review list. Try to be equitable -- not all PRs are created equally. Use the "Assigned" field and add the "Needs Review" label. +- For PRs: assign PRs to individuals on the **PR review list**. Try to be equitable -- not all PRs are created equally. Use the "Assigned" field and add the "Needs Review" label. - For Issues: try to address questions and troubleshooting requests on your own, assigning them to others as needed. Please add labels as appropriate (I.E. bug, question, backlog etc). - Issues that are questions or troubleshooting requests may be closed if the originator doesn't respond within a week to requests for confirmation or details. - Issues that are bug reports should be left open and assigned to someone in PR rotation to confirm or deny the bug status. -- It's polite to check with others before assigning them large tasks. -- If possible, check in on older items and see if they can be unstuck. +- It's polite to check with others before assigning them extra-large tasks. +- If possible, check in on older PRs and Issues and see if they can be unstuck. +- Perform the weekly Prebid.js release per instructions at https://github.com/prebid/Prebid.js/blob/master/RELEASE_SCHEDULE.md . This generally takes place on Tues or Weds. diff --git a/README.md b/README.md index be07a27ddc1..0dd5b25a50f 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ module.exports = { // override the regular exclusion from above (for being inside node_modules). { test: /.js$/, - include: new RegExp(`\\${path.sep}prebid\.js`), + include: new RegExp(`\\${path.sep}prebid\\.js`), use: { loader: 'babel-loader', // presets and plugins for Prebid.js must be manually specified separate from your other babel rule. @@ -112,7 +112,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. diff --git a/allowedModules.js b/allowedModules.js index 0d4a36308c3..2a521f781f9 100644 --- a/allowedModules.js +++ b/allowedModules.js @@ -1,11 +1,11 @@ const sharedWhiteList = [ - "core-js/library/fn/array/find", // no ie11 - "core-js/library/fn/array/includes", // no ie11 - "core-js/library/fn/set", // ie11 supports Set but not Set#values - "core-js/library/fn/string/includes", // no ie11 - "core-js/library/fn/number/is-integer", // no ie11, - "core-js/library/fn/array/from" // no ie11 + 'core-js-pure/features/array/find', // no ie11 + 'core-js-pure/features/array/includes', // no ie11 + 'core-js-pure/features/set', // ie11 supports Set but not Set#values + 'core-js-pure/features/string/includes', // no ie11 + 'core-js-pure/features/number/is-integer', // no ie11, + 'core-js-pure/features/array/from' // no ie11 ]; module.exports = { @@ -13,13 +13,15 @@ module.exports = { ...sharedWhiteList, 'criteo-direct-rsa-validate', 'jsencrypt', - 'crypto-js' + 'crypto-js', + 'live-connect' // Maintained by LiveIntent : https://github.com/liveintent-berlin/live-connect/ ], 'src': [ ...sharedWhiteList, 'fun-hooks/no-eval', 'just-clone', 'dlv', - 'dset' + 'dset', + 'deep-equal' ] }; diff --git a/browsers.json b/browsers.json index 9042d7d0627..91e0548d78a 100644 --- a/browsers.json +++ b/browsers.json @@ -7,11 +7,11 @@ "device": null, "os": "Windows" }, - "bs_edge_16_windows_10": { + "bs_edge_18_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "edge", - "browser_version": "16.0", + "browser_version": "18.0", "device": null, "os": "Windows" }, @@ -23,43 +23,43 @@ "device": null, "os": "Windows" }, - "bs_chrome_74_windows_10": { + "bs_chrome_80_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "chrome", - "browser_version": "74.0", + "browser_version": "80.0", "device": null, "os": "Windows" }, - "bs_chrome_75_windows_10": { + "bs_chrome_79_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "chrome", - "browser_version": "75.0", + "browser_version": "79.0", "device": null, "os": "Windows" }, - "bs_firefox_66_windows_10": { + "bs_firefox_73_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "firefox", - "browser_version": "66.0", + "browser_version": "73.0", "device": null, "os": "Windows" }, - "bs_firefox_67_windows_10": { + "bs_firefox_72_windows_10": { "base": "BrowserStack", "os_version": "10", "browser": "firefox", - "browser_version": "67.0", + "browser_version": "72.0", "device": null, "os": "Windows" }, - "bs_safari_11_mac_high_sierra": { + "bs_safari_11_mac_catalina": { "base": "BrowserStack", - "os_version": "High Sierra", + "os_version": "Catalina", "browser": "safari", - "browser_version": "11.1", + "browser_version": "13.0", "device": null, "os": "OS X" }, diff --git a/gulpHelpers.js b/gulpHelpers.js index 84f01b4e966..bcaf3736f15 100644 --- a/gulpHelpers.js +++ b/gulpHelpers.js @@ -59,6 +59,7 @@ module.exports = { }); } + // we need to forcefuly include the parentModule if the subModule is present in modules list and parentModule is not present in modules list Object.keys(submodules).forEach(parentModule => { if ( !modules.includes(parentModule) && @@ -83,7 +84,9 @@ module.exports = { if (fs.lstatSync(modulePath).isDirectory()) { modulePath = path.join(modulePath, 'index.js') } - memo[modulePath] = moduleName; + if (fs.existsSync(modulePath)) { + memo[modulePath] = moduleName; + } return memo; }, {}); } catch (err) { diff --git a/gulpfile.js b/gulpfile.js index 7c4ca306886..64152baa7ba 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 @@ -67,11 +68,11 @@ function lint(done) { if (argv.nolint) { return done(); } - const isFixed = function(file) { + const isFixed = function (file) { return file.eslint != null && file.eslint.fixed; } - return gulp.src(['src/**/*.js', 'modules/**/*.js', 'test/**/*.js'], {base: './'}) - .pipe(gulpif(argv.nolintfix, eslint(), eslint({fix: true}))) + return gulp.src(['src/**/*.js', 'modules/**/*.js', 'test/**/*.js'], { base: './' }) + .pipe(gulpif(argv.nolintfix, eslint(), eslint({ fix: true }))) .pipe(eslint.format('stylish')) .pipe(eslint.failAfterError()) .pipe(gulpif(isFixed, gulp.dest('./'))); @@ -84,7 +85,7 @@ function viewCoverage(done) { connect.server({ port: coveragePort, - root: 'build/coverage/karma_html', + root: 'build/coverage/lcov-report', livereload: false }); opens('http://' + mylocalhost + ':' + coveragePort); @@ -160,7 +161,7 @@ function nodeBundle(modules) { .on('error', (err) => { reject(err); }) - .pipe(through.obj(function(file, enc, done) { + .pipe(through.obj(function (file, enc, done) { resolve(file.contents.toString(enc)); done(); })); @@ -199,7 +200,7 @@ function bundle(dev, moduleArr) { return gulp.src( entries ) - .pipe(gulpif(dev, sourcemaps.init({loadMaps: true}))) + .pipe(gulpif(dev, sourcemaps.init({ loadMaps: true }))) .pipe(concat(outputFileName)) .pipe(gulpif(!argv.manualEnable, footer('\n<%= global %>.processQueue();', { global: prebid.globalVarName @@ -238,25 +239,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); }); @@ -273,7 +274,7 @@ function test(done) { } function newKarmaCallback(done) { - return function(exitCode) { + return function (exitCode) { if (exitCode) { done(new Error('Karma tests failed with exit code ' + exitCode)); if (argv.browserstack) { @@ -296,7 +297,7 @@ function testCoverage(done) { function coveralls() { // 2nd arg is a dependency: 'test' must be finished // first send results of istanbul's test coverage to coveralls.io. return gulp.src('gulpfile.js', { read: false }) // You have to give it a file, but you don't - // have to read it. + // have to read it. .pipe(shell('cat build/coverage/lcov.info | node_modules/coveralls/bin/coveralls.js')); } @@ -326,11 +327,27 @@ function setupE2e(done) { done(); } -gulp.task('updatepath', function(){ +function injectFakeServerEndpoint() { return gulp.src(['build/dist/*.js']) - .pipe(replace('ib.adnxs.com/ut/v3/prebid', host + ':' + mockServerPort + '/')) - .pipe(gulp.dest('build/dist')); -}); + .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 +372,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/advanced_size_mapping.html b/integrationExamples/gpt/advanced_size_mapping.html new file mode 100644 index 00000000000..4f1ba085c77 --- /dev/null +++ b/integrationExamples/gpt/advanced_size_mapping.html @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + +

Prebid.js Test

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

Prebid.js Test

-
- -
-
-

Audience Network quick start

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

Audigent Segments Prebid

+ +
+ +
+TDID: +
+
+ +Audigent Segments: +
+
+ + diff --git a/integrationExamples/gpt/digitrust_Full.html b/integrationExamples/gpt/digitrust_Full.html index 7ec268a619a..fc7704776f4 100644 --- a/integrationExamples/gpt/digitrust_Full.html +++ b/integrationExamples/gpt/digitrust_Full.html @@ -70,7 +70,7 @@ }()); var t = document.createElement('script'); t.async = false; - t.src = 'http://acdn.adnxs.com/cmp/cmp.bundle.js'; + t.src = 'https://acdn.adnxs.com/cmp/cmp.bundle.js'; var tag = document.getElementsByTagName('head')[0]; tag.appendChild(t); } diff --git a/integrationExamples/gpt/digitrust_Simple.html b/integrationExamples/gpt/digitrust_Simple.html index 91eca591898..2581c6ce7cc 100644 --- a/integrationExamples/gpt/digitrust_Simple.html +++ b/integrationExamples/gpt/digitrust_Simple.html @@ -71,7 +71,7 @@ }()); var t = document.createElement('script'); t.async = false; - t.src = 'http://acdn.adnxs.com/cmp/cmp.bundle.js'; + t.src = 'https://acdn.adnxs.com/cmp/cmp.bundle.js'; var tag = document.getElementsByTagName('head')[0]; tag.appendChild(t); } @@ -148,6 +148,9 @@ } else { console.error('Digitrust init failed'); + if(digiTrustResult.err){ + console.error(digiTrustResult.err); + } } } }, @@ -157,6 +160,12 @@ expires: 60 } }] + }, + userIdTargeting: { + "GAM": true, + "GAM_KEYS": { + "tdid": "TTD_ID" // send tdid as TTD_ID + } } }); pbjs.addAdUnits(adUnits); diff --git a/integrationExamples/gpt/digitrust_cmp_test.html b/integrationExamples/gpt/digitrust_cmp_test.html index f5fc0aace63..6f0a70188f3 100644 --- a/integrationExamples/gpt/digitrust_cmp_test.html +++ b/integrationExamples/gpt/digitrust_cmp_test.html @@ -187,6 +187,6 @@

DigiTrust Prebid Sample - No Framework

googletag.cmd.push(function () { googletag.display('test-div'); }); - + diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index d68e65011be..47ba5b8f18a 100755 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -88,4 +88,4 @@
Div-1
- + \ No newline at end of file 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..4acbe0aae31 100644 --- a/integrationExamples/gpt/userId_example.html +++ b/integrationExamples/gpt/userId_example.html @@ -140,7 +140,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 @@ -157,11 +168,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", @@ -184,9 +190,34 @@ 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 + } }], 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"> - + - + + - - +```javascript +{ + bidder: 'between', + params: { + s: BETWEEN_SECTION_ID, + cur: 'USD' + } +} +``` + +### GDPR +Also, we support GDPR. To find out how to use GDPR in Prebid you can visit [this page](http://prebid.org/dev-docs/modules/consentManagement.html) - + + + + }); + -

Prebid.js BetweenBidAdapter Test

- +

Prebid.js BetweenBidAdapter Test

+ - -``` \ No newline at end of file + +``` diff --git a/modules/bidfluenceBidAdapter.js b/modules/bidfluenceBidAdapter.js index c6adc2897b0..f8a1f9ac92f 100644 --- a/modules/bidfluenceBidAdapter.js +++ b/modules/bidfluenceBidAdapter.js @@ -1,5 +1,8 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const storage = getStorageManager(); const BIDDER_CODE = 'bidfluence'; function stdTimezoneOffset(t) { @@ -46,7 +49,7 @@ export const spec = { var payload = { v: '2.0', azr: true, - ck: utils.cookiesAreEnabled(), + ck: storage.cookiesAreEnabled(), re: refInfo ? refInfo.referer : '', st: refInfo ? refInfo.stack : [], tz: getBdfTz(new Date()), diff --git a/modules/bidglassBidAdapter.js b/modules/bidglassBidAdapter.js index 553a52b25f4..6db35f184ca 100644 --- a/modules/bidglassBidAdapter.js +++ b/modules/bidglassBidAdapter.js @@ -1,134 +1,134 @@ -import * as utils from '../src/utils'; -// import {config} from 'src/config'; -import {registerBidder} from '../src/adapters/bidderFactory'; - -const BIDDER_CODE = 'bidglass'; - -export const spec = { - code: BIDDER_CODE, - aliases: ['bg'], // short code - /** - * Determines whether or not the given bid request is valid. - * - * @param {BidRequest} bid The bid params to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ - isBidRequestValid: function(bid) { - return !!(bid.params.adUnitId && !isNaN(parseFloat(bid.params.adUnitId)) && isFinite(bid.params.adUnitId)); - }, - /** - * Make a server request from the list of BidRequests. - * - * @param {validBidRequests[]} - an array of bids - * @return ServerRequest Info describing the request to the server. - */ - buildRequests: function(validBidRequests, bidderRequest) { - /* - Sample array entry for validBidRequests[]: - [{ - "bidder": "bidglass", - "bidId": "51ef8751f9aead", - "params": { - "adUnitId": 11, - ... - }, - "adUnitCode": "div-gpt-ad-1460505748561-0", - "transactionId": "d7b773de-ceaa-484d-89ca-d9f51b8d61ec", - "sizes": [[320,50],[300,250],[300,600]], - "bidderRequestId": "418b37f85e772c", - "auctionId": "18fd8b8b0bd757", - "bidRequestsCount": 1 - }] - */ - - let imps = []; - let getReferer = function() { - return window === window.top ? window.location.href : window.parent === window.top ? document.referrer : null; - }; - let getOrigins = function() { - var ori = ['https://' + window.location.hostname]; - - if (window.location.ancestorOrigins) { - for (var i = 0; i < window.location.ancestorOrigins.length; i++) { - ori.push(window.location.ancestorOrigins[i]); - } - } else if (window !== window.top) { - // Derive the parent origin - var parts = document.referrer.split('/'); - - ori.push('https://' + parts[2]); - - if (window.parent !== window.top) { - // Additional unknown origins exist - ori.push('null'); - } - } - - return ori; - }; - - utils._each(validBidRequests, function(bid) { - bid.sizes = ((utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0])) ? bid.sizes : [bid.sizes]); - bid.sizes = bid.sizes.filter(size => utils.isArray(size)); - - // Stuff to send: [bid id, sizes, adUnitId] - imps.push({ - bidId: bid.bidId, - sizes: bid.sizes, - adUnitId: utils.getBidIdParameter('adUnitId', bid.params) - }); - }); - - // Stuff to send: page URL - const bidReq = { - reqId: utils.getUniqueIdentifierStr(), - imps: imps, - ref: getReferer(), - ori: getOrigins() - }; - - let url = 'https://bid.glass/ad/hb.php?' + - `src=$$REPO_AND_VERSION$$`; - - return { - method: 'POST', - url: url, - data: JSON.stringify(bidReq), - options: { - contentType: 'text/plain', - withCredentials: false - } - } - }, - - /** - * Unpack the response from the server into a list of bids. - * - * @param {ServerResponse} serverResponse A successful response from the server. - * @return {Bid[]} An array of bids which were nested inside the server. - */ - interpretResponse: function(serverResponse) { - const bidResponses = []; - - utils._each(serverResponse.body.bidResponses, function(bid) { - bidResponses.push({ - requestId: bid.requestId, - cpm: parseFloat(bid.cpm), - width: parseInt(bid.width, 10), - height: parseInt(bid.height, 10), - creativeId: bid.creativeId, - dealId: bid.dealId || null, - currency: bid.currency || 'USD', - mediaType: bid.mediaType || 'banner', - netRevenue: true, - ttl: bid.ttl || 10, - ad: bid.ad - }); - }); - - return bidResponses; - } - -} - -registerBidder(spec); +import * as utils from '../src/utils.js'; +// import {config} from 'src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'bidglass'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['bg'], // short code + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bid) { + return !!(bid.params.adUnitId && !isNaN(parseFloat(bid.params.adUnitId)) && isFinite(bid.params.adUnitId)); + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests, bidderRequest) { + /* + Sample array entry for validBidRequests[]: + [{ + "bidder": "bidglass", + "bidId": "51ef8751f9aead", + "params": { + "adUnitId": 11, + ... + }, + "adUnitCode": "div-gpt-ad-1460505748561-0", + "transactionId": "d7b773de-ceaa-484d-89ca-d9f51b8d61ec", + "sizes": [[320,50],[300,250],[300,600]], + "bidderRequestId": "418b37f85e772c", + "auctionId": "18fd8b8b0bd757", + "bidRequestsCount": 1 + }] + */ + + let imps = []; + let getReferer = function() { + return window === window.top ? window.location.href : window.parent === window.top ? document.referrer : null; + }; + let getOrigins = function() { + var ori = ['https://' + window.location.hostname]; + + if (window.location.ancestorOrigins) { + for (var i = 0; i < window.location.ancestorOrigins.length; i++) { + ori.push(window.location.ancestorOrigins[i]); + } + } else if (window !== window.top) { + // Derive the parent origin + var parts = document.referrer.split('/'); + + ori.push('https://' + parts[2]); + + if (window.parent !== window.top) { + // Additional unknown origins exist + ori.push('null'); + } + } + + return ori; + }; + + utils._each(validBidRequests, function(bid) { + bid.sizes = ((utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0])) ? bid.sizes : [bid.sizes]); + bid.sizes = bid.sizes.filter(size => utils.isArray(size)); + + // Stuff to send: [bid id, sizes, adUnitId] + imps.push({ + bidId: bid.bidId, + sizes: bid.sizes, + adUnitId: utils.getBidIdParameter('adUnitId', bid.params) + }); + }); + + // Stuff to send: page URL + const bidReq = { + reqId: utils.getUniqueIdentifierStr(), + imps: imps, + ref: getReferer(), + ori: getOrigins() + }; + + let url = 'https://bid.glass/ad/hb.php?' + + `src=$$REPO_AND_VERSION$$`; + + return { + method: 'POST', + url: url, + data: JSON.stringify(bidReq), + options: { + contentType: 'text/plain', + withCredentials: false + } + } + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse) { + const bidResponses = []; + + utils._each(serverResponse.body.bidResponses, function(bid) { + bidResponses.push({ + requestId: bid.requestId, + cpm: parseFloat(bid.cpm), + width: parseInt(bid.width, 10), + height: parseInt(bid.height, 10), + creativeId: bid.creativeId, + dealId: bid.dealId || null, + currency: bid.currency || 'USD', + mediaType: bid.mediaType || 'banner', + netRevenue: true, + ttl: bid.ttl || 10, + ad: bid.ad + }); + }); + + return bidResponses; + } + +} + +registerBidder(spec); diff --git a/modules/bidlabBidAdapter.js b/modules/bidlabBidAdapter.js new file mode 100644 index 00000000000..8f501505a6d --- /dev/null +++ b/modules/bidlabBidAdapter.js @@ -0,0 +1,112 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; + +const BIDDER_CODE = 'bidlab'; +const AD_URL = 'https://service.bidlab.ai/?c=o&m=multi'; +const URL_SYNC = 'https://service.bidlab.ai/?c=o&m=sync'; +const NO_SYNC = true; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || + !bid.ttl || !bid.currency) { + return false; + } + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + case VIDEO: + return Boolean(bid.vastUrl); + case NATIVE: + return Boolean(bid.native && bid.native.title && bid.native.image && bid.native.impressionTrackers); + default: + return false; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + noSync: NO_SYNC, + + isBidRequestValid: (bid) => { + return Boolean(bid.bidId && bid.params && !isNaN(parseInt(bid.params.placementId))); + }, + + buildRequests: (validBidRequests = [], bidderRequest) => { + let winTop = window; + let location; + try { + location = new URL(bidderRequest.refererInfo.referer) + winTop = window.top; + } catch (e) { + location = winTop.location; + utils.logMessage(e); + }; + let placements = []; + let request = { + 'deviceWidth': winTop.screen.width, + 'deviceHeight': winTop.screen.height, + 'language': (navigator && navigator.language) ? navigator.language.split('-')[0] : '', + 'secure': 1, + 'host': location.host, + 'page': location.pathname, + 'placements': placements + }; + request.language.indexOf('-') != -1 && (request.language = request.language.split('-')[0]) + if (bidderRequest) { + if (bidderRequest.uspConsent) { + request.ccpa = bidderRequest.uspConsent; + } + if (bidderRequest.gdprConsent) { + request.gdpr = bidderRequest.gdprConsent + } + } + const len = validBidRequests.length; + + for (let i = 0; i < len; i++) { + let bid = validBidRequests[i]; + let traff = bid.params.traffic || BANNER + + placements.push({ + placementId: bid.params.placementId, + bidId: bid.bidId, + sizes: bid.mediaTypes && bid.mediaTypes[traff] && bid.mediaTypes[traff].sizes ? bid.mediaTypes[traff].sizes : [], + traffic: traff + }); + if (bid.schain) { + placements.schain = bid.schain; + } + } + return { + method: 'POST', + url: AD_URL, + data: request + }; + }, + + interpretResponse: (serverResponse) => { + let response = []; + for (let i = 0; i < serverResponse.body.length; i++) { + let resItem = serverResponse.body[i]; + if (isBidResponseValid(resItem)) { + response.push(resItem); + } + } + return response; + }, + + getUserSyncs: (syncOptions, serverResponses) => { + if (NO_SYNC) { + return false + } else { + return [{ + type: 'image', + url: URL_SYNC + }]; + } + } + +}; + +registerBidder(spec); diff --git a/modules/bidlabBidAdapter.md b/modules/bidlabBidAdapter.md new file mode 100644 index 00000000000..3e5fe3128ed --- /dev/null +++ b/modules/bidlabBidAdapter.md @@ -0,0 +1,53 @@ +# Overview + +``` +Module Name: bidlab Bidder Adapter +Module Type: bidlab Bidder Adapter +``` + +# Description + +Module that connects to bidlab demand sources + +# Test Parameters +``` + var adUnits = [ + // Will return static test banner + { + code: 'placementId_0', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: 'bidlab', + params: { + placementId: 0, + traffic: 'banner' + } + } + ] + }, + // Will return test vast xml. All video params are stored under placement in publishers UI + { + code: 'placementId_0', + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'instream' + } + }, + bids: [ + { + bidder: 'bidlab', + params: { + placementId: 0, + traffic: 'video' + } + } + ] + } + ]; +``` diff --git a/modules/bidphysicsBidAdapter.js b/modules/bidphysicsBidAdapter.js index cdf30e670fc..b6b5690ede5 100644 --- a/modules/bidphysicsBidAdapter.js +++ b/modules/bidphysicsBidAdapter.js @@ -1,6 +1,6 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; -import * as utils from '../src/utils'; -import {BANNER} from '../src/mediaTypes'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; +import {BANNER} from '../src/mediaTypes.js'; const ENDPOINT_URL = 'https://exchange.bidphysics.com/auction'; diff --git a/modules/bluebillywigBidAdapter.js b/modules/bluebillywigBidAdapter.js new file mode 100644 index 00000000000..4d40d931e1d --- /dev/null +++ b/modules/bluebillywigBidAdapter.js @@ -0,0 +1,390 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { VIDEO } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; +import { Renderer } from '../src/Renderer.js'; +import { createEidsArray } from './userId/eids.js'; + +const DEV_MODE = window.location.search.match(/bbpbs_debug=true/); + +// Blue Billywig Constants +const BB_CONSTANTS = { + BIDDER_CODE: 'bluebillywig', + AUCTION_URL: '$$URL_STARTpbs.bluebillywig.com/openrtb2/auction?pub=$$PUBLICATION', + SYNC_URL: '$$URL_STARTpbs.bluebillywig.com/static/cookie-sync.html?pub=$$PUBLICATION', + RENDERER_URL: 'https://$$PUBLICATION.bbvms.com/r/$$RENDERER.js', + DEFAULT_TIMEOUT: 5000, + DEFAULT_TTL: 300, + DEFAULT_WIDTH: 768, + DEFAULT_HEIGHT: 432, + DEFAULT_NET_REVENUE: true +}; + +// Aliasing +const getConfig = config.getConfig; + +// Helper Functions +export const BB_HELPERS = { + addSiteAppDevice: function(request, pageUrl) { + if (!request) return; + + if (typeof getConfig('app') === 'object') request.app = getConfig('app'); + else { + request.site = {}; + if (typeof getConfig('site') === 'object') request.site = getConfig('site'); + if (pageUrl) request.site.page = pageUrl; + } + + if (typeof getConfig('device') === 'object') request.device = getConfig('device'); + if (!request.device) request.device = {}; + if (!request.device.w) request.device.w = window.innerWidth; + if (!request.device.h) request.device.h = window.innerHeight; + }, + addSchain: function(request, validBidRequests) { + if (!request) return; + + const schain = utils.deepAccess(validBidRequests, '0.schain'); + if (schain) request.source.ext = { schain: schain }; + }, + addCurrency: function(request) { + if (!request) return; + + const adServerCur = getConfig('currency.adServerCurrency'); + if (adServerCur && typeof adServerCur === 'string') request.cur = [adServerCur]; + else if (Array.isArray(adServerCur) && adServerCur.length) request.cur = [adServerCur[0]]; + }, + addUserIds: function(request, validBidRequests) { + if (!request) return; + + const bidUserId = utils.deepAccess(validBidRequests, '0.userId'); + const eids = createEidsArray(bidUserId); + + if (eids.length) { + utils.deepSetValue(request, 'user.ext.eids', eids); + } + }, + addDigiTrust: function(request, bidRequests) { + const digiTrust = BB_HELPERS.getDigiTrustParams(bidRequests && bidRequests[0]); + if (digiTrust) utils.deepSetValue(request, 'user.ext.digitrust', digiTrust); + }, + substituteUrl: function (url, publication, renderer) { + return url.replace('$$URL_START', (DEV_MODE) ? 'https://dev.' : 'https://').replace('$$PUBLICATION', publication).replace('$$RENDERER', renderer); + }, + getAuctionUrl: function(publication) { + return BB_HELPERS.substituteUrl(BB_CONSTANTS.AUCTION_URL, publication); + }, + getSyncUrl: function(publication) { + return BB_HELPERS.substituteUrl(BB_CONSTANTS.SYNC_URL, publication); + }, + getRendererUrl: function(publication, renderer) { + return BB_HELPERS.substituteUrl(BB_CONSTANTS.RENDERER_URL, publication, renderer); + }, + getDigiTrustParams: function(bidRequest) { + const digiTrustId = BB_HELPERS.getDigiTrustId(bidRequest); + + if (!digiTrustId || (digiTrustId.privacy && digiTrustId.privacy.optout)) return null; + return { + id: digiTrustId.id, + keyv: digiTrustId.keyv + } + }, + getDigiTrustId: function(bidRequest) { + const bidRequestDigiTrust = utils.deepAccess(bidRequest, 'userId.digitrustid.data'); + if (bidRequestDigiTrust) return bidRequestDigiTrust; + + const digiTrustUser = getConfig('digiTrustId'); + return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || null; + }, + transformRTBToPrebidProps: function(bid, serverResponse) { + bid.cpm = bid.price; delete bid.price; + bid.bidId = bid.impid; + bid.requestId = bid.impid; delete bid.impid; + bid.width = bid.w || BB_CONSTANTS.DEFAULT_WIDTH; + bid.height = bid.h || BB_CONSTANTS.DEFAULT_HEIGHT; + if (bid.adm) { + bid.ad = bid.adm; + bid.vastXml = bid.adm; + delete bid.adm; + } + if (bid.nurl && !bid.adm) { // ad markup is on win notice url, and adm is ommited according to OpenRTB 2.5 + bid.vastUrl = bid.nurl; + delete bid.nurl; + } + bid.netRevenue = BB_CONSTANTS.DEFAULT_NET_REVENUE; + bid.creativeId = bid.crid; delete bid.crid; + bid.currency = serverResponse.cur; + bid.ttl = BB_CONSTANTS.DEFAULT_TTL; + }, +}; + +// Renderer Functions +const BB_RENDERER = { + bootstrapPlayer: function(bid) { + const config = { + code: bid.adUnitCode, + }; + + if (bid.vastXml) config.vastXml = bid.vastXml; + else if (bid.vastUrl) config.vastUrl = bid.vastUrl; + + if (!bid.vastXml && !bid.vastUrl) { + utils.logWarn(`${BB_CONSTANTS.BIDDER_CODE}: No vastXml or vastUrl on bid, bailing...`); + return; + } + + const rendererId = BB_RENDERER.getRendererId(bid.publicationName, bid.rendererCode); + + const ele = document.getElementById(bid.adUnitCode); // NB convention + + let renderer; + + for (let rendererIndex = 0; rendererIndex < window.bluebillywig.renderers.length; rendererIndex++) { + if (window.bluebillywig.renderers[rendererIndex]._id === rendererId) { + renderer = window.bluebillywig.renderers[rendererIndex]; + break; + } + } + + if (renderer) renderer.bootstrap(config, ele); + else utils.logWarn(`${BB_CONSTANTS.BIDDER_CODE}: Couldn't find a renderer with ${rendererId}`); + }, + newRenderer: function(rendererUrl, adUnitCode) { + const renderer = Renderer.install({ + url: rendererUrl, + loaded: false, + adUnitCode + }); + + try { + renderer.setRender(BB_RENDERER.outstreamRender); + } catch (err) { + utils.logWarn(`${BB_CONSTANTS.BIDDER_CODE}: Error tying to setRender on renderer`, err); + } + + return renderer; + }, + outstreamRender: function(bid) { + bid.renderer.push(function() { BB_RENDERER.bootstrapPlayer(bid) }); + }, + getRendererId: function(pub, renderer) { + return `${pub}-${renderer}`; // NB convention! + } +}; + +// Spec Functions +// These functions are used to construct the core spec for the adapter +export const spec = { + code: BB_CONSTANTS.BIDDER_CODE, + supportedMediaTypes: [VIDEO], + syncStore: { bidders: [], }, + isBidRequestValid(bid) { + const publicationNameRegex = /^\w+\.?\w+$/; + const rendererRegex = /^[\w+_]+$/; + + if (!bid.params) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no params set on bid. Rejecting bid: `, bid); + return false; + } + + if (!bid.params.hasOwnProperty('publicationName') || typeof bid.params.publicationName !== 'string') { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no publicationName specified in bid params, or it's not a string. Rejecting bid: `, bid); + return false; + } else if (!publicationNameRegex.test(bid.params.publicationName)) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: publicationName must be in format 'publication' or 'publication.environment'. Rejecting bid: `, bid); + return false; + } + + if ((!bid.params.hasOwnProperty('rendererCode') || typeof bid.params.rendererCode !== 'string')) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no rendererCode was specified in bid params. Rejecting bid: `, bid); + return false; + } else if (!rendererRegex.test(bid.params.rendererCode)) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: rendererCode must be alphanumeric, including underscores. Rejecting bid: `, bid); + return false; + } + + if (!bid.params.accountId) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no accountId specified in bid params. Rejecting bid: `, bid); + return false; + } + + if (bid.params.hasOwnProperty('connections')) { + if (!Array.isArray(bid.params.connections)) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: connections is not of type array. Rejecting bid: `, bid); + return false; + } else { + for (let connectionIndex = 0; connectionIndex < bid.params.connections.length; connectionIndex++) { + const connection = bid.params.connections[connectionIndex]; + if (!bid.params.hasOwnProperty(connection)) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: connection specified in params.connections, but not configured in params. Rejecting bid: `, bid); + return false; + } + } + } + } else { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no connections specified in bid. Rejecting bid: `, bid); + return false; + } + + if (bid.hasOwnProperty('mediaTypes') && bid.mediaTypes.hasOwnProperty(VIDEO)) { + if (!bid.mediaTypes[VIDEO].hasOwnProperty('context')) { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: no context specified in bid. Rejecting bid: `, bid); + return false; + } + + if (bid.mediaTypes[VIDEO].context !== 'outstream') { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: video.context is invalid, must be "outstream". Rejecting bid: `, bid); + return false; + } + } else { + utils.logError(`${BB_CONSTANTS.BIDDER_CODE}: mediaTypes or mediaTypes.video is not specified. Rejecting bid: `, bid); + return false; + } + + return true; + }, + buildRequests(validBidRequests, bidderRequest) { + const imps = []; + + for (let validBidRequestIndex = 0; validBidRequestIndex < validBidRequests.length; validBidRequestIndex++) { + const validBidRequest = validBidRequests[validBidRequestIndex]; + const _this = this; + + const ext = validBidRequest.params.connections.reduce(function(extBuilder, connection) { + extBuilder[connection] = validBidRequest.params[connection]; + + if (_this.syncStore.bidders.indexOf(connection) === -1) _this.syncStore.bidders.push(connection); + + return extBuilder; + }, {}); + + imps.push({ id: validBidRequest.bidId, ext, secure: window.location.protocol === 'https' ? 1 : 0, video: utils.deepAccess(validBidRequest, 'mediaTypes.video') }); + } + + const request = { + id: bidderRequest.auctionId, + source: {tid: bidderRequest.auctionId}, + tmax: BB_CONSTANTS.DEFAULT_TIMEOUT, + imp: imps, + test: DEV_MODE ? 1 : 0, + ext: { + prebid: { + targeting: { includewinners: true, includebidderkeys: false } + } + } + }; + + // handle privacy settings for GDPR/CCPA/COPPA + if (bidderRequest.gdprConsent) { + let gdprApplies = 0; + if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; + utils.deepSetValue(request, 'regs.ext.gdpr', gdprApplies); + utils.deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + + if (bidderRequest.uspConsent) { + utils.deepSetValue(request, 'regs.ext.us_privacy', bidderRequest.uspConsent); + this.syncStore.uspConsent = bidderRequest.uspConsent; + } + + if (getConfig('coppa') == true) utils.deepSetValue(request, 'regs.coppa', 1); + + // Enrich the request with any external data we may have + BB_HELPERS.addSiteAppDevice(request, bidderRequest.refererInfo && bidderRequest.refererInfo.referer); + BB_HELPERS.addSchain(request, validBidRequests); + BB_HELPERS.addCurrency(request); + BB_HELPERS.addUserIds(request, validBidRequests); + BB_HELPERS.addDigiTrust(request, validBidRequests); + + return { + method: 'POST', + url: BB_HELPERS.getAuctionUrl(validBidRequests[0].params.publicationName), + data: JSON.stringify(request), + bidderRequest: bidderRequest + }; + }, + interpretResponse(serverResponse, request) { + serverResponse = serverResponse.body || {}; + + if (!serverResponse.hasOwnProperty('seatbid') || !Array.isArray(serverResponse.seatbid)) { + return []; + } + + const bids = []; + + for (let seatbidIndex = 0; seatbidIndex < serverResponse.seatbid.length; seatbidIndex++) { + const seatbid = serverResponse.seatbid[seatbidIndex]; + if (!seatbid.bid || !Array.isArray(seatbid.bid)) continue; + for (let bidIndex = 0; bidIndex < seatbid.bid.length; bidIndex++) { + const bid = seatbid.bid[bidIndex]; + BB_HELPERS.transformRTBToPrebidProps(bid, serverResponse); + + let bidParams; + for (let bidderRequestBidsIndex = 0; bidderRequestBidsIndex < request.bidderRequest.bids.length; bidderRequestBidsIndex++) { + if (request.bidderRequest.bids[bidderRequestBidsIndex].bidId === bid.bidId) { + bidParams = request.bidderRequest.bids[bidderRequestBidsIndex].params; + } + } + + if (bidParams) { + bid.publicationName = bidParams.publicationName; + bid.rendererCode = bidParams.rendererCode; + bid.accountId = bidParams.accountId; + } + + const rendererUrl = BB_HELPERS.getRendererUrl(bid.publicationName, bid.rendererCode); + + bid.renderer = BB_RENDERER.newRenderer(rendererUrl, bid.adUnitCode); + + bids.push(bid); + } + } + + return bids; + }, + getUserSyncs(syncOptions, serverResponses, gdpr) { + if (!serverResponses || !serverResponses.length) return []; + if (!syncOptions.iframeEnabled) return []; + + const queryString = []; + let accountId; + let publication; + + const serverResponse = serverResponses[0]; + if (!serverResponse.body || !serverResponse.body.seatbid) return []; + + for (let seatbidIndex = 0; seatbidIndex < serverResponse.body.seatbid.length; seatbidIndex++) { + const seatbid = serverResponse.body.seatbid[seatbidIndex]; + for (let bidIndex = 0; bidIndex < seatbid.bid.length; bidIndex++) { + const bid = seatbid.bid[bidIndex]; + accountId = bid.accountId || null; + publication = bid.publicationName || null; + + if (publication && accountId) break; + } + if (publication && accountId) break; + } + + if (!publication || !accountId) return []; + + if (gdpr.gdprApplies) queryString.push(`gdpr=${gdpr.gdprApplies ? 1 : 0}`); + if (gdpr.gdprApplies && gdpr.consentString) queryString.push(`gdpr_consent=${gdpr.consentString}`); + + if (this.syncStore.uspConsent) queryString.push(`usp_consent=${this.syncStore.uspConsent}`); + + queryString.push(`accountId=${accountId}`); + queryString.push(`bidders=${btoa(JSON.stringify(this.syncStore.bidders))}`); + queryString.push(`cb=${Date.now()}-${Math.random().toString().replace('.', '')}`); + + if (DEV_MODE) queryString.push('bbpbs_debug=true'); + + // NB syncUrl by default starts with ?pub=$$PUBLICATION + const syncUrl = `${BB_HELPERS.getSyncUrl(publication)}&${queryString.join('&')}`; + + return [{ + type: 'iframe', + url: syncUrl + }]; + } +}; + +registerBidder(spec); diff --git a/modules/bluebillywigBidAdapter.md b/modules/bluebillywigBidAdapter.md new file mode 100644 index 00000000000..7879697baf5 --- /dev/null +++ b/modules/bluebillywigBidAdapter.md @@ -0,0 +1,38 @@ +# Overview + +``` +Module Name: Blue Billywig Adapter +Module Type: Bidder Adapter +Maintainer: dev+prebid@bluebillywig.com +``` + +# Description + +Prebid Blue Billywig Bidder Adapter + +# Test Parameters + +``` + const adUnits = [{ + code: 'ad-unit', + sizes: [[[768,432],[640,480],[640,360]]], + mediaTypes: { + video: { + playerSize: [768, 432], + context: 'outstream', + mimes: ['video/mp4'], + protocols: [ 2,3,5,6] + } + }, + bids: [{ + bidder: 'bluebillywig', + params: { + publicationName: "bbprebid", + rendererCode: "renderer", + accountId: 642, + connections: [ 'bluebillywig' ], + bluebillywig: {} + } + }] + }]; +``` diff --git a/modules/bridgewellBidAdapter.js b/modules/bridgewellBidAdapter.js new file mode 100644 index 00000000000..0303e4f74bd --- /dev/null +++ b/modules/bridgewellBidAdapter.js @@ -0,0 +1,272 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE } from '../src/mediaTypes.js'; +import find from 'core-js-pure/features/array/find.js'; + +const BIDDER_CODE = 'bridgewell'; +const REQUEST_ENDPOINT = 'https://prebid.scupio.com/recweb/prebid.aspx?cb=' + Math.random(); +const BIDDER_VERSION = '0.0.2'; + +export const spec = { + code: BIDDER_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) { + let valid = false; + + if (bid && bid.params && bid.params.ChannelID) { + valid = true; + } + + return valid; + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function (validBidRequests, bidderRequest) { + const adUnits = []; + utils._each(validBidRequests, function (bid) { + adUnits.push({ + ChannelID: bid.params.ChannelID, + adUnitCode: bid.adUnitCode, + mediaTypes: bid.mediaTypes || { + banner: { + sizes: bid.sizes + } + } + }); + }); + + let topUrl = ''; + if (bidderRequest && bidderRequest.refererInfo) { + topUrl = bidderRequest.refererInfo.referer; + } + + return { + method: 'POST', + url: REQUEST_ENDPOINT, + data: { + version: { + prebid: '$prebid.version$', + bridgewell: BIDDER_VERSION + }, + inIframe: utils.inIframe(), + url: topUrl, + referrer: getTopWindowReferrer(), + adUnits: adUnits + }, + validBidRequests: validBidRequests + }; + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @param {*} bidRequest + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, bidRequest) { + const bidResponses = []; + + // map responses to requests + utils._each(bidRequest.validBidRequests, function (req) { + const bidResponse = {}; + + if (!serverResponse.body) { + return; + } + + let matchedResponse = find(serverResponse.body, function (res) { + let valid = false; + + if (res && !res.consumed) { + let mediaTypes = req.mediaTypes; + let adUnitCode = req.adUnitCode; + if (res.adUnitCode) { + return res.adUnitCode === adUnitCode; + } else if (res.width && res.height && mediaTypes) { + if (mediaTypes.native) { // dont care native sizes + valid = true; + } else if (mediaTypes.banner) { + if (mediaTypes.banner.sizes) { + let width = res.width; + let height = res.height; + let sizes = mediaTypes.banner.sizes; + // check response size validation + if (typeof sizes[0] === 'number') { // for foramt Array[Number] check + valid = width === sizes[0] && height === sizes[1]; + } else { // for format Array[Array[Number]] check + valid = !!find(sizes, function (size) { + return (width === size[0] && height === size[1]); + }); + } + } + } + } + } + + return valid; + }); + + if (matchedResponse) { + matchedResponse.consumed = true; + + // check required parameters + if (typeof matchedResponse.cpm !== 'number') { + return; + } else if (typeof matchedResponse.netRevenue !== 'boolean') { + return; + } else if (typeof matchedResponse.currency !== 'string') { + return; + } else if (typeof matchedResponse.mediaType !== 'string') { + return; + } + + bidResponse.requestId = req.bidId; + bidResponse.cpm = matchedResponse.cpm; + bidResponse.width = matchedResponse.width; + bidResponse.height = matchedResponse.height; + bidResponse.ttl = matchedResponse.ttl; + bidResponse.creativeId = matchedResponse.id; + bidResponse.netRevenue = matchedResponse.netRevenue; + bidResponse.currency = matchedResponse.currency; + bidResponse.mediaType = matchedResponse.mediaType; + + // check required parameters by matchedResponse.mediaType + switch (matchedResponse.mediaType) { + case BANNER: + // check banner required parameters + if (typeof matchedResponse.ad !== 'string') { + return; + } + + bidResponse.ad = matchedResponse.ad; + break; + case NATIVE: + // check native required parameters + if (!matchedResponse.native) { + return; + } + + let reqNativeLayout = req.mediaTypes.native; + let resNative = matchedResponse.native; + + // check title + let title = reqNativeLayout.title; + if (title && title.required) { + if (typeof resNative.title !== 'string') { + return; + } else if (title.len && title.len < resNative.title.length) { + return; + } + } + + // check body + let body = reqNativeLayout.body; + if (body && body.required) { + if (typeof resNative.body !== 'string') { + return; + } + } + + // check image + let image = reqNativeLayout.image; + if (image && image.required) { + if (resNative.image) { + if (typeof resNative.image.url !== 'string') { // check image url + return; + } else { + if (resNative.image.width !== image.sizes[0] || resNative.image.height !== image.sizes[1]) { // check image sizes + return; + } + } + } else { + return; + } + } + + // check sponsoredBy + let sponsoredBy = reqNativeLayout.sponsoredBy; + if (sponsoredBy && sponsoredBy.required) { + if (typeof resNative.sponsoredBy !== 'string') { + return; + } + } + + // check icon + let icon = reqNativeLayout.icon; + if (icon && icon.required) { + if (resNative.icon) { + if (typeof resNative.icon.url !== 'string') { // check icon url + return; + } else { + if (resNative.icon.width !== icon.sizes[0] || resNative.icon.height !== icon.sizes[0]) { // check image sizes + return; + } + } + } else { + return; + } + } + + // check clickUrl + if (typeof resNative.clickUrl !== 'string') { + return; + } + + // check clickTracker + let clickTrackers = resNative.clickTrackers; + if (clickTrackers) { + if (clickTrackers.length === 0) { + return; + } + } else { + return; + } + + // check impressionTrackers + let impressionTrackers = resNative.impressionTrackers; + if (impressionTrackers) { + if (impressionTrackers.length === 0) { + return; + } + } else { + return; + } + + bidResponse.native = matchedResponse.native; + + break; + + default: // response mediaType is not supported + return; + } + + bidResponses.push(bidResponse); + } + }); + + return bidResponses; + } +}; + +function getTopWindowReferrer() { + try { + return window.top.document.referrer; + } catch (e) { + return ''; + } +} + +registerBidder(spec); diff --git a/modules/bridgewellBidAdapter.md b/modules/bridgewellBidAdapter.md index 014be62ccef..6bcab4b8820 100644 --- a/modules/bridgewellBidAdapter.md +++ b/modules/bridgewellBidAdapter.md @@ -1,8 +1,8 @@ # Overview -Module Name: Bridgewell Bidder Adapter -Module Type: Bidder Adapter -Maintainer: kuchunchou@bridgewell.com +Module Name: Bridgewell Bidder Adapter +Module Type: Bidder Adapter +Maintainer: scupio@bridgewell.com # Description @@ -12,34 +12,15 @@ Module that connects to Bridgewell demand source to fetch bids. ``` var adUnits = [{ code: 'test-div', - sizes: [ - [300, 250] - ], - bids: [{ - bidder: 'bridgewell', - params: { - ChannelID: 'CgUxMjMzOBIBNiIFcGVubnkqCQisAhD6ARoBOQ' - } - }] - }, { - code: 'test-div', - sizes: [ - [728, 90] - ], - bids: [{ - bidder: 'bridgewell', - params: { - ChannelID: 'CgUxMjMzOBIBNiIGcGVubnkzKggI2AUQWhoBOQ', - cpmWeight: 1.5 + mediaTypes: { + banner: { + sizes: [300, 250] } - }] - }, { - code: 'test-div', - sizes: [728, 90], + }, bids: [{ bidder: 'bridgewell', params: { - ChannelID: 'CgUxMjMzOBIBNiIGcGVubnkzKggI2AUQWhoBOQ' + ChannelID: 'CgUxMjMzOBIBNiIFcGVubnkqCQisAhD6ARoBOQ' } }] }, { diff --git a/modules/brightcomBidAdapter.js b/modules/brightcomBidAdapter.js index 862933d076b..a4b013a2fe2 100644 --- a/modules/brightcomBidAdapter.js +++ b/modules/brightcomBidAdapter.js @@ -1,8 +1,7 @@ -import * as utils from '../src/utils'; -import * as url from '../src/url'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER } from '../src/mediaTypes'; -import { config } from '../src/config'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'brightcom'; const URL = 'https://brightcombid.marphezis.com/hb'; @@ -57,7 +56,7 @@ function buildRequests(bidReqs, bidderRequest) { id: utils.getUniqueIdentifierStr(), imp: brightcomImps, site: { - domain: url.parse(referrer).host, + domain: utils.parseUrl(referrer).host, page: referrer, publisher: { id: publisherId diff --git a/modules/britepoolIdSystem.js b/modules/britepoolIdSystem.js index ecea6bd3686..17a39e96aad 100644 --- a/modules/britepoolIdSystem.js +++ b/modules/britepoolIdSystem.js @@ -5,9 +5,9 @@ * @requires module:modules/userId */ -import * as utils from '../src/utils' -import {ajax} from '../src/ajax'; -import {submodule} from '../src/hook'; +import * as utils from '../src/utils.js' +import {ajax} from '../src/ajax.js'; +import {submodule} from '../src/hook.js'; /** @type {Submodule} */ export const britepoolIdSubmodule = { diff --git a/modules/browsiRtdProvider.js b/modules/browsiRtdProvider.js index a288869215b..9317786fb8d 100644 --- a/modules/browsiRtdProvider.js +++ b/modules/browsiRtdProvider.js @@ -13,17 +13,24 @@ * @property {string} pubKey * @property {string} url * @property {?string} keyName - * @property {number} auctionDelay + * @property {?number} auctionDelay + * @property {?number} timeout */ import {config} from '../src/config.js'; -import * as utils from '../src/utils'; -import {submodule} from '../src/hook'; -import {ajax} from '../src/ajax'; -import {loadExternalScript} from '../src/adloader'; +import * as utils from '../src/utils.js'; +import {submodule} from '../src/hook.js'; +import {ajaxBuilder} from '../src/ajax.js'; +import {loadExternalScript} from '../src/adloader.js'; +import { getStorageManager } from '../src/storageManager.js'; +import find from 'core-js-pure/features/array/find.js'; + +const storage = getStorageManager(); /** @type {string} */ const MODULE_NAME = 'realTimeData'; +/** @type {number} */ +const DEF_TIMEOUT = 1000; /** @type {ModuleParams} */ let _moduleParams = {}; /** @type {null|Object} */ @@ -33,14 +40,20 @@ let _dataReadyCallback = null; /** * add browsi script to page - * @param {string} bptUrl + * @param {Object} data */ -export function addBrowsiTag(bptUrl) { - let script = loadExternalScript(bptUrl, 'browsi'); +export function addBrowsiTag(data) { + let script = loadExternalScript(data.u, 'browsi'); + script.async = true; script.setAttribute('data-sitekey', _moduleParams.siteKey); script.setAttribute('data-pubkey', _moduleParams.pubKey); script.setAttribute('prebidbpt', 'true'); script.setAttribute('id', 'browsi-tag'); + script.setAttribute('src', data.u); + script.prebidData = utils.deepClone(data); + if (_moduleParams.keyName) { + script.prebidData.kn = _moduleParams.keyName; + } return script; } @@ -53,7 +66,7 @@ function collectData() { const doc = win.document; let browsiData = null; try { - browsiData = utils.getDataFromLocalStorage('__brtd'); + browsiData = storage.getDataFromLocalStorage('__brtd'); } catch (e) { utils.logError('unable to parse __brtd'); } @@ -63,7 +76,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} : {}), @@ -108,18 +121,16 @@ function sendDataToModule(adUnits, onDone) { if (!_predictions || !Object.keys(_predictions).length) { return onDone({}); } - const slots = getAllSlots(); - if (!slots) { - return onDone({}); - } let dataToReturn = adUnits.reduce((rp, cau) => { const adUnitCode = cau && cau.code; if (!adUnitCode) { return rp } - const predictionData = _predictions[adUnitCode]; + const adSlot = getSlotByCode(adUnitCode); + const identifier = adSlot ? getMacroId(_predictionsData.pmd, adSlot) : adUnitCode; + const predictionData = _predictions[identifier]; if (!predictionData) { return rp } if (predictionData.p) { - if (!isIdMatchingAdUnit(adUnitCode, slots, predictionData.w)) { + if (!isIdMatchingAdUnit(adSlot, predictionData.w)) { return rp; } rp[adUnitCode] = getKVObject(predictionData.p, _predictionsData.kn); @@ -138,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 @@ -154,25 +165,74 @@ function getKVObject(p, keyName) { } /** * check if placement id matches one of given ad units - * @param {number} id placement id - * @param {Object[]} allSlots google slots on page + * @param {Object} slot google slot * @param {string[]} whitelist ad units * @return {boolean} */ -export function isIdMatchingAdUnit(id, allSlots, whitelist) { - if (!whitelist || !whitelist.length) { +export function isIdMatchingAdUnit(slot, whitelist) { + if (!whitelist || !whitelist.length || !slot) { return true; } - const slot = allSlots.filter(s => s.getSlotElementId() === id); - const slotAdUnits = slot.map(s => s.getAdUnitPath()); - return slotAdUnits.some(a => whitelist.indexOf(a) !== -1); + const slotAdUnits = slot.getAdUnitPath(); + return whitelist.indexOf(slotAdUnits) !== -1; +} + +/** + * get GPT slot by placement id + * @param {string} code placement id + * @return {?Object} + */ +function getSlotByCode(code) { + const slots = getAllSlots(); + if (!slots || !slots.length) { + return null; + } + return find(slots, s => s.getSlotElementId() === code || s.getAdUnitPath() === code) || null; +} + +/** + * generate id according to macro script + * @param {Object} macro replacement macro + * @param {Object} slot google slot + * @return {?Object} + */ +export function getMacroId(macro, slot) { + if (macro) { + try { + const macroResult = evaluate(macro, slot.getSlotElementId(), slot.getAdUnitPath(), (match, p1) => { + return (p1 && slot.getTargeting(p1).join('_')) || 'NA'; + }); + return macroResult; + } catch (e) { + utils.logError(`failed to evaluate: ${macro}`); + } + } + return slot.getSlotElementId(); } +function evaluate(macro, divId, adUnit, replacer) { + let macroResult = macro.p + .replace(/['"]+/g, '') + .replace(//g, divId); + + if (adUnit) { + macroResult = macroResult.replace(//g, adUnit); + } + if (replacer) { + macroResult = macroResult.replace(//g, replacer); + } + if (macro.s) { + macroResult = macroResult.substring(macro.s.s, macro.s.e); + } + return macroResult; +} /** * XMLHttpRequest to get data form browsi server * @param {string} url server url with query params */ function getPredictionsFromServer(url) { + let ajax = ajaxBuilder(_moduleParams.auctionDelay || _moduleParams.timeout || DEF_TIMEOUT); + ajax(url, { success: function (response, req) { @@ -180,11 +240,11 @@ function getPredictionsFromServer(url) { try { const data = JSON.parse(response); if (data && data.p && data.kn) { - setData({p: data.p, kn: data.kn}); + setData({p: data.p, kn: data.kn, pmd: data.pmd}); } else { setData({}); } - addBrowsiTag(data.u); + addBrowsiTag(data); } catch (err) { utils.logError('unable to parse data'); setData({}) @@ -235,6 +295,7 @@ export function init(config) { _moduleParams = realTimeData.dataProviders && realTimeData.dataProviders.filter( pr => pr.name && pr.name.toLowerCase() === 'browsi')[0].params; _moduleParams.auctionDelay = realTimeData.auctionDelay; + _moduleParams.timeout = realTimeData.timeout; } catch (e) { _moduleParams = {}; } diff --git a/modules/bucksenseBidAdapter.js b/modules/bucksenseBidAdapter.js index 12a9e287f38..3f327e62121 100644 --- a/modules/bucksenseBidAdapter.js +++ b/modules/bucksenseBidAdapter.js @@ -1,10 +1,10 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER } from '../src/mediaTypes'; -import * as utils from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; const WHO = 'BKSHBID-005'; const BIDDER_CODE = 'bucksense'; -const URL = 'https://prebid.bksn.se:445/prebidjs/'; +const URL = 'https://prebid.bksn.se/prebidjs/'; export const spec = { code: BIDDER_CODE, diff --git a/modules/buzzoolaBidAdapter.js b/modules/buzzoolaBidAdapter.js index da2a3b30c2e..f87607657c3 100644 --- a/modules/buzzoolaBidAdapter.js +++ b/modules/buzzoolaBidAdapter.js @@ -1,8 +1,8 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER, VIDEO} from '../src/mediaTypes'; -import {Renderer} from '../src/Renderer'; -import {OUTSTREAM} from '../src/video'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {Renderer} from '../src/Renderer.js'; +import {OUTSTREAM} from '../src/video.js'; const BIDDER_CODE = 'buzzoola'; const ENDPOINT = 'https://exchange.buzzoola.com/ssp/prebidjs'; diff --git a/modules/byplayBidAdapter.js b/modules/byplayBidAdapter.js new file mode 100644 index 00000000000..6133cdfa647 --- /dev/null +++ b/modules/byplayBidAdapter.js @@ -0,0 +1,67 @@ +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; +import { VIDEO } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'byplay'; +const ENDPOINT_URL = 'https://prebid.byplay.net/bidder'; +const VIDEO_PLAYER_URL = 'https://cdn.byplay.net/prebid-byplay-v2.js'; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [VIDEO], + isBidRequestValid: (bid) => { + return !!bid.params.sectionId; + }, + buildRequests: function(validBidRequests) { + return validBidRequests.map(req => { + const payload = { + requestId: req.bidId, + sectionId: req.params.sectionId, + ...(req.params.env ? { env: req.params.env } : {}) + }; + + return { + method: 'POST', + url: ENDPOINT_URL, + data: JSON.stringify(payload), + options: { + withCredentials: false + } + }; + }); + }, + interpretResponse: (serverResponse, bidderRequest) => { + const response = serverResponse.body; + const data = JSON.parse(bidderRequest.data); + const bidResponse = { + requestId: data.requestId, + cpm: response.cpm, + width: response.width, + height: response.height, + creativeId: response.creativeId || '0', + ttl: config.getConfig('_bidderTimeout'), + currency: 'JPY', + netRevenue: response.netRevenue, + mediaType: VIDEO, + vastXml: response.vastXml, + renderer: createRenderer() + }; + + return [bidResponse]; + } +}; + +function createRenderer() { + const renderer = Renderer.install({ url: VIDEO_PLAYER_URL }); + + renderer.setRender(bid => { + bid.renderer.push(() => { + window.adtagRender(bid); + }); + }); + + return renderer; +} + +registerBidder(spec); diff --git a/modules/byplayBidAdapter.md b/modules/byplayBidAdapter.md new file mode 100644 index 00000000000..67fb9c40d35 --- /dev/null +++ b/modules/byplayBidAdapter.md @@ -0,0 +1,37 @@ +# Overview + +``` +Module Name: ByPlay Bidder Adapter +Module Type: Bidder Adapter +Maintainer: byplayers@tsumikiinc.com +``` + +# Description + +Connects to ByPlay exchange for bids. + +ByPlay bid adapter supports Video. + +# Test Parameters +``` + const adUnits = [ + { + code: 'byplay-ad', + mediaTypes: { + video: { + playerSize: [400, 225], + context: 'outstream' + } + }, + bids: [ + { + bidder: 'byplay', + params: { + sectionId: '7986', + env: 'dev' + } + } + ] + } + ]; +``` diff --git a/modules/c1xBidAdapter.js b/modules/c1xBidAdapter.js index 9364ef2256a..8e1f1487ba7 100644 --- a/modules/c1xBidAdapter.js +++ b/modules/c1xBidAdapter.js @@ -1,6 +1,6 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import * as utils from '../src/utils'; -import { userSync } from '../src/userSync'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; +import { userSync } from '../src/userSync.js'; const BIDDER_CODE = 'c1x'; const URL = 'https://ht.c1exchange.com/ht'; diff --git a/modules/categoryTranslation.js b/modules/categoryTranslation.js index 091b16c8211..9a9289fcd73 100644 --- a/modules/categoryTranslation.js +++ b/modules/categoryTranslation.js @@ -11,12 +11,14 @@ * If publisher has not defined translation file than prebid will use default prebid translation file provided here //cdn.jsdelivr.net/gh/prebid/category-mapping-file@1/freewheel-mapping.json */ -import { config } from '../src/config'; -import { setupBeforeHookFnOnce, hook } from '../src/hook'; -import { ajax } from '../src/ajax'; -import { timestamp, logError, setDataInLocalStorage, getDataFromLocalStorage } from '../src/utils'; -import { addBidResponse } from '../src/auction'; +import { config } from '../src/config.js'; +import { setupBeforeHookFnOnce, hook } from '../src/hook.js'; +import { ajax } from '../src/ajax.js'; +import { timestamp, logError } from '../src/utils.js'; +import { addBidResponse } from '../src/auction.js'; +import { getCoreStorageManager } from '../src/storageManager.js'; +export const storage = getCoreStorageManager('categoryTranslation'); const DEFAULT_TRANSLATION_FILE_URL = 'https://cdn.jsdelivr.net/gh/prebid/category-mapping-file@1/freewheel-mapping.json'; const DEFAULT_IAB_TO_FW_MAPPING_KEY = 'iabToFwMappingkey'; const DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB = 'iabToFwMappingkeyPub'; @@ -43,15 +45,15 @@ export function getAdserverCategoryHook(fn, adUnitCode, bid) { let localStorageKey = (config.getConfig('brandCategoryTranslation.translationFile')) ? DEFAULT_IAB_TO_FW_MAPPING_KEY_PUB : DEFAULT_IAB_TO_FW_MAPPING_KEY; if (bid.meta && !bid.meta.adServerCatId) { - let mapping = getDataFromLocalStorage(localStorageKey); + let mapping = storage.getDataFromLocalStorage(localStorageKey); if (mapping) { try { mapping = JSON.parse(mapping); } catch (error) { logError('Failed to parse translation mapping file'); } - if (bid.meta.iabSubCatId && mapping['mapping'] && mapping['mapping'][bid.meta.iabSubCatId]) { - bid.meta.adServerCatId = mapping['mapping'][bid.meta.iabSubCatId]['id']; + if (bid.meta.primaryCatId && mapping['mapping'] && mapping['mapping'][bid.meta.primaryCatId]) { + bid.meta.adServerCatId = mapping['mapping'][bid.meta.primaryCatId]['id']; } else { // This bid will be automatically ignored by adpod module as adServerCatId was not found bid.meta.adServerCatId = undefined; @@ -65,24 +67,29 @@ export function getAdserverCategoryHook(fn, adUnitCode, bid) { export function initTranslation(url, localStorageKey) { setupBeforeHookFnOnce(addBidResponse, getAdserverCategoryHook, 50); - let mappingData = getDataFromLocalStorage(localStorageKey); - if (!mappingData || timestamp() < mappingData.lastUpdated + refreshInDays * 24 * 60 * 60 * 1000) { - ajax(url, - { - success: (response) => { - try { - response = JSON.parse(response); - response['lastUpdated'] = timestamp(); - setDataInLocalStorage(localStorageKey, JSON.stringify(response)); - } catch (error) { - logError('Failed to parse translation mapping file'); + let mappingData = storage.getDataFromLocalStorage(localStorageKey); + try { + mappingData = mappingData ? JSON.parse(mappingData) : undefined; + if (!mappingData || timestamp() > mappingData.lastUpdated + refreshInDays * 24 * 60 * 60 * 1000) { + ajax(url, + { + success: (response) => { + try { + response = JSON.parse(response); + response['lastUpdated'] = timestamp(); + storage.setDataInLocalStorage(localStorageKey, JSON.stringify(response)); + } catch (error) { + logError('Failed to parse translation mapping file'); + } + }, + error: () => { + logError('Failed to load brand category translation file.') } }, - error: () => { - logError('Failed to load brand category translation file.') - } - }, - ); + ); + } + } catch (error) { + logError('Failed to parse translation mapping file'); } } diff --git a/modules/ccxBidAdapter.js b/modules/ccxBidAdapter.js index 90eb7e7ed9f..ee15d6bb3ec 100644 --- a/modules/ccxBidAdapter.js +++ b/modules/ccxBidAdapter.js @@ -1,6 +1,9 @@ -import * as utils from '../src/utils' -import { registerBidder } from '../src/adapters/bidderFactory' -import { config } from '../src/config' +import * as utils from '../src/utils.js' +import { registerBidder } from '../src/adapters/bidderFactory.js' +import { config } from '../src/config.js' +import { getStorageManager } from '../src/storageManager.js'; + +const storage = getStorageManager(); const BIDDER_CODE = 'ccx' const BID_URL = 'https://delivery.clickonometrics.pl/ortb/prebid/bid' const SUPPORTED_VIDEO_PROTOCOLS = [2, 3, 5, 6] @@ -170,7 +173,7 @@ export const spec = { requestBody.site = _getSiteObj(bidderRequest) requestBody.device = _getDeviceObj() requestBody.id = bidderRequest.bids[0].auctionId - requestBody.ext = {'ce': (utils.cookiesAreEnabled() ? 1 : 0)} + requestBody.ext = {'ce': (storage.cookiesAreEnabled() ? 1 : 0)} // Attaching GDPR Consent Params if (bidderRequest && bidderRequest.gdprConsent) { diff --git a/modules/cedatoBidAdapter.js b/modules/cedatoBidAdapter.js index 7d2edecd3b5..ab381698f01 100644 --- a/modules/cedatoBidAdapter.js +++ b/modules/cedatoBidAdapter.js @@ -1,13 +1,15 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const storage = getStorageManager(); const BIDDER_CODE = 'cedato'; const BID_URL = 'https://h.cedatoplayer.com/hb'; const SYNC_URL = 'https://h.cedatoplayer.com/hb_usync'; const TTL = 10000; const CURRENCY = 'USD'; -const FIRST_PRICE = 1; const NET_REVENUE = true; export const spec = { @@ -20,16 +22,13 @@ export const spec = { bid.params && bid.params.player_id && utils.checkCookieSupport() && - utils.cookiesAreEnabled() + storage.cookiesAreEnabled() ); }, buildRequests: function(bidRequests, bidderRequest) { - const req = bidRequests[Math.floor(Math.random() * bidRequests.length)]; - const params = req.params; - const at = FIRST_PRICE; - const site = { id: params.player_id, domain: document.domain }; - const device = { ua: navigator.userAgent }; + const site = { domain: document.domain }; + const device = { ua: navigator.userAgent, w: screen.width, h: screen.height }; const currency = CURRENCY; const tmax = bidderRequest.timeout; const auctionId = bidderRequest.auctionId; @@ -39,7 +38,7 @@ export const spec = { const imp = bidRequests.map(req => { const banner = getMediaType(req, 'banner'); const video = getMediaType(req, 'video'); - const bidfloor = params.bidfloor; + const params = req.params; const bidId = req.bidId; const adUnitCode = req.adUnitCode; const bidRequestsCount = req.bidRequestsCount; @@ -51,16 +50,15 @@ export const spec = { banner, video, adUnitCode, - bidfloor, bidRequestsCount, bidderWinsCount, - transactionId + transactionId, + params }; }); const payload = { version: '$prebid.version$', - at, site, device, imp, @@ -83,12 +81,7 @@ export const spec = { } } - return { - method: 'POST', - url: params.bid_url || BID_URL, - data: JSON.stringify(payload), - bidderRequest - }; + return formatRequest(payload, bidderRequest); }, interpretResponse: function(resp, {bidderRequest}) { @@ -186,6 +179,33 @@ function newBid(serverBid, bidderRequest) { return bid; } +function formatRequest(payload, bidderRequest) { + const payloadByUrl = {}; + const requests = []; + + payload.imp.forEach(imp => { + const url = imp.params.bid_url || BID_URL; + if (!payloadByUrl[url]) { + payloadByUrl[url] = { + ...payload, + imp: [] + }; + } + payloadByUrl[url].imp.push(imp); + }); + + for (const url in payloadByUrl) { + requests.push({ + url, + method: 'POST', + data: JSON.stringify(payloadByUrl[url]), + bidderRequest + }); + } + + return requests; +} + const getSync = (type, gdprConsent, uspConsent = '') => { const syncUrl = SYNC_URL; let params = '?type=' + type + '&us_privacy=' + uspConsent; diff --git a/modules/cleanmedianetBidAdapter.js b/modules/cleanmedianetBidAdapter.js index 97452e987bc..a8f37450d68 100644 --- a/modules/cleanmedianetBidAdapter.js +++ b/modules/cleanmedianetBidAdapter.js @@ -1,8 +1,8 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {config} from '../src/config'; -import {Renderer} from '../src/Renderer'; -import {BANNER, VIDEO} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; +import {Renderer} from '../src/Renderer.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; export const helper = { getTopWindowDomain: function (url) { diff --git a/modules/clickforceBidAdapter.js b/modules/clickforceBidAdapter.js index 43ef76cc931..20408fe9177 100644 --- a/modules/clickforceBidAdapter.js +++ b/modules/clickforceBidAdapter.js @@ -1,8 +1,8 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER, NATIVE} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, NATIVE} from '../src/mediaTypes.js'; const BIDDER_CODE = 'clickforce'; -const ENDPOINT_URL = 'https://ad.doublemax.net/adserver/prebid.json?cb=' + new Date().getTime() + '&hb=1&ver=1.21'; +const ENDPOINT_URL = 'https://ad.holmesmind.com/adserver/prebid.json?cb=' + new Date().getTime() + '&hb=1&ver=1.21'; export const spec = { code: BIDDER_CODE, @@ -112,12 +112,12 @@ export const spec = { if (syncOptions.iframeEnabled) { return [{ type: 'iframe', - url: 'https://cdn.doublemax.net/js/capmapping.htm' + url: 'https://cdn.holmesmind.com/js/capmapping.htm' }] } else if (syncOptions.pixelEnabled) { return [{ type: 'image', - url: 'https://c.doublemax.net/cm' + url: 'https://c.holmesmind.com/cm' }] } } diff --git a/modules/clicktripzBidAdapter.js b/modules/clicktripzBidAdapter.js new file mode 100644 index 00000000000..2149cbe4527 --- /dev/null +++ b/modules/clicktripzBidAdapter.js @@ -0,0 +1,67 @@ +import {logError, _each} from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'clicktripz'; +const ENDPOINT_URL = 'https://www.clicktripz.com/x/prebid/v1'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['ctz'], // short code + + isBidRequestValid: function (bid) { + if (bid && bid.params && bid.params.placementId && bid.params.siteId) { + return true; + } + + return false; + }, + + buildRequests: function (validBidRequests) { + let bidRequests = []; + + _each(validBidRequests, function (bid) { + bidRequests.push({ + bidId: bid.bidId, + placementId: bid.params.placementId, + siteId: bid.params.siteId, + sizes: bid.sizes.map(function (size) { + return size.join('x') + }) + }); + }); + return { + method: 'POST', + url: ENDPOINT_URL, + data: bidRequests + }; + }, + + interpretResponse: function (serverResponse) { + let bidResponses = []; + + if (serverResponse && serverResponse.body) { + _each(serverResponse.body, function (bid) { + if (bid.errors) { + logError(bid.errors); + return; + } + + const size = bid.size.split('x'); + bidResponses.push({ + requestId: bid.bidId, + cpm: bid.cpm, + width: size[0], + height: size[1], + creativeId: bid.creativeId, + currency: bid.currency, + netRevenue: bid.netRevenue, + ttl: bid.ttl, + adUrl: bid.adUrl + }); + }); + } + return bidResponses; + } +}; + +registerBidder(spec); diff --git a/modules/clicktripzBidAdapter.md b/modules/clicktripzBidAdapter.md new file mode 100644 index 00000000000..1de1e26f37a --- /dev/null +++ b/modules/clicktripzBidAdapter.md @@ -0,0 +1,35 @@ +# Overview + +``` +Module Name: Clicktripz Bidder Adapter +Module Type: Bidder Adapter +Maintainer: integration-support@clicktripz.com +``` + +# Description +Our module makes it easy to integrate Clicktripz demand sources into your website. + +Supported Ad Fortmats: +* Banner + +# Test Parameters +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]], + } + }, + bids: [ + { + bidder: "clicktripz", + params: { + placementId: '4312c63f', + siteId: 'prebid', + } + } + ] + } + ]; diff --git a/modules/coinzillaBidAdapter.js b/modules/coinzillaBidAdapter.js index 26ea7bb71e1..240a3f1fcde 100644 --- a/modules/coinzillaBidAdapter.js +++ b/modules/coinzillaBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import {config} from '../src/config'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'coinzilla'; const ENDPOINT_URL = 'https://request.czilladx.com/serve/request.php'; diff --git a/modules/collectcentBidAdapter.js b/modules/collectcentBidAdapter.js index f7f5f3ef0c4..add3e06430d 100644 --- a/modules/collectcentBidAdapter.js +++ b/modules/collectcentBidAdapter.js @@ -1,6 +1,6 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; -import * as utils from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; const BIDDER_CODE = 'collectcent'; const URL_MULTI = 'https://publishers.motionspots.com/?c=o&m=multi'; diff --git a/modules/colombiaBidAdapter.js b/modules/colombiaBidAdapter.js new file mode 100644 index 00000000000..55109dbaab2 --- /dev/null +++ b/modules/colombiaBidAdapter.js @@ -0,0 +1,82 @@ +import * as utils from '../src/utils.js'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +const BIDDER_CODE = 'colombia'; +const ENDPOINT_URL = 'https://ade.clmbtech.com/cde/prebid.htm'; +const HOST_NAME = document.location.protocol + '//' + window.location.host; + +export const spec = { + code: BIDDER_CODE, + aliases: ['clmb'], + supportedMediaTypes: [BANNER], + isBidRequestValid: function(bid) { + return !!(bid.params.placementId); + }, + buildRequests: function(validBidRequests, bidderRequest) { + return validBidRequests.map(bidRequest => { + const params = bidRequest.params; + const sizes = utils.parseSizesInput(bidRequest.sizes)[0]; + const width = sizes.split('x')[0]; + const height = sizes.split('x')[1]; + const placementId = params.placementId; + const cb = Math.floor(Math.random() * 99999999999); + const bidId = bidRequest.bidId; + const referrer = (bidderRequest && bidderRequest.refererInfo) ? bidderRequest.refererInfo.referer : ''; + const payload = { + v: 'hb1', + p: placementId, + w: width, + h: height, + cb: cb, + r: referrer, + uid: bidId, + t: 'i', + d: HOST_NAME, + }; + return { + method: 'POST', + url: ENDPOINT_URL, + data: payload, + } + }); + }, + interpretResponse: function(serverResponse, bidRequest) { + const bidResponses = []; + const response = serverResponse.body; + const crid = response.creativeId || 0; + const width = response.width || 0; + const height = response.height || 0; + let cpm = response.cpm || 0; + if (width == 300 && height == 250) { + cpm = cpm * 0.2; + } + if (width == 320 && height == 50) { + cpm = cpm * 0.55; + } + if (cpm <= 0) { + return bidResponses; + } + if (width !== 0 && height !== 0 && cpm !== 0 && crid !== 0) { + const dealId = response.dealid || ''; + const currency = response.currency || 'USD'; + const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue; + const bidResponse = { + requestId: bidRequest.data.uid, + cpm: cpm, + width: response.width, + height: response.height, + creativeId: crid, + dealId: dealId, + currency: currency, + netRevenue: netRevenue, + ttl: config.getConfig('_bidderTimeout'), + referrer: bidRequest.data.r, + ad: response.ad + }; + bidResponses.push(bidResponse); + } + return bidResponses; + } +} +registerBidder(spec); diff --git a/modules/colombiaBidAdapter.md b/modules/colombiaBidAdapter.md index 2131fcb4c5a..c754e49771d 100644 --- a/modules/colombiaBidAdapter.md +++ b/modules/colombiaBidAdapter.md @@ -10,13 +10,17 @@ Maintainer: colombiaonline@timesinteret.in Connect to COLOMBIA for bids. -THE COLOMBIA adapter requires setup and approval from the COLOMBIA team. Please reach out to your account team or colombiaonline@timesinteret.in for more information. +COLOMBIA adapter requires setup and approval from the COLOMBIA team. Please reach out to your account team or colombiaonline@timesinteret.in for more information. # Test Parameters ``` var adUnits = [{ code: 'test-ad-div', - sizes: [[300, 250]], + mediaTypes: { + banner: { + sizes: [[300, 250],[728,90],[320,50]] + } + }, bids: [{ bidder: 'colombia', params: { diff --git a/modules/colossussspBidAdapter.js b/modules/colossussspBidAdapter.js index adcd5df9fb6..baa60a76a0d 100644 --- a/modules/colossussspBidAdapter.js +++ b/modules/colossussspBidAdapter.js @@ -1,6 +1,6 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; -import * as utils from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; const BIDDER_CODE = 'colossusssp'; const G_URL = 'https://colossusssp.com/?c=o&m=multi'; @@ -23,6 +23,19 @@ function isBidResponseValid(bid) { } } +function getUserId(eids, id, source, uidExt) { + if (id) { + var uid = { id }; + if (uidExt) { + uid.ext = uidExt; + } + eids.push({ + source, + uids: [ uid ] + }); + } +} + export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO, NATIVE], @@ -60,13 +73,17 @@ export const spec = { 'secure': location.protocol === 'https:' ? 1 : 0, 'host': location.host, 'page': location.pathname, - 'placements': placements + 'placements': placements, }; if (bidderRequest) { if (bidderRequest.uspConsent) { request.ccpa = bidderRequest.uspConsent; } + if (bidderRequest.gdprConsent) { + request.gdpr_consent = bidderRequest.gdprConsent.consentString || 'ALL' + request.gdpr_require = bidderRequest.gdprConsent.gdprApplies ? 1 : 0 + } } for (let i = 0; i < validBidRequests.length; i++) { @@ -76,11 +93,20 @@ export const spec = { placementId: bid.params.placement_id, bidId: bid.bidId, sizes: bid.mediaTypes[traff].sizes, - traffic: traff + traffic: traff, + eids: [] }; if (bid.schain) { placement.schain = bid.schain; } + if (bid.userId) { + getUserId(placement.eids, bid.userId.britepoolid, 'britepool.com'); + getUserId(placement.eids, bid.userId.idl_env, 'identityLink'); + getUserId(placement.eids, bid.userId.id5id, 'id5-sync.com') + getUserId(placement.eids, bid.userId.tdid, 'adserver.org', { + rtiPartner: 'TDID' + }); + } placements.push(placement); } return { diff --git a/modules/connectadBidAdapter.js b/modules/connectadBidAdapter.js new file mode 100644 index 00000000000..3dcb8da9838 --- /dev/null +++ b/modules/connectadBidAdapter.js @@ -0,0 +1,299 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js' +import {config} from '../src/config.js'; + +const BIDDER_CODE = 'connectad'; +const BIDDER_CODE_ALIAS = 'connectadrealtime'; +const ENDPOINT_URL = 'https://i.connectad.io/api/v2'; +const SUPPORTED_MEDIA_TYPES = [BANNER]; + +export const spec = { + code: BIDDER_CODE, + aliases: [ BIDDER_CODE_ALIAS ], + supportedMediaTypes: SUPPORTED_MEDIA_TYPES, + + isBidRequestValid: function(bid) { + return !!(bid.params.networkId && bid.params.siteId); + }, + + buildRequests: function(validBidRequests, bidderRequest) { + let digitrust; + + let ret = { + method: 'POST', + url: '', + data: '', + bidRequest: [] + }; + + if (validBidRequests.length < 1) { + return ret; + } + + const data = Object.assign({ + placements: [], + time: Date.now(), + user: {}, + url: (bidderRequest.refererInfo && bidderRequest.refererInfo.referer) ? bidderRequest.refererInfo.referer : window.location.href, + referrer: window.document.referrer, + referrer_info: bidderRequest.refererInfo, + screensize: getScreenSize(), + dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0, + language: navigator.language, + ua: navigator.userAgent + }); + + // coppa compliance + if (config.getConfig('coppa') === true) { + utils.deepSetValue(data, 'user.coppa', 1); + } + + // adding schain object + if (validBidRequests[0].schain) { + utils.deepSetValue(data, 'source.ext.schain', validBidRequests[0].schain); + } + + // Attaching GDPR Consent Params + if (bidderRequest.gdprConsent) { + let gdprApplies; + if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { + gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; + } + utils.deepSetValue(data, 'user.ext.gdpr', gdprApplies); + utils.deepSetValue(data, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + } + + // CCPA + if (bidderRequest.uspConsent) { + utils.deepSetValue(data, 'user.ext.us_privacy', bidderRequest.uspConsent); + } + + // Digitrust Support + const bidRequestDigitrust = utils.deepAccess(validBidRequests[0], 'userId.digitrustid.data'); + if (bidRequestDigitrust && (!bidRequestDigitrust.privacy || !bidRequestDigitrust.privacy.optout)) { + digitrust = { + id: bidRequestDigitrust.id, + keyv: bidRequestDigitrust.keyv + } + } + + if (digitrust) { + utils.deepSetValue(data, 'user.ext.digitrust', { + id: digitrust.id, + keyv: digitrust.keyv + }) + } + + if (validBidRequests[0].userId && typeof validBidRequests[0].userId === 'object' && (validBidRequests[0].userId.tdid || validBidRequests[0].userId.pubcid || validBidRequests[0].userId.lipb || validBidRequests[0].userId.id5id || validBidRequests[0].userId.parrableid)) { + utils.deepSetValue(data, 'user.ext.eids', []); + + if (validBidRequests[0].userId.tdid) { + data.user.ext.eids.push({ + source: 'adserver.org', + uids: [{ + id: validBidRequests[0].userId.tdid, + ext: { + rtiPartner: 'TDID' + } + }] + }); + } + + if (validBidRequests[0].userId.pubcid) { + data.user.ext.eids.push({ + source: 'pubcommon', + uids: [{ + id: validBidRequests[0].userId.pubcid, + }] + }); + } + + if (validBidRequests[0].userId.id5id) { + data.user.ext.eids.push({ + source: 'id5-sync.com', + uids: [{ + id: validBidRequests[0].userId.id5id, + }] + }); + } + + if (validBidRequests[0].userId.parrableid) { + data.user.ext.eids.push({ + source: 'parrable.com', + uids: [{ + id: validBidRequests[0].userId.parrableid, + }] + }); + } + + if (validBidRequests[0].userId.lipb && validBidRequests[0].userId.lipb.lipbid) { + data.user.ext.eids.push({ + source: 'liveintent.com', + uids: [{ + id: validBidRequests[0].userId.lipb.lipbid + }] + }); + } + } + + validBidRequests.map(bid => { + const placement = Object.assign({ + id: bid.transactionId, + divName: bid.bidId, + sizes: bid.mediaTypes.banner.sizes, + adTypes: getSize(bid.mediaTypes.banner.sizes || bid.sizes) + }, bid.params); + + if (placement.networkId && placement.siteId) { + data.placements.push(placement); + } + }); + + ret.data = JSON.stringify(data); + ret.bidRequest = validBidRequests; + ret.url = ENDPOINT_URL; + + return ret; + }, + + interpretResponse: function(serverResponse, bidRequest, bidderRequest) { + let bid; + let bids; + let bidId; + let bidObj; + let bidResponses = []; + + bids = bidRequest.bidRequest; + + serverResponse = (serverResponse || {}).body; + for (let i = 0; i < bids.length; i++) { + bid = {}; + bidObj = bids[i]; + bidId = bidObj.bidId; + + if (serverResponse) { + const decision = serverResponse.decisions && serverResponse.decisions[bidId]; + const price = decision && decision.pricing && decision.pricing.clearPrice; + + if (decision && price) { + bid.requestId = bidId; + bid.cpm = price; + bid.width = decision.width; + bid.height = decision.height; + bid.dealid = decision.dealid || null; + bid.ad = retrieveAd(decision); + bid.currency = 'USD'; + bid.creativeId = decision.adId; + bid.ttl = 360; + bid.netRevenue = true; + bidResponses.push(bid); + } + } + } + + return bidResponses; + }, + + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { + let syncEndpoint = 'https://cdn.connectad.io/connectmyusers.php?'; + + if (gdprConsent) { + syncEndpoint = utils.tryAppendQueryString(syncEndpoint, 'gdpr', (gdprConsent.gdprApplies ? 1 : 0)); + } + + if (gdprConsent && typeof gdprConsent.consentString === 'string') { + syncEndpoint = utils.tryAppendQueryString(syncEndpoint, 'gdpr_consent', gdprConsent.consentString); + } + + if (uspConsent) { + syncEndpoint = utils.tryAppendQueryString(syncEndpoint, 'us_privacy', uspConsent); + } + + if (config.getConfig('coppa') === true) { + syncEndpoint = utils.tryAppendQueryString(syncEndpoint, 'coppa', 1); + } + + if (syncOptions.iframeEnabled) { + return [{ + type: 'iframe', + url: syncEndpoint + }]; + } else { + utils.logWarn('Bidder ConnectAd: Please activate iFrame Sync'); + } + } +}; + +const sizeMap = [ + null, + '120x90', + '200x200', + '468x60', + '728x90', + '300x250', + '160x600', + '120x600', + '300x100', + '180x150', + '336x280', + '240x400', + '234x60', + '88x31', + '120x60', + '120x240', + '125x125', + '220x250', + '250x250', + '250x90', + '0x0', + '200x90', + '300x50', + '320x50', + '320x480', + '185x185', + '620x45', + '300x125', + '800x250', + '980x120', + '980x150', + '320x150', + '300x300', + '200x600', + '320x500', + '320x320' +]; + +sizeMap[77] = '970x90'; +sizeMap[123] = '970x250'; +sizeMap[43] = '300x600'; +sizeMap[286] = '970x66'; +sizeMap[3230] = '970x280'; +sizeMap[429] = '486x60'; +sizeMap[374] = '700x500'; +sizeMap[934] = '300x1050'; +sizeMap[1578] = '320x100'; +sizeMap[331] = '320x250'; +sizeMap[3301] = '320x267'; +sizeMap[2730] = '728x250'; + +function getSize(sizes) { + const result = []; + sizes.forEach(function(size) { + const index = sizeMap.indexOf(size[0] + 'x' + size[1]); + if (index >= 0) { + result.push(index); + } + }); + return result; +} + +function retrieveAd(decision) { + return decision.contents && decision.contents[0] && decision.contents[0].body; +} + +function getScreenSize() { + return [window.screen.width, window.screen.height].join('x'); +} + +registerBidder(spec); diff --git a/modules/connectadBidAdapter.md b/modules/connectadBidAdapter.md new file mode 100644 index 00000000000..e63494e1add --- /dev/null +++ b/modules/connectadBidAdapter.md @@ -0,0 +1,46 @@ +# Overview + +``` +Module Name: ConnectAd PreBid Adapter +Module Type: Bidder Adapter +Maintainer: support@connectad.io +``` + +# Description + +ConnectAd bid adapter supports only Banner at present. Video and Mobile will follow Q2/2020 + +# Sample Ad Unit: For Publishers +``` +var adUnits = [ +{ + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]] + } + }, + bids: [{ + bidder: 'connectad', + params: { + siteId: 123456, + networkId: 123456, + bidfloor: 0.20 // Optional: Requested Bidfloor + } + }] +} + +# ## Configuration +ConnectAd recommends the UserSync configuration below otherwise we will not be able to performe user syncs. + +```javascript +pbjs.setConfig({ + userSync: { + filterSettings: { + iframe: { + bidders: ['connectad'], + filter: 'include' + } + } + } +}); \ No newline at end of file diff --git a/modules/consentManagement.js b/modules/consentManagement.js index d5703c1a784..53e97006bd1 100644 --- a/modules/consentManagement.js +++ b/modules/consentManagement.js @@ -4,11 +4,11 @@ * and make it available for any GDPR supported adapters to read/pass this information to * their system. */ -import * as utils from '../src/utils'; -import { config } from '../src/config'; -import { gdprDataHandler } from '../src/adapterManager'; -import includes from 'core-js/library/fn/array/includes'; -import strIncludes from 'core-js/library/fn/string/includes'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { gdprDataHandler } from '../src/adapterManager.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import strIncludes from 'core-js-pure/features/string/includes.js'; const DEFAULT_CMP = 'iab'; const DEFAULT_CONSENT_TIMEOUT = 10000; @@ -17,8 +17,10 @@ const DEFAULT_ALLOW_AUCTION_WO_CONSENT = true; export let userCMP; export let consentTimeout; export let allowAuction; +export let gdprScope; export let staticConsentData; +let cmpVersion = 0; let consentData; let addedConsentHook = false; @@ -47,11 +49,70 @@ function lookupStaticConsentData(cmpSuccess, cmpError, hookConfig) { * @param {object} hookConfig contains module related variables (see comment in requestBidsHook function) */ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { - function handleCmpResponseCallbacks() { + function findCMP() { + let f = window; + let cmpFrame; + let cmpFunction; + while (!cmpFrame) { + try { + if (typeof f.__tcfapi === 'function' || typeof f.__cmp === 'function') { + if (typeof f.__tcfapi === 'function') { + cmpVersion = 2; + cmpFunction = f.__tcfapi; + } else { + cmpVersion = 1; + cmpFunction = f.__cmp; + } + cmpFrame = f; + break; + } + } catch (e) { } + + // need separate try/catch blocks due to the exception errors thrown when trying to check for a frame that doesn't exist in 3rd party env + try { + if (f.frames['__tcfapiLocator']) { + cmpVersion = 2; + cmpFrame = f; + break; + } + } catch (e) { } + + try { + if (f.frames['__cmpLocator']) { + cmpVersion = 1; + cmpFrame = f; + break; + } + } catch (e) { } + + if (f === window.top) break; + f = f.parent; + } + return { + cmpFrame, + cmpFunction + }; + } + + function v2CmpResponseCallback(tcfData, success) { + utils.logInfo('Received a response from CMP', tcfData); + if (success) { + if (tcfData.eventStatus === 'tcloaded' || tcfData.eventStatus === 'useractioncomplete') { + cmpSuccess(tcfData, hookConfig); + } else if (tcfData.eventStatus === 'cmpuishown' && tcfData.tcString && tcfData.purposeOneTreatment === true) { + cmpSuccess(tcfData, hookConfig); + } + } else { + cmpError('CMP unable to register callback function. Please check CMP setup.', hookConfig); + } + } + + function handleV1CmpResponseCallbacks() { const cmpResponse = {}; function afterEach() { if (cmpResponse.getConsentData && cmpResponse.getVendorConsents) { + utils.logInfo('Received all requested responses from CMP', cmpResponse); cmpSuccess(cmpResponse, hookConfig); } } @@ -68,10 +129,13 @@ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { } } - let callbackHandler = handleCmpResponseCallbacks(); + let v1CallbackHandler = handleV1CmpResponseCallbacks(); let cmpCallbacks = {}; - let cmpFunction; + let { cmpFrame, cmpFunction } = findCMP(); + if (!cmpFrame) { + return cmpError('CMP not found.', hookConfig); + } // to collect the consent information from the user, we perform two calls to the CMP in parallel: // first to collect the user's consent choices represented in an encoded string (via getConsentData) // second to collect the user's full unparsed consent information (via getVendorConsents) @@ -81,34 +145,28 @@ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { // check to see if prebid is in a safeframe (with CMP support) // else assume prebid may be inside an iframe and use the IAB CMP locator code to see if CMP's located in a higher parent window. this works in cross domain iframes // if the CMP is not found, the iframe function will call the cmpError exit callback to abort the rest of the CMP workflow - try { - cmpFunction = window.__cmp || utils.getWindowTop().__cmp; - } catch (e) { } if (utils.isFn(cmpFunction)) { - cmpFunction('getConsentData', null, callbackHandler.consentDataCallback); - cmpFunction('getVendorConsents', null, callbackHandler.vendorConsentsCallback); - } else if (inASafeFrame() && typeof window.$sf.ext.cmp === 'function') { - callCmpWhileInSafeFrame('getConsentData', callbackHandler.consentDataCallback); - callCmpWhileInSafeFrame('getVendorConsents', callbackHandler.vendorConsentsCallback); - } else { - // find the CMP frame - let f = window; - let cmpFrame; - while (!cmpFrame) { - try { - if (f.frames['__cmpLocator']) cmpFrame = f; - } catch (e) { } - if (f === window.top) break; - f = f.parent; + utils.logInfo('Detected CMP API is directly accessible, calling it now...'); + if (cmpVersion === 1) { + cmpFunction('getConsentData', null, v1CallbackHandler.consentDataCallback); + cmpFunction('getVendorConsents', null, v1CallbackHandler.vendorConsentsCallback); + } else if (cmpVersion === 2) { + cmpFunction('addEventListener', cmpVersion, v2CmpResponseCallback); } - - if (!cmpFrame) { - return cmpError('CMP not found.', hookConfig); + } else if (cmpVersion === 1 && inASafeFrame() && typeof window.$sf.ext.cmp === 'function') { + // this safeframe workflow is only supported with TCF v1 spec; the v2 recommends to use the iframe postMessage route instead (even if you are in a safeframe). + utils.logInfo('Detected Prebid.js is encased in a SafeFrame and CMP is registered, calling it now...'); + callCmpWhileInSafeFrame('getConsentData', v1CallbackHandler.consentDataCallback); + callCmpWhileInSafeFrame('getVendorConsents', v1CallbackHandler.vendorConsentsCallback); + } else { + utils.logInfo('Detected CMP is outside the current iframe where Prebid.js is located, calling it now...'); + if (cmpVersion === 1) { + callCmpWhileInIframe('getConsentData', cmpFrame, v1CallbackHandler.consentDataCallback); + callCmpWhileInIframe('getVendorConsents', cmpFrame, v1CallbackHandler.vendorConsentsCallback); + } else if (cmpVersion === 2) { + callCmpWhileInIframe('addEventListener', cmpFrame, v2CmpResponseCallback); } - - callCmpWhileInIframe('getConsentData', cmpFrame, callbackHandler.consentDataCallback); - callCmpWhileInIframe('getVendorConsents', cmpFrame, callbackHandler.vendorConsentsCallback); } function inASafeFrame() { @@ -138,17 +196,22 @@ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { } function callCmpWhileInIframe(commandName, cmpFrame, moduleCallback) { + let apiName = (cmpVersion === 2) ? '__tcfapi' : '__cmp'; + /* Setup up a __cmp function to do the postMessage and stash the callback. This function behaves (from the caller's perspective identicially to the in-frame __cmp call */ - window.__cmp = function (cmd, arg, callback) { + window[apiName] = function (cmd, arg, callback) { let callId = Math.random() + ''; + let callName = `${apiName}Call`; let msg = { - __cmpCall: { + [callName]: { command: cmd, parameter: arg, callId: callId } }; + if (cmpVersion !== 1) msg[callName].version = cmpVersion; + cmpCallbacks[callId] = callback; cmpFrame.postMessage(msg, '*'); } @@ -157,28 +220,19 @@ function lookupIabConsent(cmpSuccess, cmpError, hookConfig) { window.addEventListener('message', readPostMessageResponse, false); // call CMP - window.__cmp(commandName, null, cmpIframeCallback); + window[apiName](commandName, null, moduleCallback); function readPostMessageResponse(event) { - let json = (typeof event.data === 'string' && strIncludes(event.data, 'cmpReturn')) ? JSON.parse(event.data) : event.data; - if (json.__cmpReturn && json.__cmpReturn.callId) { - let i = json.__cmpReturn; + let cmpDataPkgName = `${apiName}Return`; + let json = (typeof event.data === 'string' && strIncludes(event.data, cmpDataPkgName)) ? JSON.parse(event.data) : event.data; + if (json[cmpDataPkgName] && json[cmpDataPkgName].callId) { + let payload = json[cmpDataPkgName]; // TODO - clean up this logic (move listeners?); we have duplicate messages responses because 2 eventlisteners are active from the 2 cmp requests running in parallel - if (typeof cmpCallbacks[i.callId] !== 'undefined') { - cmpCallbacks[i.callId](i.returnValue, i.success); - delete cmpCallbacks[i.callId]; + if (typeof cmpCallbacks[payload.callId] !== 'undefined') { + cmpCallbacks[payload.callId](payload.returnValue, payload.success); } } } - - function removePostMessageListener() { - window.removeEventListener('message', readPostMessageResponse, false); - } - - function cmpIframeCallback(consentObject) { - removePostMessageListener(); - moduleCallback(consentObject); - } } } @@ -204,6 +258,7 @@ export function requestBidsHook(fn, reqBidsConfigObj) { // in case we already have consent (eg during bid refresh) if (consentData) { + utils.logInfo('User consent information already known. Pulling internally stored information...'); return exitModule(null, hookConfig); } @@ -232,22 +287,51 @@ export function requestBidsHook(fn, reqBidsConfigObj) { * @param {object} hookConfig contains module related variables (see comment in requestBidsHook function) */ function processCmpData(consentObject, hookConfig) { - let gdprApplies = consentObject && consentObject.getConsentData && consentObject.getConsentData.gdprApplies; - if ( - (typeof gdprApplies !== 'boolean') || - (gdprApplies === true && - !(utils.isStr(consentObject.getConsentData.consentData) && - utils.isPlainObject(consentObject.getVendorConsents) && - Object.keys(consentObject.getVendorConsents).length > 1 + function checkV1Data(consentObject) { + let gdprApplies = consentObject && consentObject.getConsentData && consentObject.getConsentData.gdprApplies; + return !!( + (typeof gdprApplies !== 'boolean') || + (gdprApplies === true && + !(utils.isStr(consentObject.getConsentData.consentData) && + utils.isPlainObject(consentObject.getVendorConsents) && + Object.keys(consentObject.getVendorConsents).length > 1 + ) ) - ) - ) { - cmpFailed(`CMP returned unexpected value during lookup process.`, hookConfig, consentObject); - } else { - clearTimeout(hookConfig.timer); - storeConsentData(consentObject); + ); + } + + function checkV2Data() { + // if CMP does not respond with a gdprApplies boolean, use defaultGdprScope (gdprScope) + let gdprApplies = consentObject && typeof consentObject.gdprApplies === 'boolean' ? consentObject.gdprApplies : gdprScope; + let tcString = consentObject && consentObject.tcString; + return !!( + (typeof gdprApplies !== 'boolean') || + (gdprApplies === true && !utils.isStr(tcString)) + ); + } - exitModule(null, hookConfig); + // do extra things for static config + if (userCMP === 'static') { + cmpVersion = (consentObject.getConsentData) ? 1 : (consentObject.getTCData) ? 2 : 0; + // remove extra layer in static v2 data object so it matches normal v2 CMP object for processing step + if (cmpVersion === 2) { + consentObject = consentObject.getTCData; + } + } + + // determine which set of checks to run based on cmpVersion + let checkFn = (cmpVersion === 1) ? checkV1Data : (cmpVersion === 2) ? checkV2Data : null; + + if (utils.isFn(checkFn)) { + if (checkFn(consentObject)) { + cmpFailed(`CMP returned unexpected value during lookup process.`, hookConfig, consentObject); + } else { + clearTimeout(hookConfig.timer); + storeConsentData(consentObject); + exitModule(null, hookConfig); + } + } else { + cmpFailed('Unable to derive CMP version to process data. Consent object does not conform to TCF v1 or v2 specs.', hookConfig, consentObject); } } @@ -279,17 +363,26 @@ function cmpFailed(errMsg, hookConfig, extraArgs) { * @param {object} cmpConsentObject required; an object representing user's consent choices (can be undefined in certain use-cases for this function only) */ function storeConsentData(cmpConsentObject) { - consentData = { - consentString: (cmpConsentObject) ? cmpConsentObject.getConsentData.consentData : undefined, - vendorData: (cmpConsentObject) ? cmpConsentObject.getVendorConsents : undefined, - gdprApplies: (cmpConsentObject) ? cmpConsentObject.getConsentData.gdprApplies : undefined - }; + if (cmpVersion === 1) { + consentData = { + consentString: (cmpConsentObject) ? cmpConsentObject.getConsentData.consentData : undefined, + vendorData: (cmpConsentObject) ? cmpConsentObject.getVendorConsents : undefined, + gdprApplies: (cmpConsentObject) ? cmpConsentObject.getConsentData.gdprApplies : gdprScope + }; + } else { + consentData = { + consentString: (cmpConsentObject) ? cmpConsentObject.tcString : undefined, + vendorData: (cmpConsentObject) || undefined, + gdprApplies: cmpConsentObject && typeof cmpConsentObject.gdprApplies === 'boolean' ? cmpConsentObject.gdprApplies : gdprScope + }; + } + consentData.apiVersion = cmpVersion; gdprDataHandler.setConsentData(consentData); } /** * This function handles the exit logic for the module. - * There are several paths in the module's logic to call this function and we only allow 1 of the 3 potential exits to happen before suppressing others. + * While there are several paths in the module's logic to call this function, we only allow 1 of the 3 potential exits to happen before suppressing others. * * We prevent multiple exits to avoid conflicting messages in the console depending on certain scenarios. * One scenario could be auction was canceled due to timeout with CMP being reached. @@ -336,12 +429,13 @@ function exitModule(errMsg, hookConfig, extraArgs) { export function resetConsentData() { consentData = undefined; userCMP = undefined; + cmpVersion = 0; gdprDataHandler.setConsentData(null); } /** * A configuration function that initializes some module variables, as well as add a hook into the requestBids function - * @param {object} config required; consentManagement module config settings; cmp (string), timeout (int), allowAuctionWithoutConsent (boolean) + * @param {{cmp:string, timeout:number, allowAuctionWithoutConsent:boolean, defaultGdprScope:boolean}} config required; consentManagement module config settings; cmp (string), timeout (int), allowAuctionWithoutConsent (boolean) */ export function setConsentConfig(config) { // if `config.gdpr` or `config.usp` exist, assume new config format. @@ -372,6 +466,9 @@ export function setConsentConfig(config) { utils.logInfo(`consentManagement config did not specify allowAuctionWithoutConsent. Using system default setting (${DEFAULT_ALLOW_AUCTION_WO_CONSENT}).`); } + // if true, then gdprApplies should be set to true + gdprScope = config.defaultGdprScope === true; + utils.logInfo('consentManagement module has been activated...'); if (userCMP === 'static') { diff --git a/modules/consentManagementUsp.js b/modules/consentManagementUsp.js index 35853ff05a6..1a5879a40ff 100644 --- a/modules/consentManagementUsp.js +++ b/modules/consentManagementUsp.js @@ -4,9 +4,9 @@ * information and make it available for any USP (CCPA) supported adapters to * read/pass this information to their system. */ -import * as utils from '../src/utils'; -import { config } from '../src/config'; -import { uspDataHandler } from '../src/adapterManager'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { uspDataHandler } from '../src/adapterManager.js'; const DEFAULT_CONSENT_API = 'iab'; const DEFAULT_CONSENT_TIMEOUT = 50; diff --git a/modules/consumableBidAdapter.js b/modules/consumableBidAdapter.js index 18545cbc319..8eb56f7d0c2 100644 --- a/modules/consumableBidAdapter.js +++ b/modules/consumableBidAdapter.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'consumable'; diff --git a/modules/convergeBidAdapter.js b/modules/convergeBidAdapter.js new file mode 100644 index 00000000000..bea3b6cb1ab --- /dev/null +++ b/modules/convergeBidAdapter.js @@ -0,0 +1,313 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'converge'; +const ENDPOINT_URL = 'https://tech.convergd.com/hb'; +const TIME_TO_LIVE = 360; +const SYNC_URL = 'https://tech.convergd.com/push_sync'; +const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; + +let hasSynced = false; + +const LOG_ERROR_MESS = { + noAuid: 'Bid from response has no auid parameter - ', + noAdm: 'Bid from response has no adm parameter - ', + noBid: 'Array of bid objects is empty', + noPlacementCode: "Can't find in requested bids the bid with auid - ", + emptyUids: 'Uids should be not empty', + emptySeatbid: 'Seatbid array from response has empty item', + emptyResponse: 'Response is empty', + hasEmptySeatbidArray: 'Response has empty seatbid array', + hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' +}; +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [ BANNER, VIDEO ], + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bid) { + return !!bid.params.uid; + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests - an array of bids + * @param {bidderRequest} bidderRequest - bidder request object + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests, bidderRequest) { + const auids = []; + const bidsMap = {}; + const slotsMapByUid = {}; + const sizeMap = {}; + const bids = validBidRequests || []; + let priceType = 'net'; + let pageKeywords; + let reqId; + + bids.forEach(bid => { + if (bid.params.priceType === 'gross') { + priceType = 'gross'; + } + reqId = bid.bidderRequestId; + const {params: {uid}, adUnitCode} = bid; + auids.push(uid); + const sizesId = utils.parseSizesInput(bid.sizes); + + if (!pageKeywords && !utils.isEmpty(bid.params.keywords)) { + const keywords = utils.transformBidderParamKeywords(bid.params.keywords); + + if (keywords.length > 0) { + keywords.forEach(deleteValues); + } + pageKeywords = keywords; + } + + if (!slotsMapByUid[uid]) { + slotsMapByUid[uid] = {}; + } + const slotsMap = slotsMapByUid[uid]; + if (!slotsMap[adUnitCode]) { + slotsMap[adUnitCode] = {adUnitCode, bids: [bid], parents: []}; + } else { + slotsMap[adUnitCode].bids.push(bid); + } + const slot = slotsMap[adUnitCode]; + + sizesId.forEach((sizeId) => { + sizeMap[sizeId] = true; + if (!bidsMap[uid]) { + bidsMap[uid] = {}; + } + + if (!bidsMap[uid][sizeId]) { + bidsMap[uid][sizeId] = [slot]; + } else { + bidsMap[uid][sizeId].push(slot); + } + slot.parents.push({parent: bidsMap[uid], key: sizeId, uid}); + }); + }); + + const payload = { + pt: priceType, + auids: auids.join(','), + sizes: utils.getKeys(sizeMap).join(','), + r: reqId, + wrapperType: 'Prebid_js', + wrapperVersion: '$prebid.version$' + }; + + if (pageKeywords) { + payload.keywords = JSON.stringify(pageKeywords); + } + + if (bidderRequest) { + if (bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { + payload.u = bidderRequest.refererInfo.referer; + } + if (bidderRequest.timeout) { + payload.wtimeout = bidderRequest.timeout; + } + if (bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.consentString) { + payload.gdpr_consent = bidderRequest.gdprConsent.consentString; + } + payload.gdpr_applies = + (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') + ? Number(bidderRequest.gdprConsent.gdprApplies) : 1; + } + if (bidderRequest.uspConsent) { + payload.us_privacy = bidderRequest.uspConsent; + } + } + + return { + method: 'GET', + url: ENDPOINT_URL, + data: utils.parseQueryStringParameters(payload).replace(/\&$/, ''), + bidsMap: bidsMap, + }; + }, + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @param {*} bidRequest + * @param {Renderer} RendererConst + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse, bidRequest, RendererConst = Renderer) { + serverResponse = serverResponse && serverResponse.body; + const bidResponses = []; + const bidsMap = bidRequest.bidsMap; + const priceType = bidRequest.data.pt; + + let errorMessage; + + if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse; + else if (serverResponse.seatbid && !serverResponse.seatbid.length) { + errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; + } + + if (!errorMessage && serverResponse.seatbid) { + serverResponse.seatbid.forEach(respItem => { + _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses, RendererConst); + }); + } + if (errorMessage) utils.logError(errorMessage); + return bidResponses; + }, + getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { + if (!hasSynced && syncOptions.pixelEnabled) { + let params = ''; + + if (gdprConsent && typeof gdprConsent.consentString === 'string') { + if (typeof gdprConsent.gdprApplies === 'boolean') { + params += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + params += `&gdpr_consent=${gdprConsent.consentString}`; + } + } + if (uspConsent) { + params += `&us_privacy=${uspConsent}`; + } + + hasSynced = true; + return { + type: 'image', + url: SYNC_URL + params + }; + } + } +}; + +function isPopulatedArray(arr) { + return !!(utils.isArray(arr) && arr.length > 0); +} + +function deleteValues(keyPairObj) { + if (isPopulatedArray(keyPairObj.value) && keyPairObj.value[0] === '') { + delete keyPairObj.value; + } +} + +function _getBidFromResponse(respItem) { + if (!respItem) { + utils.logError(LOG_ERROR_MESS.emptySeatbid); + } else if (!respItem.bid) { + utils.logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(respItem)); + } else if (!respItem.bid[0]) { + utils.logError(LOG_ERROR_MESS.noBid); + } + return respItem && respItem.bid && respItem.bid[0]; +} + +function _addBidResponse(serverBid, bidsMap, priceType, bidResponses, RendererConst) { + if (!serverBid) return; + let errorMessage; + if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); + if (!serverBid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid); + else { + const awaitingBids = bidsMap[serverBid.auid]; + if (awaitingBids) { + const sizeId = `${serverBid.w}x${serverBid.h}`; + if (awaitingBids[sizeId]) { + const slot = awaitingBids[sizeId][0]; + + const bid = slot.bids.shift(); + const bidResponse = { + requestId: bid.bidId, // bid.bidderRequestId, + bidderCode: spec.code, + cpm: serverBid.price, + width: serverBid.w, + height: serverBid.h, + creativeId: serverBid.auid, // bid.bidId, + currency: 'EUR', + netRevenue: priceType !== 'gross', + ttl: TIME_TO_LIVE, + dealId: serverBid.dealid + }; + if (serverBid.content_type === 'video' || (!serverBid.content_type && bid.mediaTypes && bid.mediaTypes.video)) { + bidResponse.vastXml = serverBid.adm; + bidResponse.mediaType = VIDEO; + bidResponse.adResponse = { + content: bidResponse.vastXml + }; + if (!bid.renderer && (!bid.mediaTypes || !bid.mediaTypes.video || bid.mediaTypes.video.context === 'outstream')) { + bidResponse.renderer = createRenderer(bidResponse, { + id: bid.bidId, + url: RENDERER_URL + }, RendererConst); + } + } else { + bidResponse.ad = serverBid.adm; + bidResponse.mediaType = BANNER; + } + + bidResponses.push(bidResponse); + + if (!slot.bids.length) { + slot.parents.forEach(({parent, key, uid}) => { + const index = parent[key].indexOf(slot); + if (index > -1) { + parent[key].splice(index, 1); + } + if (!parent[key].length) { + delete parent[key]; + if (!utils.getKeys(parent).length) { + delete bidsMap[uid]; + } + } + }); + } + } + } else { + errorMessage = LOG_ERROR_MESS.noPlacementCode + serverBid.auid; + } + } + if (errorMessage) { + utils.logError(errorMessage); + } +} + +function outstreamRender (bid) { + bid.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + targetId: bid.adUnitCode, + adResponse: bid.adResponse + }); + }); +} + +function createRenderer (bid, rendererParams, RendererConst) { + const rendererInst = RendererConst.install({ + id: rendererParams.id, + url: rendererParams.url, + loaded: false + }); + + try { + rendererInst.setRender(outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on renderer', err); + } + + return rendererInst; +} + +export function resetUserSync() { + hasSynced = false; +} + +export function getSyncUrl() { + return SYNC_URL; +} + +registerBidder(spec); diff --git a/modules/convergeBidAdapter.md b/modules/convergeBidAdapter.md new file mode 100644 index 00000000000..ab916a8b3b6 --- /dev/null +++ b/modules/convergeBidAdapter.md @@ -0,0 +1,57 @@ +# Overview + +Module Name: Converge Bidder Adapter +Module Type: Bidder Adapter +Maintainer: support@converge-digital.com + +# Description + +Module that connects to Converge demand source to fetch bids. +Converge Bid Adapter supports Banner and Video (instream and outstream). + +# Test Parameters +``` + var adUnits = [ + { + code: 'test-div', + sizes: [[300, 250]], + bids: [ + { + bidder: "converge", + params: { + uid: '59', + priceType: 'gross' // by default is 'net' + } + } + ] + },{ + code: 'test-div', + sizes: [[728, 90]], + bids: [ + { + bidder: "converge", + params: { + uid: 1, + priceType: 'gross', + keywords: { + brandsafety: ['disaster'], + topic: ['stress', 'fear'] + } + } + } + ] + },{ + code: 'test-div', + sizes: [[640, 360]], + mediaTypes: { video: {} }, + bids: [ + { + bidder: "converge", + params: { + uid: 60 + } + } + ] + } + ]; +``` diff --git a/modules/conversantBidAdapter.js b/modules/conversantBidAdapter.js index bb11b1f87cb..3b3d04dc498 100644 --- a/modules/conversantBidAdapter.js +++ b/modules/conversantBidAdapter.js @@ -1,12 +1,17 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const GVLID = 24; +export const storage = getStorageManager(GVLID); const BIDDER_CODE = 'conversant'; -const URL = '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, + gvlid: GVLID, aliases: ['cnvr'], // short code supportedMediaTypes: [BANNER, VIDEO], @@ -53,6 +58,7 @@ export const spec = { let requestId = ''; let pubcid = null; let pubcidName = '_pubcid'; + let bidurl = URL; const conversantImps = validBidRequests.map(function(bid) { const bidfloor = utils.getBidIdParameter('bidfloor', bid.params); @@ -104,6 +110,9 @@ export const spec = { } else if (bid.crumbs && bid.crumbs.pubcid) { pubcid = bid.crumbs.pubcid; } + if (bid.params.white_label_url) { + bidurl = bid.params.white_label_url; + } return imp; }); @@ -159,7 +168,7 @@ export const spec = { return { method: 'POST', - url: URL, + url: bidurl, data: payload, }; }, @@ -314,36 +323,24 @@ function copyOptProperty(src, dst, dstName) { function collectEids(bidRequests) { const request = bidRequests[0]; // bidRequests have the same userId object const eids = []; - - addEid(eids, request, 'userId.tdid', 'adserver.org'); - addEid(eids, request, 'userId.idl_env', 'liveramp.com'); - addEid(eids, request, 'userId.criteoId', 'criteo.com'); - addEid(eids, request, 'userId.id5id', 'id5-sync.com'); - addEid(eids, request, 'userId.parrableid', 'parrable.com'); - addEid(eids, request, 'userId.digitrustid.data.id', 'digitru.st'); - addEid(eids, request, 'userId.lipb.lipbid', 'liveintent.com'); - - return eids; -} - -/** - * Extract and push a single extended id into eids array - * @param eids Array of extended IDs - * @param idObj Object containing IDs - * @param keyPath Nested properties expressed as a path - * @param source Source for the ID - */ -function addEid(eids, idObj, keyPath, source) { - const id = utils.deepAccess(idObj, keyPath); - if (id) { - eids.push({ - source: source, - uids: [{ - id: id, - atype: 1 - }] + if (utils.isArray(request.userIdAsEids) && request.userIdAsEids.length > 0) { + // later following white-list can be converted to block-list if needed + const requiredSourceValues = { + 'adserver.org': 1, + 'liveramp.com': 1, + 'criteo.com': 1, + 'id5-sync.com': 1, + 'parrable.com': 1, + 'digitru.st': 1, + 'liveintent.com': 1 + }; + request.userIdAsEids.forEach(function(eid) { + if (requiredSourceValues.hasOwnProperty(eid.source)) { + eids.push(eid); + } }); } + return eids; } /** @@ -355,13 +352,13 @@ function readStoredValue(key) { let storedValue; try { // check cookies first - storedValue = utils.getCookie(key); + storedValue = storage.getCookie(key); if (!storedValue) { // check expiration time before reading local storage - const storedValueExp = utils.getDataFromLocalStorage(`${key}_exp`); + const storedValueExp = storage.getDataFromLocalStorage(`${key}_exp`); if (storedValueExp === '' || (storedValueExp && (new Date(storedValueExp)).getTime() - Date.now() > 0)) { - storedValue = utils.getDataFromLocalStorage(key); + storedValue = storage.getDataFromLocalStorage(key); storedValue = storedValue ? decodeURIComponent(storedValue) : storedValue; } } diff --git a/modules/conversantBidAdapter.md b/modules/conversantBidAdapter.md index 5aba5653043..fba793adad2 100644 --- a/modules/conversantBidAdapter.md +++ b/modules/conversantBidAdapter.md @@ -38,6 +38,7 @@ var adUnits = [ site_id: '108060', api: [2], protocols: [1, 2], + white_label_url: 'https://web.hb.ad.cpe.dotomi.com/s2s/header/24', mimes: ['video/mp4'] } }] diff --git a/modules/cosmosBidAdapter.js b/modules/cosmosBidAdapter.js index f3a8979165b..73ee5c223b3 100644 --- a/modules/cosmosBidAdapter.js +++ b/modules/cosmosBidAdapter.js @@ -1,6 +1,6 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; -import * as utils from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; const BIDDER_CODE = 'cosmos'; const BID_ENDPOINT = 'https://bid.cosmoshq.com/openrtb2/bids'; diff --git a/modules/cpmstarBidAdapter.js b/modules/cpmstarBidAdapter.js old mode 100644 new mode 100755 index 8d2ec31a2c6..b416c00c2d0 --- a/modules/cpmstarBidAdapter.js +++ b/modules/cpmstarBidAdapter.js @@ -1,7 +1,8 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import {VIDEO, BANNER} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'cpmstar'; @@ -17,12 +18,12 @@ export const spec = { supportedMediaTypes: [BANNER, VIDEO], pageID: Math.floor(Math.random() * 10e6), - getMediaType: function(bidRequest) { + getMediaType: function (bidRequest) { if (bidRequest == null) return BANNER; return !utils.deepAccess(bidRequest, 'mediaTypes.video') ? BANNER : VIDEO; }, - getPlayerSize: function(bidRequest) { + getPlayerSize: function (bidRequest) { var playerSize = utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize'); if (playerSize == null) return [640, 440]; if (playerSize[0] != null) playerSize = playerSize[0]; @@ -46,9 +47,33 @@ export const spec = { var mediaType = spec.getMediaType(bidRequest); var playerSize = spec.getPlayerSize(bidRequest); var videoArgs = '&fv=0' + (playerSize ? ('&w=' + playerSize[0] + '&h=' + playerSize[1]) : ''); + + var url = ENDPOINT + '?media=' + mediaType + (mediaType == VIDEO ? videoArgs : '') + + '&json=c_b&mv=1&poolid=' + utils.getBidIdParameter('placementId', bidRequest.params) + + '&reachedTop=' + encodeURIComponent(bidderRequest.refererInfo.reachedTop) + + '&requestid=' + bidRequest.bidId + + '&referer=' + encodeURIComponent(referer); + + if (bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.consentString != null) { + url += '&gdpr_consent=' + bidderRequest.gdprConsent.consentString; + } + if (bidderRequest.gdprConsent.gdprApplies != null) { + url += '&gdpr=' + (bidderRequest.gdprConsent.gdprApplies ? 1 : 0); + } + } + + if (bidderRequest.uspConsent != null) { + url += '&us_privacy=' + bidderRequest.uspConsent; + } + + if (config.getConfig('coppa')) { + url += '&tfcd=' + (config.getConfig('coppa') ? 1 : 0); + } + requests.push({ method: 'GET', - url: ENDPOINT + '?media=' + mediaType + (mediaType == VIDEO ? videoArgs : '') + '&json=c_b&mv=1&poolid=' + utils.getBidIdParameter('placementId', bidRequest.params) + '&reachedTop=' + encodeURIComponent(bidderRequest.refererInfo.reachedTop) + '&requestid=' + bidRequest.bidId + '&referer=' + referer, + url: url, bidRequest: bidRequest, }); } diff --git a/modules/cpmstarBidAdapter.md b/modules/cpmstarBidAdapter.md 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 4f88ea9b585..3dabe911884 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -1,18 +1,20 @@ -import { loadExternalScript } from '../src/adloader'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { config } from '../src/config'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; -import { parse } from '../src/url'; -import * as utils from '../src/utils'; -import find from 'core-js/library/fn/array/find'; -import { verify } from 'criteo-direct-rsa-validate/build/verify'; - -export const ADAPTER_VERSION = 26; +import {loadExternalScript} from '../src/adloader.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; +import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; +import find from 'core-js-pure/features/array/find.js'; +import { verify } from 'criteo-direct-rsa-validate/build/verify.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const GVLID = 91; +export const ADAPTER_VERSION = 32; const BIDDER_CODE = 'criteo'; const CDB_ENDPOINT = 'https://bidder.criteo.com/cdb'; -const CRITEO_VENDOR_ID = 91; const PROFILE_ID_INLINE = 207; export const PROFILE_ID_PUBLISHERTAG = 185; +const storage = getStorageManager(GVLID); +const LOG_PREFIX = 'Criteo: '; // Unminified source code can be found in: https://github.com/Prebid-org/prebid-js-external-js-criteo/blob/master/dist/prod.js const PUBLISHER_TAG_URL = 'https://static.criteo.net/js/ld/publishertag.prebid.js'; @@ -23,6 +25,7 @@ const FAST_BID_PUBKEY_N = 'ztQYwCE5BU7T9CDM5he6rKoabstXRmkzx54zFPZkWbK530dwtLBDe /** @type {BidderSpec} */ export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: [ BANNER, VIDEO, NATIVE ], /** @@ -54,7 +57,11 @@ export const spec = { let url; let data; - Object.assign(bidderRequest, { ceh: config.getConfig('criteo.ceh') }); + Object.assign(bidderRequest, { + publisherExt: config.getConfig('fpd.context'), + userExt: config.getConfig('fpd.user'), + ceh: config.getConfig('criteo.ceh') + }); // If publisher tag not already loaded try to get it from fast bid if (!publisherTagAvailable()) { @@ -149,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(); + } + }); } }, @@ -160,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); @@ -196,7 +209,7 @@ function buildContext(bidRequests, bidderRequest) { if (bidderRequest && bidderRequest.refererInfo) { referrer = bidderRequest.refererInfo.referer; } - const queryString = parse(referrer).search; + const queryString = utils.parseUrl(referrer).search; const context = { url: referrer, @@ -238,9 +251,20 @@ function buildCdbUrl(context) { return url; } +function checkNativeSendId(bidRequest) { + return !(bidRequest.nativeParams && + ((bidRequest.nativeParams.image && bidRequest.nativeParams.image.sendId !== true) || + (bidRequest.nativeParams.icon && bidRequest.nativeParams.icon.sendId !== true) || + (bidRequest.nativeParams.clickUrl && bidRequest.nativeParams.clickUrl.sendId !== true) || + (bidRequest.nativeParams.displayUrl && bidRequest.nativeParams.displayUrl.sendId !== true) || + (bidRequest.nativeParams.privacyLink && bidRequest.nativeParams.privacyLink.sendId !== true) || + (bidRequest.nativeParams.privacyIcon && bidRequest.nativeParams.privacyIcon.sendId !== true))); +} + /** * @param {CriteoContext} context * @param {BidRequest[]} bidRequests + * @param bidderRequest * @return {*} */ function buildCdbRequest(context, bidRequests, bidderRequest) { @@ -248,6 +272,7 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { const request = { publisher: { url: context.url, + ext: bidderRequest.publisherExt }, slots: bidRequests.map(bidRequest => { networkId = bidRequest.params.networkId || networkId; @@ -255,25 +280,36 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { impid: bidRequest.adUnitCode, transactionid: bidRequest.transactionId, auctionId: bidRequest.auctionId, - sizes: getBannerSizes(bidRequest), }; if (bidRequest.params.zoneId) { slot.zoneid = bidRequest.params.zoneId; } + if (bidRequest.fpd && bidRequest.fpd.context) { + slot.ext = bidRequest.fpd.context; + } + if (bidRequest.params.ext) { + slot.ext = Object.assign({}, slot.ext, bidRequest.params.ext); + } if (bidRequest.params.publisherSubId) { slot.publishersubid = bidRequest.params.publisherSubId; } if (bidRequest.params.nativeCallback || utils.deepAccess(bidRequest, `mediaTypes.${NATIVE}`)) { slot.native = true; + if (!checkNativeSendId(bidRequest)) { + utils.logWarn(LOG_PREFIX + 'all native assets containing URL should be sent as placeholders with sendId(icon, image, clickUrl, displayUrl, privacyLink, privacyIcon)'); + } + slot.sizes = parseSizes(retrieveBannerSizes(bidRequest), parseNativeSize); + } else { + slot.sizes = parseSizes(retrieveBannerSizes(bidRequest), parseSize); } if (hasVideoMediaType(bidRequest)) { const video = { - playersizes: getVideoSizes(bidRequest), + playersizes: parseSizes(utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize'), parseSize), mimes: bidRequest.mediaTypes.video.mimes, protocols: bidRequest.mediaTypes.video.protocols, maxduration: bidRequest.mediaTypes.video.maxduration, api: bidRequest.mediaTypes.video.api - } + }; video.skip = bidRequest.params.video.skip; video.placement = bidRequest.params.video.placement; @@ -289,7 +325,9 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { if (networkId) { request.publisher.networkid = networkId; } - request.user = {}; + request.user = { + ext: bidderRequest.userExt + }; if (bidderRequest && bidderRequest.ceh) { request.user.ceh = bidderRequest.ceh; } @@ -298,10 +336,7 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { if (typeof bidderRequest.gdprConsent.gdprApplies !== 'undefined') { request.gdprConsent.gdprApplies = !!(bidderRequest.gdprConsent.gdprApplies); } - if (bidderRequest.gdprConsent.vendorData && bidderRequest.gdprConsent.vendorData.vendorConsents && - typeof bidderRequest.gdprConsent.vendorData.vendorConsents[ CRITEO_VENDOR_ID.toString(10) ] !== 'undefined') { - request.gdprConsent.consentGiven = !!(bidderRequest.gdprConsent.vendorData.vendorConsents[ CRITEO_VENDOR_ID.toString(10) ]); - } + request.gdprConsent.version = bidderRequest.gdprConsent.apiVersion; if (typeof bidderRequest.gdprConsent.consentString !== 'undefined') { request.gdprConsent.consentData = bidderRequest.gdprConsent.consentString; } @@ -312,24 +347,26 @@ function buildCdbRequest(context, bidRequests, bidderRequest) { return request; } -function getVideoSizes(bidRequest) { - return parseSizes(utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize')); +function retrieveBannerSizes(bidRequest) { + return utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes') || bidRequest.sizes; } -function getBannerSizes(bidRequest) { - return parseSizes(utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes') || bidRequest.sizes); +function parseSizes(sizes, parser) { + if (Array.isArray(sizes[0])) { // is there several sizes ? (ie. [[728,90],[200,300]]) + return sizes.map(size => parser(size)); + } + return [parser(sizes)]; // or a single one ? (ie. [728,90]) } function parseSize(size) { return size[0] + 'x' + size[1]; } -function parseSizes(sizes) { - if (Array.isArray(sizes[0])) { // is there several sizes ? (ie. [[728,90],[200,300]]) - return sizes.map(size => parseSize(size)); +function parseNativeSize(size) { + if (size[0] === undefined && size[1] === undefined) { + return '2x2'; } - - return [parseSize(sizes)]; // or a single one ? (ie. [728,90]) + return size[0] + 'x' + size[1]; } function hasVideoMediaType(bidRequest) { @@ -423,7 +460,7 @@ export function tryGetCriteoFastBid() { try { const fastBidStorageKey = 'criteo_fast_bid'; const hashPrefix = '// Hash: '; - const fastBidFromStorage = localStorage.getItem(fastBidStorageKey); + const fastBidFromStorage = storage.getDataFromLocalStorage(fastBidStorageKey); if (fastBidFromStorage !== null) { // The value stored must contain the file's encrypted hash as first line @@ -432,7 +469,7 @@ export function tryGetCriteoFastBid() { if (firstLine.substr(0, hashPrefix.length) !== hashPrefix) { utils.logWarn('No hash found in FastBid'); - localStorage.removeItem(fastBidStorageKey); + storage.removeDataFromLocalStorage(fastBidStorageKey); } else { // Remove the hash part from the locally stored value const publisherTagHash = firstLine.substr(hashPrefix.length); @@ -440,13 +477,10 @@ 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'); - localStorage.removeItem(fastBidStorageKey); + storage.removeDataFromLocalStorage(fastBidStorageKey); } } } diff --git a/modules/criteoIdSystem.js b/modules/criteoIdSystem.js index fe89de5d341..c44f0c843ae 100644 --- a/modules/criteoIdSystem.js +++ b/modules/criteoIdSystem.js @@ -5,11 +5,13 @@ * @requires module:modules/userId */ -import * as utils from '../src/utils' -import * as ajax from '../src/ajax' -import * as urlLib from '../src/url' -import { getRefererInfo } from '../src/refererDetection' -import { submodule } from '../src/hook'; +import * as utils from '../src/utils.js' +import * as ajax from '../src/ajax.js' +import { getRefererInfo } from '../src/refererDetection.js' +import { submodule } from '../src/hook.js'; +import { getStorageManager } from '../src/storageManager.js'; + +export const storage = getStorageManager(); const bididStorageKey = 'cto_bidid'; const bundleStorageKey = 'cto_bundle'; @@ -20,33 +22,33 @@ const pastDateString = new Date(0).toString(); const expirationString = new Date(utils.timestamp() + cookiesMaxAge).toString(); function areCookiesWriteable() { - utils.setCookie(cookieWriteableKey, '1'); - const canWrite = utils.getCookie(cookieWriteableKey) === '1'; - utils.setCookie(cookieWriteableKey, '', pastDateString); + storage.setCookie(cookieWriteableKey, '1'); + const canWrite = storage.getCookie(cookieWriteableKey) === '1'; + storage.setCookie(cookieWriteableKey, '', pastDateString); return canWrite; } function extractProtocolHost (url, returnOnlyHost = false) { - const parsedUrl = urlLib.parse(url) + const parsedUrl = utils.parseUrl(url) return returnOnlyHost ? `${parsedUrl.hostname}` : `${parsedUrl.protocol}://${parsedUrl.hostname}${parsedUrl.port ? ':' + parsedUrl.port : ''}/`; } function getFromAllStorages(key) { - return utils.getCookie(key) || utils.getDataFromLocalStorage(key); + return storage.getCookie(key) || storage.getDataFromLocalStorage(key); } function saveOnAllStorages(key, value) { if (key && value) { - utils.setCookie(key, value, expirationString); - utils.setDataInLocalStorage(key, value); + storage.setCookie(key, value, expirationString); + storage.setDataInLocalStorage(key, value); } } function deleteFromAllStorages(key) { - utils.setCookie(key, '', pastDateString); - utils.removeDataFromLocalStorage(key); + storage.setCookie(key, '', pastDateString); + storage.removeDataFromLocalStorage(key); } function getCriteoDataFromAllStorages() { @@ -56,18 +58,19 @@ function getCriteoDataFromAllStorages() { } } -function buildCriteoUsersyncUrl(topUrl, domain, bundle, areCookiesWriteable, isPublishertagPresent) { +function buildCriteoUsersyncUrl(topUrl, domain, bundle, areCookiesWriteable, isPublishertagPresent, gdprString) { const url = 'https://gum.criteo.com/sid/json?origin=prebid' + `${topUrl ? '&topUrl=' + encodeURIComponent(topUrl) : ''}` + `${domain ? '&domain=' + encodeURIComponent(domain) : ''}` + `${bundle ? '&bundle=' + encodeURIComponent(bundle) : ''}` + + `${gdprString ? '&gdprString=' + encodeURIComponent(gdprString) : ''}` + `${areCookiesWriteable ? '&cw=1' : ''}` + `${isPublishertagPresent ? '&pbt=1' : ''}` return url; } -function callCriteoUserSync(parsedCriteoData) { +function callCriteoUserSync(parsedCriteoData, gdprString) { const cw = areCookiesWriteable(); const topUrl = extractProtocolHost(getRefererInfo().referer); const domain = extractProtocolHost(document.location.href, true); @@ -78,7 +81,8 @@ function callCriteoUserSync(parsedCriteoData) { domain, parsedCriteoData.bundle, cw, - isPublishertagPresent + isPublishertagPresent, + gdprString ); ajax.ajaxBuilder()( @@ -119,11 +123,16 @@ export const criteoIdSubmodule = { /** * get the Criteo Id from local storages and initiate a new user sync * @function + * @param {SubmoduleParams} [configParams] + * @param {ConsentData} [consentData] * @returns {{id: {criteoId: string} | undefined}}} */ - getId() { + getId(configParams, consentData) { + const hasGdprData = consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies; + const gdprConsentString = hasGdprData ? consentData.consentString : undefined; + let localData = getCriteoDataFromAllStorages(); - callCriteoUserSync(localData); + callCriteoUserSync(localData, gdprConsentString); return { id: localData.bidId ? { criteoId: localData.bidId } : undefined } } diff --git a/modules/criteortusIdSystem.js b/modules/criteortusIdSystem.js deleted file mode 100644 index 8486bfae9f3..00000000000 --- a/modules/criteortusIdSystem.js +++ /dev/null @@ -1,106 +0,0 @@ -/** - * This module adds Criteo Real Time User Sync to the User ID module - * The {@link module:modules/userId} module is required - * @module modules/criteortusIdSystem - * @requires module:modules/userId - */ - -import * as utils from '../src/utils' -import { ajax } from '../src/ajax'; -import { submodule } from '../src/hook'; - -const key = '__pbjs_criteo_rtus'; - -/** @type {Submodule} */ -export const criteortusIdSubmodule = { - /** - * used to link submodule with config - * @type {string} - */ - name: 'criteortus', - /** - * decode the stored id value for passing to bid requests - * @function - * @returns {{criteortus:Object}} - */ - decode() { - let uid = utils.getCookie(key); - try { - uid = JSON.parse(uid); - return { 'criteortus': uid }; - } catch (error) { - utils.logError('Error in parsing criteo rtus data', error); - } - }, - /** - * performs action to obtain id and return a value in the callback's response argument - * @function - * @param {SubmoduleParams} [configParams] - * @returns {IdResponse|undefined} - */ - getId(configParams) { - if (!configParams || !utils.isPlainObject(configParams.clientIdentifier)) { - utils.logError('User ID - Criteo rtus requires client identifier to be defined'); - return; - } - - let uid = utils.getCookie(key); - if (uid) { - return {id: uid}; - } else { - let userIds = {}; - const resp = function(callback) { - let bidders = Object.keys(configParams.clientIdentifier); - - function afterAllResponses() { - // criteo rtus user id expires in 1 hour - const expiresStr = (new Date(Date.now() + (60 * 60 * 1000))).toUTCString(); - utils.setCookie(key, JSON.stringify(userIds), expiresStr); - callback(userIds); - } - - const onResponse = utils.delayExecution(afterAllResponses, bidders.length); - - bidders.forEach((bidder) => { - let url = `https://gum.criteo.com/sync?c=${configParams.clientIdentifier[bidder]}&r=3`; - const getSuccessHandler = (bidder) => { - return function onSuccess(response) { - if (response) { - try { - response = JSON.parse(response); - userIds[bidder] = response; - onResponse(); - } catch (error) { - utils.logError(error); - } - } - } - } - - const getFailureHandler = (bidder) => { - return function onFailure(error) { - utils.logError(`Criteo RTUS server call failed for ${bidder}`, error); - onResponse(); - } - } - - ajax( - url, - { - success: getSuccessHandler(bidder), - error: getFailureHandler(bidder) - }, - undefined, - Object.assign({ - method: 'GET', - withCredentials: true - }) - ); - }) - }; - return {callback: resp}; - } - } -}; - -submodule('userId', criteortusIdSubmodule); diff --git a/modules/currency.js b/modules/currency.js index 28e033fb1a2..0464d9b5cdb 100644 --- a/modules/currency.js +++ b/modules/currency.js @@ -1,8 +1,9 @@ -import { createBid } from '../src/bidfactory'; -import { STATUS } from '../src/constants'; -import { ajax } from '../src/ajax'; -import * as utils from '../src/utils'; -import { config } from '../src/config'; +import { getGlobal } from '../src/prebidGlobal.js'; +import { createBid } from '../src/bidfactory.js'; +import { STATUS } from '../src/constants.json'; +import { ajax } from '../src/ajax.js'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; import { getHook } from '../src/hook.js'; const DEFAULT_CURRENCY_RATE_URL = 'https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json?date=$$TODAY$$'; @@ -122,6 +123,8 @@ function initCurrency(url) { utils.logInfo('Installing addBidResponse decorator for currency module', arguments); + // Adding conversion function to prebid global for external module and on page use + getGlobal().convertCurrency = (cpm, fromCurrency, toCurrency) => parseFloat(cpm) * getCurrencyConversion(fromCurrency, toCurrency); getHook('addBidResponse').before(addBidResponseHook, 100); // call for the file if we haven't already @@ -149,6 +152,7 @@ function resetCurrency() { utils.logInfo('Uninstalling addBidResponse decorator for currency module', arguments); getHook('addBidResponse').getHooks({hook: addBidResponseHook}).remove(); + delete getGlobal().convertCurrency; adServerCurrency = 'USD'; conversionCache = {}; diff --git a/modules/dailyhuntBidAdapter.js b/modules/dailyhuntBidAdapter.js index bcad7679c4f..1018417300a 100644 --- a/modules/dailyhuntBidAdapter.js +++ b/modules/dailyhuntBidAdapter.js @@ -1,55 +1,337 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import * as mediaTypes from '../src/mediaTypes'; -import * as utils from '../src/utils'; +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/datablocksAnalyticsAdapter.js b/modules/datablocksAnalyticsAdapter.js index 76dd490180b..5e977155284 100644 --- a/modules/datablocksAnalyticsAdapter.js +++ b/modules/datablocksAnalyticsAdapter.js @@ -2,8 +2,8 @@ * Analytics Adapter for Datablocks */ -import adapter from '../src/AnalyticsAdapter'; -import adapterManager from '../src/adapterManager'; +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; var datablocksAdapter = adapter({ global: 'datablocksAnalytics', diff --git a/modules/datablocksBidAdapter.js b/modules/datablocksBidAdapter.js index cbad3ac910c..b00a3eae659 100644 --- a/modules/datablocksBidAdapter.js +++ b/modules/datablocksBidAdapter.js @@ -1,7 +1,6 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; -import { parse as parseUrl } from '../src/url'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; const NATIVE_MAP = { 'body': 2, 'body2': 10, @@ -61,7 +60,7 @@ export const spec = { let imps = {}; let site = {}; let device = {}; - let refurl = parseUrl(bidderRequest.referrer); + let refurl = utils.parseUrl(bidderRequest.referrer); let requests = []; validBidRequests.forEach(bidRequest => { diff --git a/modules/deepintentBidAdapter.js b/modules/deepintentBidAdapter.js index ace4bcb5ae2..c4dc23cf912 100644 --- a/modules/deepintentBidAdapter.js +++ b/modules/deepintentBidAdapter.js @@ -1,6 +1,6 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER} from '../src/mediaTypes'; -import * as utils from '../src/utils'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; const BIDDER_CODE = 'deepintent'; const BIDDER_ENDPOINT = 'https://prebid.deepintent.com/prebid'; const USER_SYNC_URL = 'https://cdn.deepintent.com/syncpixel.html'; @@ -37,9 +37,18 @@ export const spec = { imp: validBidRequests.map(bid => buildImpression(bid)), site: buildSite(bidderRequest), device: buildDevice(), - user: user && user.length == 1 ? user[0] : {} + user: user && user.length === 1 ? user[0] : {} }; + if (bidderRequest && bidderRequest.uspConsent) { + utils.deepSetValue(openRtbBidRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + + if (bidderRequest && bidderRequest.gdprConsent) { + utils.deepSetValue(openRtbBidRequest, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + utils.deepSetValue(openRtbBidRequest, 'regs.ext.gdpr', (bidderRequest.gdprConsent.gdprApplies ? 1 : 0)); + } + return { method: 'POST', url: BIDDER_ENDPOINT, @@ -127,13 +136,15 @@ function buildBanner(bid) { if (utils.isArray(sizes) && sizes.length > 0) { return { h: sizes[0][1], - w: sizes[0][0] + w: sizes[0][0], + pos: bid && bid.params && bid.params.pos ? bid.params.pos : 0 } } } else { return { h: bid.params.height, - w: bid.params.width + w: bid.params.width, + pos: bid && bid.params && bid.params.pos ? bid.params.pos : 0 } } } diff --git a/modules/deepintentBidAdapter.md b/modules/deepintentBidAdapter.md index 7f5afbd233a..79a6a1679e2 100644 --- a/modules/deepintentBidAdapter.md +++ b/modules/deepintentBidAdapter.md @@ -29,6 +29,7 @@ Module that connects to Deepintent's demand sources. tagId: '1300', // Required parameter w: 300, // Width and Height here will override sizes in mediatype h: 250, + pos: 1, custom: { // Custom parameters in form of key value pairs user_min_age: 18 } diff --git a/modules/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js index c3f867308d1..71a8471d554 100644 --- a/modules/dfpAdServerVideo.js +++ b/modules/dfpAdServerVideo.js @@ -2,13 +2,12 @@ * This module adds [DFP support]{@link https://www.doubleclickbygoogle.com/} for Video to Prebid. */ -import { registerVideoSupport } from '../src/adServerManager'; -import { targeting } from '../src/targeting'; -import { formatQS, format as buildUrl, parse } from '../src/url'; -import { deepAccess, isEmpty, logError, parseSizesInput } from '../src/utils'; -import { config } from '../src/config'; -import { getHook, submodule } from '../src/hook'; -import { auctionManager } from '../src/auctionManager'; +import { registerVideoSupport } from '../src/adServerManager.js'; +import { targeting } from '../src/targeting.js'; +import { deepAccess, isEmpty, logError, parseSizesInput, formatQS, parseUrl, buildUrl } from '../src/utils.js'; +import { config } from '../src/config.js'; +import { getHook, submodule } from '../src/hook.js'; +import { auctionManager } from '../src/auctionManager.js'; /** * @typedef {Object} DfpVideoParams @@ -74,7 +73,7 @@ export function buildDfpVideoUrl(options) { if (options.url) { // when both `url` and `params` are given, parsed url will be overwriten // with any matching param components - urlComponents = parse(options.url, {noDecodeWholeURL: true}); + urlComponents = parseUrl(options.url, {noDecodeWholeURL: true}); if (isEmpty(options.params)) { return buildUrlFromAdserverUrlComponents(urlComponents, bid, options); diff --git a/modules/digiTrustIdSystem.js b/modules/digiTrustIdSystem.js index 9cce72a92ce..d8aa8be9376 100644 --- a/modules/digiTrustIdSystem.js +++ b/modules/digiTrustIdSystem.js @@ -9,9 +9,13 @@ * @requires module:modules/userId */ -import * as utils from '../src/utils' -import { ajax } from '../src/ajax'; -import { submodule } from '../src/hook'; +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 @@ -40,13 +44,19 @@ var noop = function () { const MAX_RETRIES = 2; const DT_ID_SVC = 'https://prebid.digitru.st/id/v1'; -const DT_VENDOR_ID = 64; // cmp gvlVendorId 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, { @@ -54,9 +64,7 @@ function callApi(options) { error: options.fail }, null, - { - method: 'GET' - } + ajaxOptions ); } @@ -69,7 +77,7 @@ function encId(id) { if (typeof (id) !== 'string') { id = JSON.stringify(id); } - return encodeURIComponent(btoa(id)); + return btoa(id); } catch (ex) { return id; } @@ -83,8 +91,32 @@ function writeDigiId(id) { var key = 'DigiTrust.v1.identity'; var date = new Date(); date.setTime(date.getTime() + 604800000); - var exp = 'expires=' + date.toUTCString(); - document.cookie = key + '=' + encId(id) + '; ' + exp + '; path=/;SameSite=none;'; + 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; } /** @@ -92,8 +124,6 @@ function writeDigiId(id) { * */ function initDigitrustFacade(config) { - var _savedId = null; // closure variable for storing Id to avoid additional requests - clearTimeout(fallbackTimer); fallbackTimer = 0; @@ -112,12 +142,12 @@ function initDigitrustFacade(config) { inter.callCount++; // wrap the initializer callback, if present - var checkCallInitializeCb = function (idResponse) { + 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'); + utils.logError('Exception in passed DigiTrust init callback', ex); } } } @@ -132,9 +162,9 @@ function initDigitrustFacade(config) { } if (_savedId != null) { - checkCallInitializeCb(_savedId); if (isAsync) { - cb(_savedId); + checkAndCallInitializeCb(_savedId); + // cb(_savedId); return; } else { return _savedId; @@ -147,14 +177,14 @@ function initDigitrustFacade(config) { success: true } try { - writeDigiId(respText); idResult.identity = JSON.parse(respText); - _savedId = idResult; + _savedId = idResult; // Save result to the cache variable + writeDigiId(respText); } catch (ex) { idResult.success = false; + delete idResult.identity; } - checkCallInitializeCb(idResult); - cb(idResult); + checkAndCallInitializeCb(idResult); }, fail: function (statusErr, result) { utils.logError('DigiTrustId API error: ' + statusErr); @@ -164,6 +194,14 @@ function initDigitrustFacade(config) { // 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); } }) @@ -207,9 +245,9 @@ var gdprConsent = { var consentAnswer = false; if (typeof (window.__cmp) !== 'undefined') { stopTimer = setTimeout(function () { - consentAnswer = true; - consentCb(consentAnswer); + consentAnswer = false; processed = true; + consentCb(consentAnswer); }, options.consentTimeout); window.__cmp('ping', null, function(pingAnswer) { @@ -227,9 +265,12 @@ var gdprConsent = { consentCb(consentAnswer); } }); + } else { + // __cmp library is not preset. + // ignore this check and rely on id system GDPR consent management + consentAnswer = true; + consentCb(consentAnswer); } - consentAnswer = true; - consentCb(consentAnswer); } } @@ -251,6 +292,10 @@ var ResultWrapper = function (opts) { */ this.userIdCallback = function (callback) { idSystemFn = callback; + if (me.idObj == null) { + me.idObj = _savedId; + } + if (me.idObj != null && isFunc(callback)) { callback(wrapIdResult()); } @@ -260,6 +305,10 @@ var ResultWrapper = function (opts) { * Return a wrapped result formatted for userId system */ function wrapIdResult() { + if (me.idObj == null) { + me.idObj = _savedId; + } + if (me.idObj == null) { return null; } diff --git a/modules/districtmDMXBidAdapter.js b/modules/districtmDMXBidAdapter.js index 772508e02d8..03dca0b607d 100644 --- a/modules/districtmDMXBidAdapter.js +++ b/modules/districtmDMXBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import {config} from '../src/config'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; const BIDDER_CODE = 'districtmDMX'; @@ -27,6 +27,9 @@ export const spec = { nBid.requestId = nBid.impid; nBid.width = nBid.w || width; nBid.height = nBid.h || height; + if (nBid.dealid) { + nBid.dealId = nBid.dealid; + } nBid.ad = nBid.adm; nBid.netRevenue = true; nBid.creativeId = nBid.crid; @@ -69,6 +72,7 @@ export const spec = { publisher: { id: String(bidRequest[0].params.memberid) || null } } } + try { let params = config.getConfig('dmx'); dmxRequest.user = params.user || {}; @@ -77,6 +81,18 @@ export const spec = { } catch (e) { } + + let eids = []; + if (bidRequest && bidRequest.userId) { + bindUserId(eids, utils.deepAccess(bidRequest, `userId.idl_env`), 'liveramp.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest, `userId.digitrustid.data.id`), 'digitru.st', 1); + bindUserId(eids, utils.deepAccess(bidRequest, `userId.id5id`), 'id5-sync.com', 1); + bindUserId(eids, utils.deepAccess(bidRequest, `userId.pubcid`), 'pubcid.org', 1); + bindUserId(eids, utils.deepAccess(bidRequest, `userId.tdid`), 'adserver.org', 1); + dmxRequest.user = dmxRequest.user || {}; + dmxRequest.user.ext = dmxRequest.user.ext || {}; + dmxRequest.user.ext.eids = eids; + } if (!dmxRequest.test) { delete dmxRequest.test; } @@ -88,6 +104,8 @@ export const spec = { dmxRequest.user.ext = {}; dmxRequest.user.ext.consent = bidderRequest.gdprConsent.consentString; } + dmxRequest.regs = dmxRequest.regs || {}; + dmxRequest.regs.coppa = config.getConfig('coppa') === true ? 1 : 0; if (bidderRequest && bidderRequest.uspConsent) { dmxRequest.regs = dmxRequest.regs || {}; dmxRequest.regs.ext = dmxRequest.regs.ext || {}; @@ -130,11 +148,22 @@ export const spec = { test() { return window.location.href.indexOf('dmTest=true') !== -1 ? 1 : 0; }, - getUserSyncs(optionsType) { + getUserSyncs(optionsType, serverResponses, gdprConsent, uspConsent) { + let query = []; + let url = 'https://cdn.districtm.io/ids/index.html' + if (gdprConsent && gdprConsent.gdprApplies && typeof gdprConsent.consentString === 'string') { + query.push(['gdpr', gdprConsent.consentString]) + } + if (uspConsent) { + query.push(['ccpa', uspConsent]) + } + if (query.length > 0) { + url += '?' + query.map(q => q.join('=')).join('&') + } if (optionsType.iframeEnabled) { return [{ type: 'iframe', - url: 'https://cdn.districtm.io/ids/index.html' + url: url }]; } } @@ -267,4 +296,18 @@ export function defaultSize(thebidObj) { returnObject.height = checkDeepArray(sizes)[1]; return returnObject; } + +export function bindUserId(eids, value, source, atype) { + if (utils.isStr(value) && Array.isArray(eids)) { + eids.push({ + source, + uids: [ + { + id: value, + atype + } + ] + }) + } +} registerBidder(spec); diff --git a/modules/districtmDmxBidAdapter.md b/modules/districtmDmxBidAdapter.md index 5bc1e5d5780..792cf2e7305 100644 --- a/modules/districtmDmxBidAdapter.md +++ b/modules/districtmDmxBidAdapter.md @@ -13,6 +13,8 @@ The `districtmDmxAdapter` module allows publishers to include DMX Exchange deman * Single Request * Multi-Size Support * GDPR Compliant +* CCPA Compliant +* COPPA Compliant * Bids returned in **NET** ## Media Types @@ -23,8 +25,8 @@ The `districtmDmxAdapter` module allows publishers to include DMX Exchange deman | Key | Scope | Type | Description | --- | --- | --- | --- -| dmxid | Mandatory | Integer | Unique identifier of the placement, dmxid can be obtained in the district m Boost platform. -| memberid | Mandatory | Integer | Unique identifier for your account, memberid can be obtained in the district m Boost platform. +| `dmxid` | Mandatory | Integer | Unique identifier of the placement, dmxid can be obtained in the district m Boost platform. +| `memberid` | Mandatory | Integer | Unique identifier for your account, memberid can be obtained in the district m Boost platform. # Ad Unit Configuration Example @@ -47,6 +49,9 @@ The `districtmDmxAdapter` module allows publishers to include DMX Exchange deman ``` +# Ad Unit Configuration when COPPA is needed + + # Quick Start Guide ###### 1. Including the `districtmDmxAdapter` in your build process. diff --git a/modules/djaxBidAdapter.js b/modules/djaxBidAdapter.js index 80975f0929a..ffaf61a3f15 100644 --- a/modules/djaxBidAdapter.js +++ b/modules/djaxBidAdapter.js @@ -1,9 +1,9 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { config } from '../src/config'; -import * as utils from '../src/utils'; -import {BANNER, VIDEO} from '../src/mediaTypes'; -import { ajax } from '../src/ajax'; -import {Renderer} from '../src/Renderer'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import * as utils from '../src/utils.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import { ajax } from '../src/ajax.js'; +import {Renderer} from '../src/Renderer.js'; const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; const BIDDER_CODE = 'djax'; diff --git a/modules/dspxBidAdapter.js b/modules/dspxBidAdapter.js index 4954347d288..d05549601e1 100644 --- a/modules/dspxBidAdapter.js +++ b/modules/dspxBidAdapter.js @@ -1,45 +1,82 @@ -import * as utils from '../src/utils'; -import {config} from '../src/config'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; const BIDDER_CODE = 'dspx'; const ENDPOINT_URL = 'https://buyer.dspx.tv/request/'; const ENDPOINT_URL_DEV = 'https://dcbuyer.dspx.tv/request/'; +const DEFAULT_VAST_FORMAT = 'vast2'; export const spec = { code: BIDDER_CODE, aliases: ['dspx'], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid: function(bid) { return !!(bid.params.placement); }, buildRequests: function(validBidRequests, bidderRequest) { return validBidRequests.map(bidRequest => { const params = bidRequest.params; + + const 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; } @@ -74,9 +111,15 @@ export const spec = { dealId: dealId, currency: currency, netRevenue: netRevenue, - ttl: config.getConfig('_bidderTimeout'), - ad: response.adTag + type: response.type, + ttl: config.getConfig('_bidderTimeout') }; + if (response.vastXml) { + bidResponse.vastXml = response.vastXml; + bidResponse.mediaType = 'video'; + } else { + bidResponse.ad = response.adTag; + } bidResponses.push(bidResponse); } return bidResponses; @@ -98,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/e_volutionBidAdapter.js b/modules/e_volutionBidAdapter.js new file mode 100644 index 00000000000..9fc7035db32 --- /dev/null +++ b/modules/e_volutionBidAdapter.js @@ -0,0 +1,111 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; + +const BIDDER_CODE = 'e_volution'; +const AD_URL = 'https://service.e-volution.ai/?c=o&m=multi'; +const URL_SYNC = 'https://service.e-volution.ai/?c=o&m=sync'; +const NO_SYNC = true; + +function isBidResponseValid(bid) { + if (!bid.requestId || !bid.cpm || !bid.creativeId || + !bid.ttl || !bid.currency) { + return false; + } + switch (bid.mediaType) { + case BANNER: + return Boolean(bid.width && bid.height && bid.ad); + case VIDEO: + return Boolean(bid.vastUrl); + case NATIVE: + return Boolean(bid.native && bid.native.title && bid.native.image && bid.native.impressionTrackers); + default: + return false; + } +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], + noSync: NO_SYNC, + + isBidRequestValid: (bid) => { + return Boolean(bid.bidId && bid.params && !isNaN(parseInt(bid.params.placementId))); + }, + + buildRequests: (validBidRequests = [], bidderRequest) => { + let winTop = window; + let location; + try { + location = new URL(bidderRequest.refererInfo.referer) + winTop = window.top; + } catch (e) { + location = winTop.location; + utils.logMessage(e); + }; + let placements = []; + let request = { + 'deviceWidth': winTop.screen.width, + 'deviceHeight': winTop.screen.height, + 'language': (navigator && navigator.language) ? navigator.language.split('-')[0] : '', + 'secure': 1, + 'host': location.host, + 'page': location.pathname, + 'placements': placements + }; + if (bidderRequest) { + if (bidderRequest.uspConsent) { + request.ccpa = bidderRequest.uspConsent; + } + if (bidderRequest.gdprConsent) { + request.gdpr = bidderRequest.gdprConsent + } + } + const len = validBidRequests.length; + + for (let i = 0; i < len; i++) { + let bid = validBidRequests[i]; + let traff = bid.params.traffic || BANNER + + placements.push({ + placementId: bid.params.placementId, + bidId: bid.bidId, + sizes: bid.mediaTypes && bid.mediaTypes[traff] && bid.mediaTypes[traff].sizes ? bid.mediaTypes[traff].sizes : [], + traffic: traff + }); + if (bid.schain) { + placements.schain = bid.schain; + } + } + return { + method: 'POST', + url: AD_URL, + data: request + }; + }, + + interpretResponse: (serverResponse) => { + let response = []; + for (let i = 0; i < serverResponse.body.length; i++) { + let resItem = serverResponse.body[i]; + if (isBidResponseValid(resItem)) { + response.push(resItem); + } + } + return response; + }, + + getUserSyncs: (syncOptions, serverResponses) => { + if (NO_SYNC) { + return false + } else { + return [{ + type: 'image', + url: URL_SYNC + }]; + } + } + +}; + +registerBidder(spec); diff --git a/modules/e_volutionBidAdapter.md b/modules/e_volutionBidAdapter.md new file mode 100644 index 00000000000..ff5b2860e05 --- /dev/null +++ b/modules/e_volutionBidAdapter.md @@ -0,0 +1,53 @@ +# Overview + +``` +Module Name: e_volution Bidder Adapter +Module Type: Bidder Adapter +``` + +# Description + +Module that connects to e-volution-tech demand sources + +# Test Parameters +``` + var adUnits = [ + // Will return static test banner + { + code: 'placementId_0', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: 'e_volution', + params: { + placementId: 0, + traffic: 'banner' + } + } + ] + }, + // Will return test vast xml. All video params are stored under placement in publishers UI + { + code: 'placementId_0', + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'instream' + } + }, + bids: [ + { + bidder: 'e_volution', + params: { + placementId: 0, + traffic: 'video' + } + } + ] + } + ]; +``` diff --git a/modules/ebdrBidAdapter.js b/modules/ebdrBidAdapter.js index d8af215f96a..c30c10d8a90 100644 --- a/modules/ebdrBidAdapter.js +++ b/modules/ebdrBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import { VIDEO, BANNER } from '../src/mediaTypes'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'ebdr'; export const spec = { code: BIDDER_CODE, diff --git a/modules/edgequeryxBidAdapter.js b/modules/edgequeryxBidAdapter.js new file mode 100644 index 00000000000..ee50946ee18 --- /dev/null +++ b/modules/edgequeryxBidAdapter.js @@ -0,0 +1,98 @@ +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'edgequeryx'; + +export const spec = { + code: BIDDER_CODE, + aliases: ['eqx'], // short code + supportedMediaTypes: [BANNER, VIDEO], + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function (bid) { + return !!(bid.params && bid.params.accountId && bid.params.widgetId); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests an array of bids + * @param {BidderRequest} bidderRequest bidder request object + * @return {ServerRequest[]} Info describing the request to the server. + */ + buildRequests: function (validBidRequests, bidderRequest) { + // use bidderRequest.bids[] to get bidder-dependent request info + // if your bidder supports multiple currencies, use config.getConfig(currency) + // to find which one the ad server needs + + // pull requested transaction ID from bidderRequest.bids[].transactionId + return validBidRequests.map(bid => { + // Common bid request attributes for banner, outstream and instream. + let payload = { + accountId: bid.params.accountId, + widgetId: bid.params.widgetId, + currencyCode: 'EUR', + tagId: bid.adUnitCode, + transactionId: bid.transactionId, + timeout: config.getConfig('bidderTimeout'), + bidId: bid.bidId, + prebidVersion: '$prebid.version$' + }; + + const bannerMediaType = utils.deepAccess(bid, 'mediaTypes.banner'); + payload.sizes = bannerMediaType.sizes.map(size => ({ + w: size[0], + h: size[1] + })); + + var payloadString = JSON.stringify(payload); + + return { + method: 'POST', + url: (bid.params.domain !== undefined ? bid.params.domain : 'https://deep.edgequery.io') + '/prebid/x', + data: payloadString, + }; + }); + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @param {*} bidRequestString + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse, bidRequestString) { + const bidResponses = []; + let response = serverResponse.body; + try { + if (response) { + let bidResponse = { + requestId: response.requestId, + cpm: response.cpm, + currency: response.currency, + width: response.width, + height: response.height, + ad: response.ad, + ttl: response.ttl, + creativeId: response.creativeId, + netRevenue: response.netRevenue + }; + + bidResponses.push(bidResponse); + } + } catch (error) { + utils.logError('Error while parsing Edge Query X response', error); + } + return bidResponses; + } + +}; + +registerBidder(spec); diff --git a/modules/edgequeryxBidAdapter.md b/modules/edgequeryxBidAdapter.md new file mode 100644 index 00000000000..265120dfaba --- /dev/null +++ b/modules/edgequeryxBidAdapter.md @@ -0,0 +1,39 @@ +# Overview + +``` +Module Name: Edge Query X Bidder Adapter +Module Type: Bidder Adapter +Maintainer: contact@edgequery.com +``` + +# Description + +Connect to Edge Query X for bids. + +The Edge Query X adapter requires setup and approval from the Edge Query team. +Please reach out to your Technical account manager for more information. + +# Test Parameters + +## Web +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[1, 1]] + } + }, + bids: [ + { + bidder: "edgequeryx", + params: { + accountId: "test", + widgetId: "test" + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/modules/emoteevBidAdapter.js b/modules/emoteevBidAdapter.js index fb62e4381e3..e0f88725d8a 100644 --- a/modules/emoteevBidAdapter.js +++ b/modules/emoteevBidAdapter.js @@ -14,8 +14,8 @@ * @author Emoteev Engineering . */ -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER} from '../src/mediaTypes'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; import { triggerPixel, getUniqueIdentifierStr, @@ -24,10 +24,12 @@ import { isArray, isInteger, getParameterByName, - getCookie -} from '../src/utils'; -import {config} from '../src/config'; -import * as url from '../src/url'; + buildUrl +} from '../src/utils.js'; +import {config} from '../src/config.js'; +import { getStorageManager } from '../src/storageManager.js'; + +export const storage = getStorageManager(); export const BIDDER_CODE = 'emoteev'; @@ -232,7 +234,7 @@ export const domain = (env) => { * @param {string} env Emoteev environment parameter * @returns {string} The full URL which events is sent to. */ -export const eventsUrl = env => url.format({ +export const eventsUrl = env => buildUrl({ protocol: (env === DEVELOPMENT) ? 'http' : 'https', hostname: domain(env), pathname: EVENTS_PATH @@ -244,7 +246,7 @@ export const eventsUrl = env => url.format({ * @param {string} env Emoteev environment parameter * @returns {string} The full URL which bidderRequest is sent to. */ -export const bidderUrl = env => url.format({ +export const bidderUrl = env => buildUrl({ protocol: (env === DEVELOPMENT) ? 'http' : 'https', hostname: domain(env), pathname: BIDDER_PATH @@ -256,7 +258,7 @@ export const bidderUrl = env => url.format({ * @param {string} env Emoteev environment parameter * @returns {string} The full URL called for iframe-based user sync */ -export const userSyncIframeUrl = env => url.format({ +export const userSyncIframeUrl = env => buildUrl({ protocol: (env === DEVELOPMENT) ? 'http' : 'https', hostname: domain(env), pathname: USER_SYNC_IFRAME_PATH @@ -268,7 +270,7 @@ export const userSyncIframeUrl = env => url.format({ * @param {string} env Emoteev environment parameter * @returns {string} The full URL called for image-based user sync */ -export const userSyncImageUrl = env => url.format({ +export const userSyncImageUrl = env => buildUrl({ protocol: (env === DEVELOPMENT) ? 'http' : 'https', hostname: domain(env), pathname: USER_SYNC_IMAGE_PATH @@ -506,12 +508,12 @@ export const spec = { bidderRequest), interpretResponse: interpretResponse, onBidWon: (bidObject) => - triggerPixel(url.format(onBidWon( + triggerPixel(buildUrl(onBidWon( resolveEnv(config.getConfig(), getParameterByName('emoteevEnv')), - getCookie('_pubcid'), + storage.getCookie('_pubcid'), bidObject))), onTimeout: (bidRequest) => - triggerPixel(url.format(onTimeout( + triggerPixel(buildUrl(onTimeout( resolveEnv(config.getConfig(), getParameterByName('emoteevEnv')), bidRequest))), getUserSyncs: (syncOptions) => diff --git a/modules/emx_digitalBidAdapter.js b/modules/emx_digitalBidAdapter.js index 60e3de4adcd..6688d15d8e9 100644 --- a/modules/emx_digitalBidAdapter.js +++ b/modules/emx_digitalBidAdapter.js @@ -1,14 +1,14 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; -import { Renderer } from '../src/Renderer'; -import includes from 'core-js/library/fn/array/includes'; -import {parse as parseUrl} from '../src/url'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { Renderer } from '../src/Renderer.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import find from 'core-js-pure/features/array/find.js'; const BIDDER_CODE = 'emx_digital'; const ENDPOINT = 'hb.emxdgt.com'; const RENDERER_URL = 'https://js.brealtime.com/outstream/1.30.0/bundle.js'; -const ADAPTER_VERSION = '1.5.0'; +const ADAPTER_VERSION = '1.5.1'; const DEFAULT_CUR = 'USD'; export const emxAdapter = { @@ -42,11 +42,14 @@ export const emxAdapter = { }, formatVideoResponse: (bidResponse, emxBid, bidRequest) => { bidResponse.vastXml = emxBid.adm; - if (bidRequest.bidRequest && bidRequest.bidRequest.mediaTypes && bidRequest.bidRequest.mediaTypes.video && bidRequest.bidRequest.mediaTypes.video.context === 'outstream') { - bidResponse.renderer = emxAdapter.createRenderer(bidResponse, { - id: emxBid.id, - url: RENDERER_URL - }); + if (bidRequest.bidderRequest && bidRequest.bidderRequest.bids && bidRequest.bidderRequest.bids.length > 0) { + const matchingBid = find(bidRequest.bidderRequest.bids, bid => bidResponse.requestId && bid.bidId && bidResponse.requestId === bid.bidId && bid.mediaTypes && bid.mediaTypes.video && bid.mediaTypes.video.context === 'outstream'); + if (matchingBid) { + bidResponse.renderer = emxAdapter.createRenderer(bidResponse, { + id: emxBid.id, + url: RENDERER_URL + }); + } } return bidResponse; }, @@ -130,7 +133,7 @@ export const emxAdapter = { } }, getSite: (refInfo) => { - let url = parseUrl(refInfo.referer); + let url = utils.parseUrl(refInfo.referer); return { domain: url.hostname, page: refInfo.referer, diff --git a/modules/envivoBidAdapter.js b/modules/envivoBidAdapter.js index 41bfda7c071..b9c80ffd468 100644 --- a/modules/envivoBidAdapter.js +++ b/modules/envivoBidAdapter.js @@ -1,9 +1,9 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { config } from '../src/config'; -import * as utils from '../src/utils'; -import {BANNER, VIDEO} from '../src/mediaTypes'; -import { ajax } from '../src/ajax'; -import {Renderer} from '../src/Renderer'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import * as utils from '../src/utils.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import { ajax } from '../src/ajax.js'; +import {Renderer} from '../src/Renderer.js'; const SUPPORTED_AD_TYPES = [BANNER, VIDEO]; const BIDDER_CODE = 'envivo'; diff --git a/modules/eplanningAnalyticsAdapter.js b/modules/eplanningAnalyticsAdapter.js index 21ecddfbc3a..08db2f2ca9d 100644 --- a/modules/eplanningAnalyticsAdapter.js +++ b/modules/eplanningAnalyticsAdapter.js @@ -1,7 +1,7 @@ -import {ajax} from '../src/ajax'; -import adapter from '../src/AnalyticsAdapter'; -import adapterManager from '../src/adapterManager'; -import * as utils from '../src/utils'; +import {ajax} from '../src/ajax.js'; +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; const CONSTANTS = require('../src/constants.json'); diff --git a/modules/eplanningBidAdapter.js b/modules/eplanningBidAdapter.js index 219192b6406..ac5ba659ad7 100644 --- a/modules/eplanningBidAdapter.js +++ b/modules/eplanningBidAdapter.js @@ -1,11 +1,14 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { getStorageManager } from '../src/storageManager.js'; + +export const storage = getStorageManager(); const BIDDER_CODE = 'eplanning'; const rnd = Math.random(); const DEFAULT_SV = 'ads.us.e-planning.net'; const DEFAULT_ISV = 'i.e-planning.net'; -const PARAMS = ['ci', 'sv', 't']; +const PARAMS = ['ci', 'sv', 't', 'ml']; const DOLLARS = 'USD'; const NET_REVENUE = true; const TTL = 120; @@ -29,7 +32,7 @@ export const spec = { let params; const urlConfig = getUrlConfig(bidRequests); const pcrs = getCharset(); - const spaces = getSpaces(bidRequests); + const spaces = getSpaces(bidRequests, urlConfig.ml); const pageUrl = bidderRequest.refererInfo.referer; const getDomain = (url) => { let anchor = document.createElement('a'); @@ -41,16 +44,16 @@ 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 (utils.hasLocalStorage()) { + if (storage.hasLocalStorage()) { registerViewabilityAllBids(bidRequests); } params = { rnd: rnd, e: spaces.str, - ur: encodeURIComponent(pageUrl || FILE), + ur: pageUrl || FILE, r: 'pbjs', pbv: '$prebid.version$', ncb: '1', @@ -185,12 +188,16 @@ function getSpacesStruct(bids) { return e; } -function getSpaces(bidRequests) { +function cleanName(name) { + return name.replace(/_|\.|-|\//g, '').replace(/\)\(|\(|\)|:/g, '_').replace(/^_+|_+$/g, ''); +} + +function getSpaces(bidRequests, ml) { let spacesStruct = getSpacesStruct(bidRequests); let es = {str: '', vs: '', map: {}}; es.str = Object.keys(spacesStruct).map(size => spacesStruct[size].map((bid, i) => { es.vs += getVs(bid); - let name = getSize(bid, true) + '_' + i; + let name = ml ? cleanName(bid.adUnitCode) : getSize(bid, true) + '_' + i; es.map[name] = bid.bidId; return name + ':' + getSize(bid); }).join('+')).join('+'); @@ -200,7 +207,7 @@ function getSpaces(bidRequests) { function getVs(bid) { let s; let vs = ''; - if (utils.hasLocalStorage()) { + if (storage.hasLocalStorage()) { s = getViewabilityData(bid); vs += s.render >= 4 ? s.ratio.toString(16) : 'F'; } else { @@ -210,8 +217,8 @@ function getVs(bid) { } function getViewabilityData(bid) { - let r = utils.getDataFromLocalStorage(STORAGE_RENDER_PREFIX + bid.adUnitCode) || 0; - let v = utils.getDataFromLocalStorage(STORAGE_VIEW_PREFIX + bid.adUnitCode) || 0; + let r = storage.getDataFromLocalStorage(STORAGE_RENDER_PREFIX + bid.adUnitCode) || 0; + let v = storage.getDataFromLocalStorage(STORAGE_VIEW_PREFIX + bid.adUnitCode) || 0; let ratio = r > 0 ? (v / r) : 0; return { render: r, @@ -310,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; } @@ -350,7 +359,7 @@ function getViewabilityTracker() { } function itIsNotHiddenByTabFocus() { - return getContext().top.document.hasFocus(); + try { return getContext().top.document.hasFocus(); } catch (e) {} } function isDefined(e) { @@ -404,9 +413,9 @@ function visibilityHandler(obj) { function registerAuction(storageID) { let value; try { - value = utils.getDataFromLocalStorage(storageID); + value = storage.getDataFromLocalStorage(storageID); value = value ? window.parseInt(value, 10) + 1 : 1; - utils.setDataInLocalStorage(storageID, value); + storage.setDataInLocalStorage(storageID, value); } catch (exc) { return false; } diff --git a/modules/etargetBidAdapter.js b/modules/etargetBidAdapter.js index ad341a136b1..5e07561044a 100644 --- a/modules/etargetBidAdapter.js +++ b/modules/etargetBidAdapter.js @@ -1,7 +1,7 @@ 'use strict'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; const BIDDER_CODE = 'etarget'; const countryMap = { diff --git a/modules/express.js b/modules/express.js index e5ea22fe272..f4a76daefdf 100644 --- a/modules/express.js +++ b/modules/express.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; +import * as utils from '../src/utils.js'; const MODULE_NAME = 'express'; diff --git a/modules/feedadBidAdapter.js b/modules/feedadBidAdapter.js index 1e995ee8914..3992f2db5e0 100644 --- a/modules/feedadBidAdapter.js +++ b/modules/feedadBidAdapter.js @@ -1,7 +1,7 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER, VIDEO} from '../src/mediaTypes'; -import {ajax} from '../src/ajax'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {ajax} from '../src/ajax.js'; /** * Version of the FeedAd bid adapter diff --git a/modules/fidelityBidAdapter.js b/modules/fidelityBidAdapter.js index f27c71d2712..baf5384fbfe 100644 --- a/modules/fidelityBidAdapter.js +++ b/modules/fidelityBidAdapter.js @@ -1,11 +1,13 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'fidelity'; const BIDDER_SERVER = 'x.fidelity-media.com'; const FIDELITY_VENDOR_ID = 408; export const spec = { code: BIDDER_CODE, + aliases: ['kubient'], + gvlid: 408, isBidRequestValid: function isBidRequestValid(bid) { return !!(bid && bid.params && bid.params.zoneid); }, @@ -26,6 +28,7 @@ export const spec = { tmax: bidderRequest.timeout, defloc: bidderRequest.refererInfo.referer, referrer: getTopWindowReferrer(), + schain: getSupplyChain(bidRequest.schain), }; setConsentParams(bidderRequest.gdprConsent, bidderRequest.uspConsent, payload); @@ -108,13 +111,37 @@ 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; } } +function getSupplyChain(schain) { + var supplyChain = ''; + if (schain != null && schain.nodes) { + supplyChain = schain.ver + ',' + schain.complete; + for (let i = 0; i < schain.nodes.length; i++) { + supplyChain += '!'; + supplyChain += (schain.nodes[i].asi) ? encodeURIComponent(schain.nodes[i].asi) : ''; + supplyChain += ','; + supplyChain += (schain.nodes[i].sid) ? encodeURIComponent(schain.nodes[i].sid) : ''; + supplyChain += ','; + supplyChain += (schain.nodes[i].hp) ? encodeURIComponent(schain.nodes[i].hp) : ''; + supplyChain += ','; + supplyChain += (schain.nodes[i].rid) ? encodeURIComponent(schain.nodes[i].rid) : ''; + supplyChain += ','; + supplyChain += (schain.nodes[i].name) ? encodeURIComponent(schain.nodes[i].name) : ''; + supplyChain += ','; + supplyChain += (schain.nodes[i].domain) ? encodeURIComponent(schain.nodes[i].domain) : ''; + } + } + return supplyChain; +} registerBidder(spec); diff --git a/modules/fintezaAnalyticsAdapter.js b/modules/fintezaAnalyticsAdapter.js index a1376c28427..8729035491f 100644 --- a/modules/fintezaAnalyticsAdapter.js +++ b/modules/fintezaAnalyticsAdapter.js @@ -1,9 +1,10 @@ -import { ajax } from '../src/ajax'; -import adapter from '../src/AnalyticsAdapter'; -import adapterManager from '../src/adapterManager'; -import * as utils from '../src/utils'; -import { parse as parseURL } from '../src/url'; +import { ajax } from '../src/ajax.js'; +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; +import { getStorageManager } from '../src/storageManager.js'; +const storage = getStorageManager(); const CONSTANTS = require('../src/constants.json'); const ANALYTICS_TYPE = 'endpoint'; @@ -27,7 +28,7 @@ function getPageInfo() { } if (document.referrer) { - pageInfo.referrerDomain = parseURL(document.referrer).hostname; + pageInfo.referrerDomain = utils.parseUrl(document.referrer).hostname; } return pageInfo; @@ -46,8 +47,8 @@ function getUniqId() { let uniq = cookies[ UNIQ_ID_KEY ]; if (!uniq) { try { - if (window.localStorage) { - uniq = window.localStorage.getItem(UNIQ_ID_KEY) || ''; + if (storage.hasLocalStorage()) { + uniq = storage.getDataFromLocalStorage(UNIQ_ID_KEY) || ''; isUniqFromLS = true; } } catch (b) {} @@ -62,7 +63,7 @@ function getUniqId() { expires.setFullYear(expires.getFullYear() + 10); try { - document.cookie = UNIQ_ID_KEY + '=' + uniq + '; path=/; expires=' + expires.toUTCString(); + storage.setCookie(UNIQ_ID_KEY, uniq, expires.toUTCString()); } catch (e) {} } @@ -90,7 +91,7 @@ function initFirstVisit() { now.setFullYear(now.getFullYear() + 20); try { - document.cookie = FIRST_VISIT_DATE + '=' + visitDate + '; path=/; expires=' + now.toUTCString(); + storage.setCookie(FIRST_VISIT_DATE, visitDate, now.toUTCString()); } catch (e) {} } @@ -110,7 +111,7 @@ function parseCookies(cookie) { let param, value; let i, j; - if (!cookie) { + if (!cookie || !storage.cookiesAreEnabled()) { return {}; } @@ -203,7 +204,7 @@ function initSession() { } try { - document.cookie = SESSION_ID + '=' + sessionId + '; path=/; expires=' + expires.toUTCString(); + storage.setCookie(SESSION_ID, sessionId, expires.toUTCString()); } catch (e) {} return { @@ -249,10 +250,10 @@ function saveTrackRequestTime() { const expires = new Date(now + SESSION_DURATION); try { - if (window.localStorage) { - window.localStorage.setItem(TRACK_TIME_KEY, now.toString()); + if (storage.hasLocalStorage()) { + storage.setDataInLocalStorage(TRACK_TIME_KEY, now.toString()); } else { - document.cookie = TRACK_TIME_KEY + '=' + now + '; path=/; expires=' + expires.toUTCString(); + storage.setCookie(TRACK_TIME_KEY, now.toString(), expires.toUTCString()); } } catch (a) {} } @@ -261,9 +262,9 @@ function getTrackRequestLastTime() { let cookie; try { - if (window.localStorage) { + if (storage.hasLocalStorage()) { return parseInt( - window.localStorage.getItem(TRACK_TIME_KEY) || 0, + storage.getDataFromLocalStorage(TRACK_TIME_KEY) || 0, 10, ); } diff --git a/modules/fluctBidAdapter.js b/modules/fluctBidAdapter.js index 6e09d9368b5..420fe04ddcb 100644 --- a/modules/fluctBidAdapter.js +++ b/modules/fluctBidAdapter.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'fluct'; const END_POINT = 'https://hb.adingo.jp/prebid'; diff --git a/modules/freeWheelAdserverVideo.js b/modules/freeWheelAdserverVideo.js index 03217b1165d..cb4bd938373 100644 --- a/modules/freeWheelAdserverVideo.js +++ b/modules/freeWheelAdserverVideo.js @@ -2,8 +2,8 @@ * This module adds Freewheel support for Video to Prebid. */ -import { registerVideoSupport } from '../src/adServerManager'; -import { getHook, submodule } from '../src/hook'; +import { registerVideoSupport } from '../src/adServerManager.js'; +import { getHook, submodule } from '../src/hook.js'; export const adpodUtils = {}; export function notifyTranslationModule(fn) { diff --git a/modules/freewheel-sspBidAdapter.js b/modules/freewheel-sspBidAdapter.js index 010b075bdbc..5e3717ce1fe 100644 --- a/modules/freewheel-sspBidAdapter.js +++ b/modules/freewheel-sspBidAdapter.js @@ -1,376 +1,422 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; - -const BIDDER_CODE = 'freewheel-ssp'; - -const PROTOCOL = getProtocol(); -const FREEWHEEL_ADSSETUP = PROTOCOL + '://ads.stickyadstv.com/www/delivery/swfIndex.php'; -const MUSTANG_URL = PROTOCOL + '://cdn.stickyadstv.com/mustang/mustang.min.js'; -const PRIMETIME_URL = PROTOCOL + '://cdn.stickyadstv.com/prime-time/'; -const USER_SYNC_URL = PROTOCOL + '://ads.stickyadstv.com/auto-user-sync'; - -function getProtocol() { - return 'https'; -} - -function isValidUrl(str) { - if (!str) { - return false; - } - - // regExp for url validation - var pattern = /^(https?|ftp|file):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/; - return pattern.test(str); -} - -function getBiggerSize(array) { - var result = [0, 0]; - for (var i = 0; i < array.length; i++) { - if (array[i][0] * array[i][1] > result[0] * result[1]) { - result = array[i]; - } - } - return result; -} - -function getBiggerSizeWithLimit(array, minSizeLimit, maxSizeLimit) { - var minSize = minSizeLimit || [0, 0]; - var maxSize = maxSizeLimit || [Number.MAX_VALUE, Number.MAX_VALUE]; - var candidates = []; - - for (var i = 0; i < array.length; i++) { - if (array[i][0] * array[i][1] >= minSize[0] * minSize[1] && array[i][0] * array[i][1] <= maxSize[0] * maxSize[1]) { - candidates.push(array[i]); - } - } - - return getBiggerSize(candidates); -} - -/* -* read the pricing extension with this format: 1.0000 -* @return {object} pricing data in format: {currency: "EUR", price:"1.000"} -*/ -function getPricing(xmlNode) { - var pricingExtNode; - var princingData = {}; - - var extensions = xmlNode.querySelectorAll('Extension'); - // Nodelist.forEach is not supported in IE and Edge - // Workaround given here https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10638731/ - Array.prototype.forEach.call(extensions, function(node) { - if (node.getAttribute('type') === 'StickyPricing') { - pricingExtNode = node; - } - }); - - if (pricingExtNode) { - var priceNode = pricingExtNode.querySelector('Price'); - princingData = { - currency: priceNode.getAttribute('currency'), - price: priceNode.textContent || priceNode.innerText - }; - } else { - utils.logWarn('PREBID - ' + BIDDER_CODE + ': Can\'t get pricing data. Is price awareness enabled?'); - } - - return princingData; -} - -function hashcode(inputString) { - var hash = 0; - var char; - if (inputString.length == 0) return hash; - for (var i = 0; i < inputString.length; i++) { - char = inputString.charCodeAt(i); - hash = ((hash << 5) - hash) + char; - hash = hash & hash; // Convert to 32bit integer - } - return hash; -} - -function getCreativeId(xmlNode) { - var creaId = ''; - var adNodes = xmlNode.querySelectorAll('Ad'); - // Nodelist.forEach is not supported in IE and Edge - // Workaround given here https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10638731/ - Array.prototype.forEach.call(adNodes, function(el) { - creaId += '[' + el.getAttribute('id') + ']'; - }); - - return creaId; -} - -/** -* returns the top most accessible window -*/ -function getTopMostWindow() { - var res = window; - - try { - while (top !== res) { - if (res.parent.location.href.length) { res = res.parent; } - } - } catch (e) {} - - return res; -} - -function getComponentId(inputFormat) { - var component = 'mustang'; // default component id - - if (inputFormat && inputFormat !== 'inbanner') { - // format identifiers are equals to their component ids. - component = inputFormat; - } - - return component; -} - -function getAPIName(componentId) { - componentId = componentId || ''; - - // remove dash in componentId to get API name - return componentId.replace('-', ''); -} - -function formatAdHTML(bid, size) { - var integrationType = bid.params.format; - - var divHtml = '
'; - - var script = ''; - var libUrl = ''; - if (integrationType && integrationType !== 'inbanner') { - libUrl = PRIMETIME_URL + getComponentId(bid.params.format) + '.min.js'; - script = getOutstreamScript(bid, size); - } else { - libUrl = MUSTANG_URL; - script = getInBannerScript(bid, size); - } - - return divHtml + - ''; -} - -var getInBannerScript = function(bid, size) { - return 'var config = {' + - ' preloadedVast:vast,' + - ' autoPlay:true' + - ' };' + - ' var ad = new window.com.stickyadstv.vpaid.Ad(document.getElementById("freewheelssp_prebid_target"),config);' + - ' (new window.com.stickyadstv.tools.ASLoader(' + bid.params.zoneId + ', \'' + getComponentId(bid.params.format) + '\')).registerEvents(ad);' + - ' ad.initAd(' + size[0] + ',' + size[1] + ',"",0,"","");'; -}; - -var getOutstreamScript = function(bid) { - var config = bid.params; - - // default placement if no placement is set - if (!config.hasOwnProperty('domId') && !config.hasOwnProperty('auto') && !config.hasOwnProperty('p') && !config.hasOwnProperty('article')) { - if (config.format === 'intext-roll') { - config.iframeMode = 'dfp'; - } else { - config.domId = 'freewheelssp_prebid_target'; - } - } - - var script = 'var config = {' + - ' preloadedVast:vast,' + - ' ASLoader:new window.com.stickyadstv.tools.ASLoader(' + bid.params.zoneId + ', \'' + getComponentId(bid.params.format) + '\')'; - - for (var key in config) { - // dont' send format parameter - // neither zone nor vastUrlParams value as Vast is already loaded - if (config.hasOwnProperty(key) && key !== 'format' && key !== 'zone' && key !== 'zoneId' && key !== 'vastUrlParams') { - script += ',' + key + ':"' + config[key] + '"'; - } - } - script += '};' + - - 'window.com.stickyadstv.' + getAPIName(bid.params.format) + '.start(config);'; - - return script; -}; - -export const spec = { - code: BIDDER_CODE, - supportedMediaTypes: ['banner', 'video'], - aliases: ['stickyadstv'], // former name for freewheel-ssp - /** - * Determines whether or not the given bid request is valid. - * - * @param {object} bid The bid to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ - isBidRequestValid: function(bid) { - return !!(bid.params.zoneId); - }, - - /** - * Make a server request from the list of BidRequests. - * - * @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server. - * @return ServerRequest Info describing the request to the server. - */ - buildRequests: function(bidRequests, bidderRequest) { - // var currency = config.getConfig(currency); - - var currentBidRequest = bidRequests[0]; - if (bidRequests.length > 1) { - utils.logMessage('Prebid.JS - freewheel bid adapter: only one ad unit is required.'); - } - - var zone = currentBidRequest.params.zoneId; - var timeInMillis = new Date().getTime(); - var keyCode = hashcode(zone + '' + timeInMillis); - var requestParams = { - reqType: 'AdsSetup', - protocolVersion: '2.0', - zoneId: zone, - componentId: getComponentId(currentBidRequest.params.format), - timestamp: timeInMillis, - pKey: keyCode - }; - - // Add GDPR flag and consent string - if (bidderRequest && bidderRequest.gdprConsent) { - requestParams._fw_gdpr_consent = bidderRequest.gdprConsent.consentString; - - if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { - requestParams._fw_gdpr = bidderRequest.gdprConsent.gdprApplies; - } - } - - if (currentBidRequest.params.gdpr_consented_providers) { - requestParams._fw_gdpr_consented_providers = currentBidRequest.params.gdpr_consented_providers; - } - - // Add CCPA consent string - if (bidderRequest && bidderRequest.uspConsent) { - requestParams._fw_us_privacy = bidderRequest.uspConsent; - } - - var vastParams = currentBidRequest.params.vastUrlParams; - if (typeof vastParams === 'object') { - for (var key in vastParams) { - if (vastParams.hasOwnProperty(key)) { - requestParams[key] = vastParams[key]; - } - } - } - - var location = (bidderRequest && bidderRequest.refererInfo) ? bidderRequest.refererInfo.referer : getTopMostWindow().location.href; - if (isValidUrl(location)) { - requestParams.loc = location; - } - - var playerSize = getBiggerSizeWithLimit(currentBidRequest.mediaTypes.banner.sizes, currentBidRequest.mediaTypes.banner.minSizeLimit, currentBidRequest.mediaTypes.banner.maxSizeLimit); - - if (playerSize[0] > 0 || playerSize[1] > 0) { - requestParams.playerSize = playerSize[0] + 'x' + playerSize[1]; - } - - return { - method: 'GET', - url: FREEWHEEL_ADSSETUP, - data: requestParams, - bidRequest: currentBidRequest - }; - }, - - /** - * Unpack the response from the server into a list of bids. - * - * @param {*} serverResponse A successful response from the server. - * @param {object} request: the built request object containing the initial bidRequest. - * @return {Bid[]} An array of bids which were nested inside the server. - */ - interpretResponse: function(serverResponse, request) { - var bidrequest = request.bidRequest; - var playerSize = getBiggerSizeWithLimit(bidrequest.mediaTypes.banner.sizes, bidrequest.mediaTypes.banner.minSizeLimit, bidrequest.mediaTypes.banner.maxSizeLimit); - - if (typeof serverResponse == 'object' && typeof serverResponse.body == 'string') { - serverResponse = serverResponse.body; - } - - var xmlDoc; - try { - var parser = new DOMParser(); - xmlDoc = parser.parseFromString(serverResponse, 'application/xml'); - } catch (err) { - utils.logWarn('Prebid.js - ' + BIDDER_CODE + ' : ' + err); - return; - } - - const princingData = getPricing(xmlDoc); - const creativeId = getCreativeId(xmlDoc); - - const topWin = getTopMostWindow(); - if (!topWin.freewheelssp_cache) { - topWin.freewheelssp_cache = {}; - } - topWin.freewheelssp_cache[bidrequest.adUnitCode] = serverResponse; - - const bidResponses = []; - - if (princingData.price) { - const bidResponse = { - requestId: bidrequest.bidId, - cpm: princingData.price, - width: playerSize[0], - height: playerSize[1], - creativeId: creativeId, - currency: princingData.currency, - netRevenue: true, - ttl: 360 - }; - - var mediaTypes = bidrequest.mediaTypes || {}; - if (mediaTypes.video) { - // bidResponse.vastXml = serverResponse; - bidResponse.mediaType = 'video'; - - var blob = new Blob([serverResponse], {type: 'application/xml'}); - bidResponse.vastUrl = window.URL.createObjectURL(blob); - } else { - bidResponse.ad = formatAdHTML(bidrequest, playerSize); - } - - bidResponses.push(bidResponse); - } - - return bidResponses; - }, - - getUserSyncs: function(syncOptions) { - if (syncOptions && syncOptions.pixelEnabled) { - return [{ - type: 'image', - url: USER_SYNC_URL - }]; - } else { - return []; - } - }, - -} -registerBidder(spec); +import * as utils from '../src/utils.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'freewheel-ssp'; + +const PROTOCOL = getProtocol(); +const FREEWHEEL_ADSSETUP = PROTOCOL + '://ads.stickyadstv.com/www/delivery/swfIndex.php'; +const MUSTANG_URL = PROTOCOL + '://cdn.stickyadstv.com/mustang/mustang.min.js'; +const PRIMETIME_URL = PROTOCOL + '://cdn.stickyadstv.com/prime-time/'; +const USER_SYNC_URL = PROTOCOL + '://ads.stickyadstv.com/auto-user-sync'; + +function getProtocol() { + return 'https'; +} + +function isValidUrl(str) { + if (!str) { + return false; + } + + // regExp for url validation + var pattern = /^(https?|ftp|file):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/; + return pattern.test(str); +} + +function getBiggerSize(array) { + var result = [0, 0]; + for (var i = 0; i < array.length; i++) { + if (array[i][0] * array[i][1] > result[0] * result[1]) { + result = array[i]; + } + } + return result; +} + +function getBiggerSizeWithLimit(array, minSizeLimit, maxSizeLimit) { + var minSize = minSizeLimit || [0, 0]; + var maxSize = maxSizeLimit || [Number.MAX_VALUE, Number.MAX_VALUE]; + var candidates = []; + + for (var i = 0; i < array.length; i++) { + if (array[i][0] * array[i][1] >= minSize[0] * minSize[1] && array[i][0] * array[i][1] <= maxSize[0] * maxSize[1]) { + candidates.push(array[i]); + } + } + + return getBiggerSize(candidates); +} + +/* +* read the pricing extension with this format: 1.0000 +* @return {object} pricing data in format: {currency: "EUR", price:"1.000"} +*/ +function getPricing(xmlNode) { + var pricingExtNode; + var princingData = {}; + + var extensions = xmlNode.querySelectorAll('Extension'); + // Nodelist.forEach is not supported in IE and Edge + // Workaround given here https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10638731/ + Array.prototype.forEach.call(extensions, function(node) { + if (node.getAttribute('type') === 'StickyPricing') { + pricingExtNode = node; + } + }); + + if (pricingExtNode) { + var priceNode = pricingExtNode.querySelector('Price'); + princingData = { + currency: priceNode.getAttribute('currency'), + price: priceNode.textContent || priceNode.innerText + }; + } else { + utils.logWarn('PREBID - ' + BIDDER_CODE + ': Can\'t get pricing data. Is price awareness enabled?'); + } + + return princingData; +} + +function hashcode(inputString) { + var hash = 0; + var char; + if (inputString.length == 0) return hash; + for (var i = 0; i < inputString.length; i++) { + char = inputString.charCodeAt(i); + hash = ((hash << 5) - hash) + char; + hash = hash & hash; // Convert to 32bit integer + } + return hash; +} + +function getCreativeId(xmlNode) { + var creaId = ''; + var adNodes = xmlNode.querySelectorAll('Ad'); + // Nodelist.forEach is not supported in IE and Edge + // Workaround given here https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10638731/ + Array.prototype.forEach.call(adNodes, function(el) { + creaId += '[' + el.getAttribute('id') + ']'; + }); + + return creaId; +} + +function getDealId(xmlNode) { + var dealId = ''; + var impNodes = xmlNode.querySelectorAll('Impression'); // Nodelist.forEach is not supported in IE and Edge + // Workaround given here https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10638731/ + + Array.prototype.forEach.call(impNodes, function (el) { + var queries = el.textContent.substring(el.textContent.indexOf('?') + 1).split('&'); + Array.prototype.forEach.call(queries, function (item) { + var split = item.split('='); + if (split[0] == 'dealId') { + dealId = split[1]; + } + }); + }); + + return dealId; +} + +/** +* returns the top most accessible window +*/ +function getTopMostWindow() { + var res = window; + + try { + while (top !== res) { + if (res.parent.location.href.length) { res = res.parent; } + } + } catch (e) {} + + return res; +} + +function getComponentId(inputFormat) { + var component = 'mustang'; // default component id + + if (inputFormat && inputFormat !== 'inbanner') { + // format identifiers are equals to their component ids. + component = inputFormat; + } + + return component; +} + +function getAPIName(componentId) { + componentId = componentId || ''; + + // remove dash in componentId to get API name + return componentId.replace('-', ''); +} + +function formatAdHTML(bid, size) { + var integrationType = bid.params.format; + + var divHtml = '
'; + + var script = ''; + var libUrl = ''; + if (integrationType && integrationType !== 'inbanner') { + libUrl = PRIMETIME_URL + getComponentId(bid.params.format) + '.min.js'; + script = getOutstreamScript(bid, size); + } else { + libUrl = MUSTANG_URL; + script = getInBannerScript(bid, size); + } + + return divHtml + + ''; +} + +var getInBannerScript = function(bid, size) { + return 'var config = {' + + ' preloadedVast:vast,' + + ' autoPlay:true' + + ' };' + + ' var ad = new window.com.stickyadstv.vpaid.Ad(document.getElementById("freewheelssp_prebid_target"),config);' + + ' (new window.com.stickyadstv.tools.ASLoader(' + bid.params.zoneId + ', \'' + getComponentId(bid.params.format) + '\')).registerEvents(ad);' + + ' ad.initAd(' + size[0] + ',' + size[1] + ',"",0,"","");'; +}; + +var getOutstreamScript = function(bid) { + var config = bid.params; + + // default placement if no placement is set + if (!config.hasOwnProperty('domId') && !config.hasOwnProperty('auto') && !config.hasOwnProperty('p') && !config.hasOwnProperty('article')) { + if (config.format === 'intext-roll') { + config.iframeMode = 'dfp'; + } else { + config.domId = 'freewheelssp_prebid_target'; + } + } + + var script = 'var config = {' + + ' preloadedVast:vast,' + + ' ASLoader:new window.com.stickyadstv.tools.ASLoader(' + bid.params.zoneId + ', \'' + getComponentId(bid.params.format) + '\')'; + + for (var key in config) { + // dont' send format parameter + // neither zone nor vastUrlParams value as Vast is already loaded + if (config.hasOwnProperty(key) && key !== 'format' && key !== 'zone' && key !== 'zoneId' && key !== 'vastUrlParams') { + script += ',' + key + ':"' + config[key] + '"'; + } + } + script += '};' + + + 'window.com.stickyadstv.' + getAPIName(bid.params.format) + '.start(config);'; + + return script; +}; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], + aliases: ['stickyadstv'], // former name for freewheel-ssp + /** + * Determines whether or not the given bid request is valid. + * + * @param {object} bid The bid to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bid) { + return !!(bid.params.zoneId); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server. + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(bidRequests, bidderRequest) { + // var currency = config.getConfig(currency); + + let buildRequest = (currentBidRequest, bidderRequest) => { + var zone = currentBidRequest.params.zoneId; + var timeInMillis = new Date().getTime(); + var keyCode = hashcode(zone + '' + timeInMillis); + var requestParams = { + reqType: 'AdsSetup', + protocolVersion: '2.0', + zoneId: zone, + componentId: 'prebid', + componentSubId: getComponentId(currentBidRequest.params.format), + timestamp: timeInMillis, + pKey: keyCode + }; + + // Add GDPR flag and consent string + if (bidderRequest && bidderRequest.gdprConsent) { + requestParams._fw_gdpr_consent = bidderRequest.gdprConsent.consentString; + + if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { + requestParams._fw_gdpr = bidderRequest.gdprConsent.gdprApplies; + } + } + + if (currentBidRequest.params.gdpr_consented_providers) { + requestParams._fw_gdpr_consented_providers = currentBidRequest.params.gdpr_consented_providers; + } + + // Add CCPA consent string + if (bidderRequest && bidderRequest.uspConsent) { + requestParams._fw_us_privacy = bidderRequest.uspConsent; + } + + var vastParams = currentBidRequest.params.vastUrlParams; + if (typeof vastParams === 'object') { + for (var key in vastParams) { + if (vastParams.hasOwnProperty(key)) { + requestParams[key] = vastParams[key]; + } + } + } + + var location = (bidderRequest && bidderRequest.refererInfo) ? bidderRequest.refererInfo.referer : getTopMostWindow().location.href; + if (isValidUrl(location)) { + requestParams.loc = location; + } + + var playerSize = []; + if (currentBidRequest.mediaTypes.video && currentBidRequest.mediaTypes.video.playerSize) { + // If mediaTypes is video, get size from mediaTypes.video.playerSize per http://prebid.org/blog/pbjs-3 + if (utils.isArray(currentBidRequest.mediaTypes.video.playerSize[0])) { + playerSize = currentBidRequest.mediaTypes.video.playerSize[0]; + } else { + playerSize = currentBidRequest.mediaTypes.video.playerSize; + } + } else if (currentBidRequest.mediaTypes.banner.sizes) { + // If mediaTypes is banner, get size from mediaTypes.banner.sizes per http://prebid.org/blog/pbjs-3 + playerSize = getBiggerSizeWithLimit(currentBidRequest.mediaTypes.banner.sizes, currentBidRequest.mediaTypes.banner.minSizeLimit, currentBidRequest.mediaTypes.banner.maxSizeLimit); + } else { + // Backward compatible code, in case size still pass by sizes in bid request + playerSize = getBiggerSize(currentBidRequest.sizes); + } + + if (playerSize[0] > 0 || playerSize[1] > 0) { + requestParams.playerSize = playerSize[0] + 'x' + playerSize[1]; + } + + return { + method: 'GET', + url: FREEWHEEL_ADSSETUP, + data: requestParams, + bidRequest: currentBidRequest + }; + }; + + return bidRequests.map(function(currentBidRequest) { + return buildRequest(currentBidRequest, bidderRequest); + }); + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @param {object} request: the built request object containing the initial bidRequest. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse, request) { + var bidrequest = request.bidRequest; + var playerSize = []; + if (bidrequest.mediaTypes.video && bidrequest.mediaTypes.video.playerSize) { + // If mediaTypes is video, get size from mediaTypes.video.playerSize per http://prebid.org/blog/pbjs-3 + if (utils.isArray(bidrequest.mediaTypes.video.playerSize[0])) { + playerSize = bidrequest.mediaTypes.video.playerSize[0]; + } else { + playerSize = bidrequest.mediaTypes.video.playerSize; + } + } else if (bidrequest.mediaTypes.banner.sizes) { + // If mediaTypes is banner, get size from mediaTypes.banner.sizes per http://prebid.org/blog/pbjs-3 + playerSize = getBiggerSizeWithLimit(bidrequest.mediaTypes.banner.sizes, bidrequest.mediaTypes.banner.minSizeLimit, bidrequest.mediaTypes.banner.maxSizeLimit); + } else { + // Backward compatible code, in case size still pass by sizes in bid request + playerSize = getBiggerSize(bidrequest.sizes); + } + + if (typeof serverResponse == 'object' && typeof serverResponse.body == 'string') { + serverResponse = serverResponse.body; + } + + var xmlDoc; + try { + var parser = new DOMParser(); + xmlDoc = parser.parseFromString(serverResponse, 'application/xml'); + } catch (err) { + utils.logWarn('Prebid.js - ' + BIDDER_CODE + ' : ' + err); + return; + } + + const princingData = getPricing(xmlDoc); + const creativeId = getCreativeId(xmlDoc); + const dealId = getDealId(xmlDoc); + + const topWin = getTopMostWindow(); + if (!topWin.freewheelssp_cache) { + topWin.freewheelssp_cache = {}; + } + topWin.freewheelssp_cache[bidrequest.adUnitCode] = serverResponse; + + const bidResponses = []; + + if (princingData.price) { + const bidResponse = { + requestId: bidrequest.bidId, + cpm: princingData.price, + width: playerSize[0], + height: playerSize[1], + creativeId: creativeId, + currency: princingData.currency, + netRevenue: true, + ttl: 360, + dealId: dealId + }; + + if (bidrequest.mediaTypes.video) { + bidResponse.vastXml = serverResponse; + bidResponse.mediaType = 'video'; + } + + bidResponse.ad = formatAdHTML(bidrequest, playerSize); + bidResponses.push(bidResponse); + } + + return bidResponses; + }, + + getUserSyncs: function(syncOptions) { + if (syncOptions && syncOptions.pixelEnabled) { + return [{ + type: 'image', + url: USER_SYNC_URL + }]; + } else { + return []; + } + }, + +} +registerBidder(spec); diff --git a/modules/gammaBidAdapter.js b/modules/gammaBidAdapter.js index 71dee0936eb..5fd3c56b2c6 100644 --- a/modules/gammaBidAdapter.js +++ b/modules/gammaBidAdapter.js @@ -1,4 +1,4 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const ENDPOINT = 'https://hb.gammaplatform.com'; const ENDPOINT_USERSYNC = 'https://cm-supply-web.gammaplatform.com'; diff --git a/modules/gamoshiBidAdapter.js b/modules/gamoshiBidAdapter.js index f41c17d5bc7..1316d74e430 100644 --- a/modules/gamoshiBidAdapter.js +++ b/modules/gamoshiBidAdapter.js @@ -1,8 +1,8 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {config} from '../src/config'; -import {Renderer} from '../src/Renderer'; -import {BANNER, VIDEO} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; +import {Renderer} from '../src/Renderer.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; const ENDPOINTS = { 'gamoshi': 'https://rtb.gamoshi.io' @@ -42,7 +42,7 @@ export const helper = { export const spec = { code: 'gamoshi', - aliases: ['gambid', 'cleanmedia', '9MediaOnline', 'adtarget'], + aliases: ['gambid', 'cleanmedia', '9MediaOnline'], supportedMediaTypes: ['banner', 'video'], isBidRequestValid: function (bid) { diff --git a/modules/gdprEnforcement.js b/modules/gdprEnforcement.js new file mode 100644 index 00000000000..6a3fbdce1f2 --- /dev/null +++ b/modules/gdprEnforcement.js @@ -0,0 +1,184 @@ +/** + * This module gives publishers extra set of features to enforce individual purposes of TCF v2 + */ + +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { hasDeviceAccess } from '../src/utils.js'; +import adapterManager, { gdprDataHandler } from '../src/adapterManager.js'; +import find from 'core-js-pure/features/array/find.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import { registerSyncInner } from '../src/adapters/bidderFactory.js'; +import { getHook } from '../src/hook.js'; +import { validateStorageEnforcement } from '../src/storageManager.js'; + +const purpose1 = 'storage'; + +let addedDeviceAccessHook = false; +let enforcementRules; + +function getGvlid() { + let gvlid; + const bidderCode = config.getCurrentBidder(); + if (bidderCode) { + const bidder = adapterManager.getBidAdapter(bidderCode); + gvlid = bidder.getSpec().gvlid; + } else { + utils.logWarn('Current module not found'); + } + return gvlid; +} + +/** + * This function takes in rules and consentData as input and validates against the consentData provided. If it returns true Prebid will allow the next call else it will log a warning + * @param {Object} rules enforcement rules set in config + * @param {Object} consentData gdpr consent data + * @returns {boolean} + */ +function validateRules(rule, consentData, currentModule, gvlid) { + // if vendor has exception => always true + if (includes(rule.vendorExceptions || [], currentModule)) { + return true; + } + // if enforcePurpose is false or purpose was granted isAllowed is true, otherwise false + const purposeAllowed = rule.enforcePurpose === false || utils.deepAccess(consentData, 'vendorData.purpose.consents.1') === true; + // if enforceVendor is false or vendor was granted isAllowed is true, otherwise false + const vendorAllowed = rule.enforceVendor === false || utils.deepAccess(consentData, `vendorData.vendor.consents.${gvlid}`) === true; + return purposeAllowed && vendorAllowed; +} + +/** + * This hook checks whether module has permission to access device or not. Device access include cookie and local storage + * @param {Function} fn reference to original function (used by hook logic) + * @param {Number=} gvlid gvlid of the module + * @param {string=} moduleName name of the module + */ +export function deviceAccessHook(fn, gvlid, moduleName, result) { + result = Object.assign({}, { + hasEnforcementHook: true + }); + if (!hasDeviceAccess()) { + utils.logWarn('Device access is disabled by Publisher'); + result.valid = false; + fn.call(this, gvlid, moduleName, result); + } else { + const consentData = gdprDataHandler.getConsentData(); + if (consentData && consentData.gdprApplies) { + if (consentData.apiVersion === 2) { + if (!gvlid) { + gvlid = getGvlid(); + } + const curModule = moduleName || config.getCurrentBidder(); + const purpose1Rule = find(enforcementRules, hasPurpose1); + let isAllowed = validateRules(purpose1Rule, consentData, curModule, gvlid); + if (isAllowed) { + result.valid = true; + fn.call(this, gvlid, moduleName, result); + } else { + utils.logWarn(`User denied Permission for Device access for ${curModule}`); + result.valid = false; + fn.call(this, gvlid, moduleName, result); + } + } else { + utils.logInfo('Enforcing TCF2 only'); + result.valid = true; + fn.call(this, gvlid, moduleName, result); + } + } else { + result.valid = true; + fn.call(this, gvlid, moduleName, result); + } + } +} + +/** + * This hook checks if a bidder has consent for user sync or not + * @param {Function} fn reference to original function (used by hook logic) + * @param {...any} args args + */ +export function userSyncHook(fn, ...args) { + const consentData = gdprDataHandler.getConsentData(); + if (consentData && consentData.gdprApplies) { + if (consentData.apiVersion === 2) { + const gvlid = getGvlid(); + const curBidder = config.getCurrentBidder(); + if (gvlid) { + const purpose1Rule = find(enforcementRules, hasPurpose1); + let isAllowed = validateRules(purpose1Rule, consentData, curBidder, gvlid); + if (isAllowed) { + fn.call(this, ...args); + } else { + utils.logWarn(`User sync not allowed for ${curBidder}`); + } + } else { + utils.logWarn(`User sync not allowed for ${curBidder}`); + } + } else { + utils.logInfo('Enforcing TCF2 only'); + fn.call(this, ...args); + } + } else { + fn.call(this, ...args); + } +} + +/** + * This hook checks if user id module is given consent or not + * @param {Function} fn reference to original function (used by hook logic) + * @param {Submodule[]} submodules Array of user id submodules + * @param {Object} consentData GDPR consent data + */ +export function userIdHook(fn, submodules, consentData) { + if (consentData && consentData.gdprApplies) { + if (consentData.apiVersion === 2) { + let userIdModules = submodules.map((submodule) => { + const gvlid = submodule.submodule.gvlid; + const moduleName = submodule.submodule.name; + if (gvlid) { + const purpose1Rule = find(enforcementRules, hasPurpose1); + let isAllowed = validateRules(purpose1Rule, consentData, moduleName, gvlid); + if (isAllowed) { + return submodule; + } else { + utils.logWarn(`User denied permission to fetch user id for ${moduleName} User id module`); + } + } else { + utils.logWarn(`User denied permission to fetch user id for ${moduleName} User id module`); + } + return undefined; + }).filter(module => module) + fn.call(this, userIdModules, {...consentData, hasValidated: true}); + } else { + utils.logInfo('Enforcing TCF2 only'); + fn.call(this, submodules, consentData); + } + } else { + fn.call(this, submodules, consentData); + } +} + +const hasPurpose1 = (rule) => { return rule.purpose === purpose1 } + +/** + * A configuration function that initializes some module variables, as well as add hooks + * @param {Object} config GDPR enforcement config object + */ +export function setEnforcementConfig(config) { + const rules = utils.deepAccess(config, 'gdpr.rules'); + if (!rules) { + utils.logWarn('GDPR enforcement rules not defined, exiting enforcement module'); + return; + } + + enforcementRules = rules; + const hasDefinedPurpose1 = find(enforcementRules, hasPurpose1); + if (hasDefinedPurpose1 && !addedDeviceAccessHook) { + addedDeviceAccessHook = true; + validateStorageEnforcement.before(deviceAccessHook, 49); + registerSyncInner.before(userSyncHook, 48); + // Using getHook as user id and gdprEnforcement are both optional modules. Using import will auto include the file in build + getHook('validateGdprEnforcement').before(userIdHook, 47); + } +} + +config.getConfig('consentManagement', config => setEnforcementConfig(config.consentManagement)); diff --git a/modules/getintentBidAdapter.js b/modules/getintentBidAdapter.js index e1652602951..134dd0b4fc9 100644 --- a/modules/getintentBidAdapter.js +++ b/modules/getintentBidAdapter.js @@ -1,5 +1,5 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { isInteger } from '../src/utils'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { isInteger } from '../src/utils.js'; const BIDDER_CODE = 'getintent'; const IS_NET_REVENUE = true; 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/googleAnalyticsAdapter.js b/modules/googleAnalyticsAdapter.js index 2e569cd7ba1..a8fc83ae62e 100644 --- a/modules/googleAnalyticsAdapter.js +++ b/modules/googleAnalyticsAdapter.js @@ -2,10 +2,10 @@ * ga.js - analytics adapter for google analytics */ -var events = require('../src/events'); -var utils = require('../src/utils'); +var events = require('../src/events.js'); +var utils = require('../src/utils.js'); var CONSTANTS = require('../src/constants.json'); -var adapterManager = require('../src/adapterManager').default; +var adapterManager = require('../src/adapterManager.js').default; var BID_REQUESTED = CONSTANTS.EVENTS.BID_REQUESTED; var BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index 33c4bea23a4..d18effa349b 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -1,11 +1,12 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { Renderer } from '../src/Renderer'; -import { VIDEO, BANNER } from '../src/mediaTypes'; +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 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'; @@ -47,14 +48,32 @@ export const spec = { const slotsMapByUid = {}; const sizeMap = {}; const bids = validBidRequests || []; + let pageKeywords = null; let reqId; bids.forEach(bid => { reqId = bid.bidderRequestId; - const {params: {uid}, adUnitCode} = bid; + 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] = {}; } @@ -81,6 +100,19 @@ export const spec = { }); }); + 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(','), @@ -89,6 +121,10 @@ export const spec = { wrapperVersion: '$prebid.version$' }; + if (pageKeywords) { + payload.keywords = JSON.stringify(pageKeywords); + } + if (bidderRequest) { if (bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { payload.u = bidderRequest.refererInfo.referer; @@ -167,6 +203,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); 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 new file mode 100644 index 00000000000..ffd6c1b250c --- /dev/null +++ b/modules/gridNMBidAdapter.js @@ -0,0 +1,234 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; +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=themediagrid'; +const TIME_TO_LIVE = 360; +const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; + +let hasSynced = false; + +const LOG_ERROR_MESS = { + noAdm: 'Bid from response has no adm parameter - ', + noPrice: 'Bid from response has no price parameter - ', + wrongContentType: 'Bid from response has wrong content_type parameter - ', + noBid: 'Array of bid objects is empty', + noPlacementCode: 'Can\'t find in requested bids the bid with auid - ', + emptyUids: 'Uids should be not empty', + emptySeatbid: 'Seatbid array from response has empty item', + emptyResponse: 'Response is empty', + hasEmptySeatbidArray: 'Response has empty seatbid array', + hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' +}; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [ VIDEO ], + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bid) { + let invalid = + !bid.params.source || !utils.isStr(bid.params.source) || + !bid.params.secid || !utils.isStr(bid.params.secid) || + !bid.params.pubid || !utils.isStr(bid.params.pubid); + + if (!invalid) { + invalid = !bid.params.video || !bid.params.video.protocols || !bid.params.video.mimes; + } + if (!invalid) { + const {protocols, mimes} = bid.params.video; + invalid = !utils.isArray(mimes) || !mimes.length || mimes.filter((it) => !(it && utils.isStr(it))).length; + if (!invalid) { + invalid = !utils.isArray(protocols) || !protocols.length || protocols.filter((it) => !(utils.isNumber(it) && it > 0 && !(it % 1))).length; + } + } + return !invalid; + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests - an array of bids + * @param {bidderRequest} bidderRequest bidder request object + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests, bidderRequest) { + const bids = validBidRequests || []; + const requests = []; + + bids.forEach(bid => { + const {params, bidderRequestId, sizes} = bid; + const payload = { + sizes: utils.parseSizesInput(sizes).join(','), + r: bidderRequestId, + 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; + } + } + + requests.push({ + method: 'POST', + url: ENDPOINT_URL + '?' + utils.parseQueryStringParameters(payload).replace(/\&$/, ''), + bid: bid, + data: params // content + }); + }); + + return requests; + }, + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @param {*} bidRequest + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse, bidRequest) { + serverResponse = serverResponse && serverResponse.body; + const bidResponses = []; + + let errorMessage; + + if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse; + else if (serverResponse.seatbid && !serverResponse.seatbid.length) { + errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; + } + + if (!errorMessage && serverResponse.seatbid) { + const serverBid = _getBidFromResponse(serverResponse.seatbid[0]); + if (serverBid) { + if (!serverBid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid); + else if (!serverBid.price) errorMessage = LOG_ERROR_MESS.noPrice + JSON.stringify(serverBid); + else if (serverBid.content_type !== 'video') errorMessage = LOG_ERROR_MESS.wrongContentType + serverBid.content_type; + if (!errorMessage) { + const bid = bidRequest.bid; + if (!serverBid.w || !serverBid.h) { + const size = utils.parseSizesInput(bid.sizes)[0].split('x'); + serverBid.w = size[0]; + serverBid.h = size[1]; + } + const bidResponse = { + requestId: bid.bidId, + bidderCode: spec.code, + cpm: serverBid.price, + width: serverBid.w, + height: serverBid.h, + creativeId: serverBid.auid || bid.bidderRequestId, + currency: 'USD', + netRevenue: false, + ttl: TIME_TO_LIVE, + dealId: serverBid.dealid, + vastXml: serverBid.adm, + mediaType: VIDEO, + adResponse: { + content: serverBid.adm + } + }; + + if (!bid.renderer && (!bid.mediaTypes || !bid.mediaTypes.video || bid.mediaTypes.video.context === 'outstream')) { + bidResponse.renderer = createRenderer(bidResponse, { + id: bid.bidId, + url: RENDERER_URL + }); + } + bidResponses.push(bidResponse); + } + } + } + if (errorMessage) utils.logError(errorMessage); + return bidResponses; + }, + getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) { + if (!hasSynced && syncOptions.pixelEnabled) { + let params = ''; + + if (gdprConsent && typeof gdprConsent.consentString === 'string') { + if (typeof gdprConsent.gdprApplies === 'boolean') { + params += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + params += `&gdpr_consent=${gdprConsent.consentString}`; + } + } + if (uspConsent) { + params += `&us_privacy=${uspConsent}`; + } + + hasSynced = true; + return { + type: 'image', + url: SYNC_URL + params + }; + } + } +}; + +function _getBidFromResponse(respItem) { + if (!respItem) { + utils.logError(LOG_ERROR_MESS.emptySeatbid); + } else if (!respItem.bid) { + utils.logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(respItem)); + } else if (!respItem.bid[0]) { + utils.logError(LOG_ERROR_MESS.noBid); + } + return respItem && respItem.bid && respItem.bid[0]; +} + +function outstreamRender (bid) { + bid.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + targetId: bid.adUnitCode, + adResponse: bid.adResponse + }); + }); +} + +function createRenderer (bid, rendererParams) { + const renderer = Renderer.install({ + id: rendererParams.id, + url: rendererParams.url, + loaded: false + }); + + try { + renderer.setRender(outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on renderer', err); + } + + return renderer; +} + +export function resetUserSync() { + hasSynced = false; +} + +export function getSyncUrl() { + return SYNC_URL; +} + +registerBidder(spec); diff --git a/modules/gridNMBidAdapter.md b/modules/gridNMBidAdapter.md new file mode 100644 index 00000000000..6decdde7f4c --- /dev/null +++ b/modules/gridNMBidAdapter.md @@ -0,0 +1,39 @@ +# Overview + +Module Name: The Grid Media Bidder Adapter +Module Type: Bidder Adapter +Maintainer: grid-tech@themediagrid.com + +# Description + +Module that connects to Grid demand source to fetch bids. +Grid bid adapter supports Banner and Video (instream and outstream). + +# Test Parameters +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + video: { + playerSize: [728, 90], + context: 'outstream' + } + }, + bids: [ + { + bidder: "gridNM", + params: { + source: 'jwp', + secid: '11', + pubid: '22', + video: { + mimes: ['video/mp4', 'video/x-ms-wmv'], + protocols: [1,2,3,4,5,6] + } + } + } + ] + } + ]; +``` diff --git a/modules/gumgumBidAdapter.js b/modules/gumgumBidAdapter.js index 894e3ac1b0c..54d845be7ad 100644 --- a/modules/gumgumBidAdapter.js +++ b/modules/gumgumBidAdapter.js @@ -1,15 +1,23 @@ -import * as utils from '../src/utils' +import * as utils from '../src/utils.js' -import { config } from '../src/config' -import includes from 'core-js/library/fn/array/includes'; -import { registerBidder } from '../src/adapters/bidderFactory' +import { BANNER, VIDEO } from '../src/mediaTypes.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 @@ -23,7 +31,7 @@ function _getBrowserParams(topWindowUrl) { function getNetworkSpeed () { const connection = window.navigator && (window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection) const Mbps = connection && (connection.downlink || connection.bandwidth) - return Mbps ? Math.round(Mbps * 1024) : null // 1 megabit -> 1024 kilobits + return Mbps ? Math.round(Mbps * 1024) : null } function getOgURL () { let ogURL = '' @@ -53,9 +61,9 @@ function _getBrowserParams(topWindowUrl) { sw: topScreen.width, sh: topScreen.height, pu: topUrl, - ce: utils.cookiesAreEnabled(), + ce: storage.cookiesAreEnabled(), dpr: topWindow.devicePixelRatio || 1, - jcsi: JSON.stringify({ t: 0, rq: 8 }), + jcsi: JSON.stringify(JCSI), ogu: getOgURL() } @@ -85,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 {}; @@ -131,11 +135,21 @@ function isBidRequestValid (bid) { params, adUnitCode } = bid; + const id = params.inScreen || params.inScreenPubID || params.inSlot || params.ICV || params.video || params.inVideo; + + if (invalidRequestIds[id]) { + utils.logWarn(`[GumGum] Please check the implementation for ${id} for the placement ${adUnitCode}`); + return false; + } switch (true) { 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; @@ -149,6 +163,41 @@ function isBidRequestValid (bid) { return true; } +/** + * Renames vid params from mediatypes.video keys + * @param {Object} attributes + * @returns {Object} + */ +function _getVidParams (attributes) { + const { + minduration: mind, + maxduration: maxd, + linearity: li, + startdelay: sd, + placement: pt, + protocols = [], + playerSize = [] + } = attributes; + const sizes = utils.parseSizesInput(playerSize); + const [viw, vih] = sizes[0] && sizes[0].split('x'); + let pr = ''; + + if (protocols.length) { + pr = protocols.join(','); + } + + return { + mind, + maxd, + li, + sd, + pt, + pr, + viw, + vih + }; +} + /** * Make a server request from the list of BidRequests. * @@ -159,20 +208,22 @@ function buildRequests (validBidRequests, bidderRequest) { const bids = []; const gdprConsent = bidderRequest && bidderRequest.gdprConsent; const uspConsent = bidderRequest && bidderRequest.uspConsent; + const timeout = config.getConfig('bidderTimeout'); + const topWindowUrl = bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer; utils._each(validBidRequests, bidRequest => { - const timeout = config.getConfig('bidderTimeout'); const { bidId, + mediaTypes = {}, params = {}, schain, transactionId, userId = {} } = bidRequest; - const data = {}; - const sizes = bidRequest.mediaTypes && bidRequest.mediaTypes.banner && bidRequest.mediaTypes.banner.sizes; - const topWindowUrl = bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer; + const bannerSizes = mediaTypes.banner && mediaTypes.banner.sizes; + let data = {}; + if (pageViewId) { - data.pv = pageViewId + data.pv = pageViewId; } if (params.bidfloor) { data.fp = params.bidfloor; @@ -193,6 +244,21 @@ function buildRequests (validBidRequests, bidderRequest) { data.ni = parseInt(params.ICV, 10); data.pi = 5; } + if (params.videoPubID) { + data = Object.assign(data, _getVidParams(mediaTypes.video)); + data.pubId = params.videoPubID; + data.pi = 7; + } + if (params.video) { + data = Object.assign(data, _getVidParams(mediaTypes.video)); + data.t = params.video; + data.pi = 7; + } + if (params.inVideo) { + data = Object.assign(data, _getVidParams(mediaTypes.video)); + data.t = params.inVideo; + data.pi = 6; + } if (gdprConsent) { data.gdprApplies = gdprConsent.gdprApplies ? 1 : 0; } @@ -212,7 +278,7 @@ function buildRequests (validBidRequests, bidderRequest) { tId: transactionId, pi: data.pi, selector: params.selector, - sizes: sizes || bidRequest.sizes, + sizes: bannerSizes, url: BID_ENDPOINT, method: 'GET', data: Object.assign(data, _getBrowserParams(topWindowUrl), _getDigiTrustQueryParams(userId), _getTradeDeskIDParam(userId)) @@ -230,6 +296,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.t || data.si || data.ni || 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, @@ -250,7 +329,8 @@ function interpretResponse (serverResponse, bidRequest) { cw: wrapper, pag: { pvid - } + }, + jcsi } = Object.assign(defaultResponse, serverResponseBody) let data = bidRequest.data || {} let product = data.pi @@ -264,6 +344,10 @@ function interpretResponse (serverResponse, bidRequest) { height = '1' } + if (jcsi) { + serverResponseBody.jcsi = JCSI + } + // update Page View ID from server response pageViewId = pvid @@ -271,7 +355,9 @@ function interpretResponse (serverResponse, bidRequest) { bidResponses.push({ // dealId: DEAL_ID, // referrer: REFERER, + ...(product === 7 && { vastXml: markup }), ad: wrapper ? getWrapperCode(wrapper, Object.assign({}, serverResponseBody, { bidRequest })) : markup, + ...(product === 6 && {ad: markup}), cpm: isTestUnit ? 0.1 : cpm, creativeId, currency: cur || 'USD', @@ -314,6 +400,7 @@ export const spec = { isBidRequestValid, buildRequests, interpretResponse, - getUserSyncs + getUserSyncs, + supportedMediaTypes: SUPPORTED_MEDIA_TYPES } registerBidder(spec) 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/hpmdnetworkBidAdapter.js b/modules/hpmdnetworkBidAdapter.js index 2642a0c9f65..5cc28ab6362 100644 --- a/modules/hpmdnetworkBidAdapter.js +++ b/modules/hpmdnetworkBidAdapter.js @@ -1,5 +1,5 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER } from '../src/mediaTypes'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; const BIDDER_CODE = 'hpmdnetwork'; const BIDDER_CODE_ALIAS = 'hpmd'; diff --git a/modules/hybridBidAdapter.js b/modules/hybridBidAdapter.js new file mode 100644 index 00000000000..5671756e0b2 --- /dev/null +++ b/modules/hybridBidAdapter.js @@ -0,0 +1,198 @@ +import * as utils from '../src/utils.js' +import { registerBidder } from '../src/adapters/bidderFactory.js' +import { auctionManager } from '../src/auctionManager.js' +import { BANNER, VIDEO } from '../src/mediaTypes.js' +import {Renderer} from '../src/Renderer.js'; +import find from 'core-js-pure/features/array/find.js'; + +const BIDDER_CODE = 'hybrid'; +const DSP_ENDPOINT = 'https://hbe198.hybrid.ai/prebidhb'; +const TRAFFIC_TYPE_WEB = 1; +const PLACEMENT_TYPE_BANNER = 1; +const PLACEMENT_TYPE_VIDEO = 2; +const TTL = 60; +const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; + +const placementTypes = { + 'banner': PLACEMENT_TYPE_BANNER, + 'video': PLACEMENT_TYPE_VIDEO +}; + +function buildBidRequests(validBidRequests) { + return utils._map(validBidRequests, function(validBidRequest) { + const params = validBidRequest.params; + const bidRequest = { + bidId: validBidRequest.bidId, + transactionId: validBidRequest.transactionId, + sizes: validBidRequest.sizes, + placement: placementTypes[params.placement], + placeId: params.placeId + }; + + return bidRequest; + }) +} + +const outstreamRender = bid => { + bid.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + sizes: [bid.width, bid.height], + targetId: bid.adUnitCode, + rendererOptions: { + showBigPlayButton: false, + showProgressBar: 'bar', + showVolume: false, + allowFullscreen: true, + skippable: false, + content: bid.vastXml + } + }); + }); +} + +const createRenderer = (bid) => { + const renderer = Renderer.install({ + targetId: bid.adUnitCode, + url: RENDERER_URL, + loaded: false + }); + + try { + renderer.setRender(outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on renderer', err); + } + + return renderer; +} + +function buildBid(bidData) { + const bid = { + requestId: bidData.bidId, + cpm: bidData.price, + width: bidData.width, + height: bidData.height, + creativeId: bidData.bidId, + currency: bidData.currency, + netRevenue: true, + ttl: TTL + }; + + if (bidData.placement === PLACEMENT_TYPE_VIDEO) { + bid.vastXml = bidData.content; + bid.mediaType = VIDEO; + + let adUnit = find(auctionManager.getAdUnits(), function (unit) { + return unit.transactionId === bidData.transactionId; + }); + + if (adUnit) { + bid.width = adUnit.mediaTypes.video.playerSize[0][0]; + bid.height = adUnit.mediaTypes.video.playerSize[0][1]; + + if (adUnit.mediaTypes.video.context === 'outstream') { + bid.renderer = createRenderer(bid); + } + } + } else { + bid.ad = bidData.content; + bid.mediaType = BANNER; + } + + return bid; +} + +function getMediaTypeFromBid(bid) { + return bid.mediaTypes && Object.keys(bid.mediaTypes)[0] +} + +function hasVideoMandatoryParams(mediaTypes) { + const isHasVideoContext = !!mediaTypes.video && (mediaTypes.video.context === 'instream' || mediaTypes.video.context === 'outstream'); + + const isPlayerSize = + !!utils.deepAccess(mediaTypes, 'video.playerSize') && + utils.isArray(utils.deepAccess(mediaTypes, 'video.playerSize')); + + return isHasVideoContext && isPlayerSize; +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], + placementTypes: placementTypes, + + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid(bid) { + return ( + !!bid.params.placeId && + !!bid.params.placement && + ( + (getMediaTypeFromBid(bid) === BANNER && bid.params.placement === 'banner') || + (getMediaTypeFromBid(bid) === VIDEO && bid.params.placement === 'video' && hasVideoMandatoryParams(bid.mediaTypes)) + ) + ); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests(validBidRequests, bidderRequest) { + const payload = { + url: bidderRequest.refererInfo.referer, + cmp: !!bidderRequest.gdprConsent, + trafficType: TRAFFIC_TYPE_WEB, + bidRequests: buildBidRequests(validBidRequests) + }; + + if (payload.cmp) { + const gdprApplies = bidderRequest.gdprConsent.gdprApplies; + if (gdprApplies !== undefined) payload['ga'] = gdprApplies; + payload['cs'] = bidderRequest.gdprConsent.consentString; + } + + const payloadString = JSON.stringify(payload); + return { + method: 'POST', + url: DSP_ENDPOINT, + data: payloadString, + options: { + contentType: 'application/json' + } + } + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse, bidRequest) { + let bidRequests = JSON.parse(bidRequest.data).bidRequests; + const serverBody = serverResponse.body; + + if (serverBody && serverBody.bids && utils.isArray(serverBody.bids)) { + return utils._map(serverBody.bids, function(bid) { + let rawBid = find(bidRequests, function (item) { + return item.bidId === bid.bidId; + }); + bid.placement = rawBid.placement; + bid.transactionId = rawBid.transactionId; + bid.placeId = rawBid.placeId; + return buildBid(bid); + }); + } else { + return []; + } + } + +} +registerBidder(spec); diff --git a/modules/hybridBidAdapter.md b/modules/hybridBidAdapter.md new file mode 100644 index 00000000000..245f010970a --- /dev/null +++ b/modules/hybridBidAdapter.md @@ -0,0 +1,54 @@ +# Overview + + +**Module Name**: Hybrid.ai Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: prebid@hybrid.ai + +# Description + +You can use this adapter to get a bid from Hybrid.ai + +About us: https://hybrid.ai + +## Sample Banner Ad Unit + +```js +var adUnits = [{ + code: 'banner_ad_unit', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + bids: [{ + bidder: "hybrid", + params: { + placement: "banner", // required + placeId: "5af45ad34d506ee7acad0c26" // required + } + }] +}]; +``` + +## Sample Video Ad Unit + +```js +var adUnits = [{ + code: 'video_ad_unit', + mediaTypes: { + video: { + context: 'outstream', // required + playerSize: [640, 480] // required + } + }, + bids: [{ + bidder: 'hybrid', + params: { + placement: "video", // required + placeId: "5af45ad34d506ee7acad0c26" // required + } + }] +}]; +``` + diff --git a/modules/iasBidAdapter.js b/modules/iasBidAdapter.js index 3115daeb56b..733c123e769 100644 --- a/modules/iasBidAdapter.js +++ b/modules/iasBidAdapter.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'ias'; diff --git a/modules/id5IdSystem.js b/modules/id5IdSystem.js index 6ed56b89d6d..ae3c7e55863 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' -import {ajax} from '../src/ajax'; -import {submodule} from '../src/hook'; +import * as utils from '../src/utils.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,6 +25,13 @@ export const id5IdSubmodule = { * @type {string} */ name: 'id5Id', + + /** + * Vendor id of ID5 + * @type {Number} + */ + gvlid: GVLID, + /** * decode the stored id value for passing to bid requests * @function decode @@ -23,41 +39,114 @@ export const id5IdSubmodule = { * @returns {(Object|undefined)} */ decode(value) { - return (value && typeof value['ID5ID'] === 'string') ? { 'id5id': value['ID5ID'] } : undefined; + if (value && typeof value.ID5ID === 'string') { + // don't lose our legacy value from cache + return { 'id5id': value.ID5ID }; + } else if (value && typeof value.universal_uid === 'string') { + return { 'id5id': value.universal_uid }; + } else { + return undefined; + } }, + /** * 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) { - ajax(url, response => { - let responseObj; - if (response) { - try { - responseObj = JSON.parse(response); - } catch (error) { - utils.logError(error); + const callbacks = { + success: response => { + let responseObj; + if (response) { + try { + responseObj = JSON.parse(response); + resetNb(configParams); + } catch (error) { + utils.logError(error); + } } + callback(responseObj); + }, + error: error => { + utils.logError(`id5Id: ID fetch encountered an error`, error); + callback(); } - callback(responseObj); - }, 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 ffbfe466035..c516c06d11a 100644 --- a/modules/identityLinkIdSystem.js +++ b/modules/identityLinkIdSystem.js @@ -7,7 +7,7 @@ import * as utils from '../src/utils.js' import {ajax} from '../src/ajax.js'; -import {submodule} from '../src/hook'; +import {submodule} from '../src/hook.js'; /** @type {Submodule} */ export const identityLinkSubmodule = { @@ -42,38 +42,48 @@ export const identityLinkSubmodule = { // 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 : ''}`; let resp; - // if ats library is initialised, use it to retrieve envelope. If not use standard third party endpoint - if (window.ats) { - 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); } }); - } - } else { - resp = function (callback) { + } else { getEnvelope(url, callback); } - } + }; + return {callback: resp}; } -} +}; // return envelope from third party endpoint function getEnvelope(url, callback) { - ajax(url, response => { - let responseObj; - if (response) { - try { - responseObj = JSON.parse(response); - } catch (error) { - utils.logError(error); + utils.logInfo('A 3P retrieval is attempted!'); + const callbacks = { + success: response => { + let responseObj; + if (response) { + try { + responseObj = JSON.parse(response); + } catch (error) { + utils.logInfo(error); + } } + callback((responseObj && responseObj.envelope) ? responseObj.envelope : ''); + }, + error: error => { + utils.logInfo(`identityLink: ID fetch encountered an error`, error); + callback(); } - callback(responseObj.envelope); - }, undefined, {method: 'GET', withCredentials: true}); + }; + ajax(url, callbacks, undefined, {method: 'GET', withCredentials: true}); } submodule('userId', identityLinkSubmodule); diff --git a/modules/imonomyBidAdapter.js b/modules/imonomyBidAdapter.js index 91086c2dd32..b9205943f65 100644 --- a/modules/imonomyBidAdapter.js +++ b/modules/imonomyBidAdapter.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'imonomy'; const ENDPOINT = 'https://b.imonomy.com/openrtb/hb/00000'; diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js index cd7ab1bd50b..3c000258ede 100644 --- a/modules/improvedigitalBidAdapter.js +++ b/modules/improvedigitalBidAdapter.js @@ -1,13 +1,16 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { config } from '../src/config'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import {Renderer} from '../src/Renderer.js'; const BIDDER_CODE = 'improvedigital'; +const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js'; export const spec = { - version: '6.0.1', + version: '7.1.0', code: BIDDER_CODE, + gvlid: 253, aliases: ['id'], supportedMediaTypes: [BANNER, NATIVE, VIDEO], @@ -43,6 +46,10 @@ export const spec = { requestParameters.gdpr = bidderRequest.gdprConsent.consentString; } + if (bidderRequest && bidderRequest.uspConsent) { + requestParameters.usPrivacy = bidderRequest.uspConsent; + } + if (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { requestParameters.referrer = bidderRequest.refererInfo.referer; } @@ -57,7 +64,7 @@ export const spec = { if (requestObj.errors && requestObj.errors.length > 0) { utils.logError('ID WARNING 0x01'); } - + requestObj.requests.forEach(request => request.bidderRequest = bidderRequest); return requestObj.requests; }, @@ -67,7 +74,7 @@ export const spec = { * @param {*} serverResponse A successful response from the server. * @return {Bid[]} An array of bids which were nested inside the server. */ - interpretResponse: function (serverResponse, bidRequest) { + interpretResponse: function (serverResponse, {bidderRequest}) { const bids = []; utils._each(serverResponse.body.bid, function (bidObject) { if (!bidObject.price || bidObject.price === null || @@ -75,7 +82,7 @@ export const spec = { (!bidObject.adm && !bidObject.native)) { return; } - + const bidRequest = utils.getBidRequest(bidObject.id, [bidderRequest]); const bid = {}; if (bidObject.native) { @@ -90,6 +97,14 @@ export const spec = { } else if (bidObject.ad_type && bidObject.ad_type === 'video') { bid.vastXml = bidObject.adm; bid.mediaType = VIDEO; + if (isOutstreamVideo(bidRequest)) { + bid.adResponse = { + content: bid.vastXml, + height: bidObject.h, + width: bidObject.w + }; + bid.renderer = createRenderer(bidRequest); + } } else { // Banner let nurl = ''; @@ -108,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) && @@ -116,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]; } @@ -132,10 +147,6 @@ export const spec = { if (!bid.width || !bid.height) { bid.width = 1; bid.height = 1; - if (bidRequest.sizes) { - bid.width = bidRequest.sizes[0][0]; - bid.height = bidRequest.sizes[0][1]; - } } bids.push(bid); @@ -171,9 +182,47 @@ 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' || (mediaTypes.length === 1 && videoMediaType && context !== 'outstream'); +} + +function isOutstreamVideo(bid) { const videoMediaType = utils.deepAccess(bid, 'mediaTypes.video'); const context = utils.deepAccess(bid, 'mediaTypes.video.context'); - return bid.mediaType === 'video' || (videoMediaType && context !== 'outstream'); + return videoMediaType && context === 'outstream'; +} + +function outstreamRender(bid) { + bid.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + sizes: [bid.width, bid.height], + targetId: bid.adUnitCode, + adResponse: bid.adResponse, + 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: utils.deepAccess(bidRequest, 'renderer.options'), + adUnitCode: bidRequest.adUnitCode + }); + try { + renderer.setRender(outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on renderer', err); + } + return renderer; } function getNormalizedBidRequest(bid) { @@ -213,7 +262,7 @@ function getNormalizedBidRequest(bid) { normalizedBidRequest.keyValues = keyValues; } - if (config.getConfig('improvedigital.usePrebidSizes') === true && !isInstreamVideo(bid) && bid.sizes && bid.sizes.length > 0) { + if (config.getConfig('improvedigital.usePrebidSizes') === true && !isInstreamVideo(bid) && !isOutstreamVideo(bid) && bid.sizes && bid.sizes.length > 0) { normalizedBidRequest.format = bid.sizes; } else if (singleSizeFilter && singleSizeFilter.w && singleSizeFilter.h) { normalizedBidRequest.size = {}; @@ -343,7 +392,7 @@ export function ImproveDigitalAdServerJSClient(endPoint) { AD_SERVER_BASE_URL: 'ice.360yield.com', END_POINT: endPoint || 'hb', AD_SERVER_URL_PARAM: 'jsonp=', - CLIENT_VERSION: 'JS-6.2.0', + CLIENT_VERSION: 'JS-6.3.0', MAX_URL_LENGTH: 2083, ERROR_CODES: { MISSING_PLACEMENT_PARAMS: 2, @@ -497,6 +546,9 @@ export function ImproveDigitalAdServerJSClient(endPoint) { if (requestParameters.gdpr || requestParameters.gdpr === 0) { impressionBidRequestObject.gdpr = requestParameters.gdpr; } + if (requestParameters.usPrivacy) { + impressionBidRequestObject.us_privacy = requestParameters.usPrivacy; + } if (requestParameters.schain) { impressionBidRequestObject.schain = requestParameters.schain; } diff --git a/modules/innityBidAdapter.js b/modules/innityBidAdapter.js index ca281cd746b..aae79818daf 100644 --- a/modules/innityBidAdapter.js +++ b/modules/innityBidAdapter.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'innity'; const ENDPOINT = 'https://as.innity.com/synd/'; diff --git a/modules/inskinBidAdapter.js b/modules/inskinBidAdapter.js new file mode 100644 index 00000000000..2a55b5280db --- /dev/null +++ b/modules/inskinBidAdapter.js @@ -0,0 +1,374 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; + +const BIDDER_CODE = 'inskin'; + +const CONFIG = { + 'inskin': { + 'BASE_URI': 'https://mfad.inskinad.com/api/v2' + } +}; + +export const spec = { + code: BIDDER_CODE, + + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bid) { + return !!(bid.params.networkId && bid.params.siteId); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @param {bidderRequest} - the full bidder request object + * @return ServerRequest Info describing the request to the server. + */ + + buildRequests: function(validBidRequests, bidderRequest) { + // Do we need to group by bidder? i.e. to make multiple requests for + // different endpoints. + + let ret = { + method: 'POST', + url: '', + data: '', + bidRequest: [] + }; + + if (validBidRequests.length < 1) { + return ret; + } + + let ENDPOINT_URL; + + const data = Object.assign({ + placements: [], + time: Date.now(), + user: {}, + url: bidderRequest.refererInfo.referer, + enableBotFiltering: true, + includePricingData: true, + parallel: true + }, validBidRequests[0].params); + + data.keywords = data.keywords || []; + const restrictions = []; + + if (bidderRequest && bidderRequest.gdprConsent) { + data.consent = { + gdprVendorId: 150, + gdprConsentString: bidderRequest.gdprConsent.consentString, + // 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 => { + let config = CONFIG[bid.bidder]; + ENDPOINT_URL = config.BASE_URI; + + const placement = Object.assign({ + divName: bid.bidId, + adTypes: bid.adTypes || getSize(bid.sizes), + eventIds: [40, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295] + }, bid.params); + + 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); + } + }); + + ret.data = JSON.stringify(data); + ret.bidRequest = validBidRequests; + ret.url = ENDPOINT_URL; + + return ret; + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse, bidRequest) { + let bid; + let bids; + let bidId; + let bidObj; + let bidResponses = []; + let bidsMap = {}; + + bids = bidRequest.bidRequest; + + serverResponse = (serverResponse || {}).body; + for (let i = 0; i < bids.length; i++) { + bid = {}; + bidObj = bids[i]; + bidId = bidObj.bidId; + + bidsMap[bidId] = bidObj; + + if (serverResponse) { + const decision = serverResponse.decisions && serverResponse.decisions[bidId]; + const data = decision && decision.contents && decision.contents[0] && decision.contents[0].data; + const pubCPM = data && data.customData && data.customData.pubCPM; + const clearPrice = decision && decision.pricing && decision.pricing.clearPrice; + const price = pubCPM || clearPrice; + + if (decision && price) { + decision.impressionUrl += ('&property:pubcpm=' + price); + bidObj.price = price; + + bid.requestId = bidId; + bid.cpm = price; + bid.width = decision.width; + bid.height = decision.height; + bid.ad = retrieveAd(bidId, decision); + bid.currency = 'USD'; + bid.creativeId = decision.adId; + bid.ttl = 360; + bid.netRevenue = true; + + bidResponses.push(bid); + } + } + } + + if (bidResponses.length) { + window.addEventListener('message', function(e) { + if (!e.data || e.data.from !== 'ism-bid') { + return; + } + + const decision = serverResponse.decisions && serverResponse.decisions[e.data.bidId]; + if (!decision) { + return; + } + + 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 + }; + const script = document.createElement('script'); + script.src = 'https://cdn.inskinad.com/isfe/publishercode/' + bidsMap[e.data.bidId].params.siteId + '/default.js?autoload&id=' + id; + document.getElementsByTagName('head')[0].appendChild(script); + }); + } + + return bidResponses; + }, + + getUserSyncs: function(syncOptions) { + const userSyncs = []; + + if (syncOptions.pixelEnabled) { + userSyncs.push({ + type: 'image', + url: 'https://e.serverbid.com/udb/9969/match?redir=https%3A%2F%2Fmfad.inskinad.com%2Fudb%2F9874%2Fpool%2Fset%2Fi.gif%3FpoolId%3D9969%26poolKey%3D' + }); + userSyncs.push({ + type: 'image', + url: 'https://ssum.casalemedia.com/usermatchredir?s=185638&cb=https%3A%2F%2Fmfad.inskinad.com%2Fudb%2F9874%2Fsync%2Fi.gif%3FpartnerId%3D1%26userId%3D' + }); + } + + if (syncOptions.iframeEnabled) { + userSyncs.push({ + type: 'iframe', + url: 'https://ssum-sec.casalemedia.com/usermatch?s=184665&cb=https%3A%2F%2Fmfad.inskinad.com%2Fudb%2F9874%2Fsync%2Fi.gif%3FpartnerId%3D1%26userId%3D' + }); + } + + return userSyncs; + } +}; + +const sizeMap = [ + null, + '120x90', + '120x90', + '468x60', + '728x90', + '300x250', + '160x600', + '120x600', + '300x100', + '180x150', + '336x280', + '240x400', + '234x60', + '88x31', + '120x60', + '120x240', + '125x125', + '220x250', + '250x250', + '250x90', + '0x0', + '200x90', + '300x50', + '320x50', + '320x480', + '185x185', + '620x45', + '300x125', + '800x250' +]; + +sizeMap[77] = '970x90'; +sizeMap[123] = '970x250'; +sizeMap[43] = '300x600'; + +function getSize(sizes) { + const result = []; + sizes.forEach(function(size) { + const index = sizeMap.indexOf(size[0] + 'x' + size[1]); + if (index >= 0) { + result.push(index); + } + }); + return result; +} + +function retrieveAd(bidId, decision) { + return "`; +} + +function createRenderTag(width, height, vast) { + return ``; +}; + +function newRenderer(bidId, playerUrl) { + const renderer = Renderer.install({ + id: bidId, + url: playerUrl, + loaded: false + }); + try { + renderer.setRender(outstreamRender); + } catch (err) { + utils.logWarn('renderer.setRender Error', err); + } + return renderer; +} + +function outstreamRender(bid) { + bid.renderer.push(() => { + window.RelaidoPlayer.renderAd({ + adUnitCode: bid.adUnitCode, + width: bid.width, + height: bid.height, + vastXml: bid.vastXml, + mediaType: bid.mediaType, + }); + }); +} + +function receiveMessage() { + window.addEventListener('message', setUuid); +} + +function setUuid(e) { + if (utils.isPlainObject(e.data) && e.data.relaido_uuid) { + storage.setDataInLocalStorage(UUID_KEY, e.data.relaido_uuid); + window.removeEventListener('message', setUuid); + } +} + +function isBannerValid(bid) { + if (!isMobile()) { + return false; + } + const sizes = utils.deepAccess(bid, 'mediaTypes.banner.sizes'); + if (sizes && utils.isArray(sizes)) { + if (utils.isArray(sizes[0])) { + const width = sizes[0][0]; + const height = sizes[0][1]; + if (width >= 300 && height >= 250) { + return true; + } + } + } + return false; +} + +function isVideoValid(bid) { + const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize'); + if (playerSize && utils.isArray(playerSize) && playerSize.length > 0) { + const context = utils.deepAccess(bid, 'mediaTypes.video.context'); + if (context && context === 'outstream') { + return true; + } + } + return false; +} + +function hasUuid() { + return !!storage.getDataFromLocalStorage(UUID_KEY); +} + +function getUuid() { + return storage.getDataFromLocalStorage(UUID_KEY) || ''; +} + +export function isMobile() { + const ua = navigator.userAgent; + if (ua.indexOf('iPhone') > -1 || ua.indexOf('iPod') > -1 || (ua.indexOf('Android') > -1 && ua.indexOf('Tablet') == -1)) { + return true; + } + return false; +} + +function getMediaType(bid) { + if (hasVideoMediaType(bid)) { + return VIDEO; + } else if (hasBannerMediaType(bid)) { + return BANNER; + } + return ''; +} + +function hasBannerMediaType(bid) { + return !!utils.deepAccess(bid, 'mediaTypes.banner'); +} + +function hasVideoMediaType(bid) { + return !!utils.deepAccess(bid, 'mediaTypes.video'); +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs: getUserSyncs, + onBidWon, + onTimeout +} + +registerBidder(spec); diff --git a/modules/relaidoBidAdapter.md b/modules/relaidoBidAdapter.md new file mode 100644 index 00000000000..459f772c66b --- /dev/null +++ b/modules/relaidoBidAdapter.md @@ -0,0 +1,48 @@ +# Overview + +``` +Module Name: Relaido Bidder Adapter +Module Type: Bidder Adapter +Maintainer: video-dev@cg.relaido.co.jp +``` + +# Description + +Connects to Relaido exchange for bids. + +Relaido bid adapter supports Outstream Video. + +# Test Parameters + +```javascript + var adUnits=[{ + code: 'banner-ad-div', + mediaTypes: { + banner: { + sizes: [ + [300, 250] + ] + } + }, + bids: [{ + bidder: 'relaido', + params: { + placementId: '9900' + } + }] + },{ + code: 'video-ad-player', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 360] + } + }, + bids: [{ + bidder: 'relaido', + params: { + placementId: '9900' + } + }] + }]; +``` \ No newline at end of file diff --git a/modules/reloadBidAdapter.js b/modules/reloadBidAdapter.js index d99de5d6c53..94ea4be281f 100644 --- a/modules/reloadBidAdapter.js +++ b/modules/reloadBidAdapter.js @@ -1,8 +1,12 @@ import { registerBidder } - from '../src/adapters/bidderFactory'; -import * as utils from '../src/utils'; + from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const storage = getStorageManager(); + const BIDDER_CODE = 'reload'; const VERSION_ADAPTER = '1.10'; export const spec = { @@ -390,14 +394,14 @@ function ReloadClientTool(args) { var stgFileStr = JSON.stringify(stgFileObj); - localStorage.setItem(name, stgFileStr); + storage.setDataInLocalStorage(name, stgFileStr); return true; } function _getItem (name) { try { - var obStgFileStr = localStorage.getItem(name); + var obStgFileStr = storage.getDataFromLocalStorage(name); if (obStgFileStr === null) return null; var stgFileObj = JSON.parse(obStgFileStr); diff --git a/modules/resultsmediaBidAdapter.js b/modules/resultsmediaBidAdapter.js new file mode 100644 index 00000000000..beb9991e1e2 --- /dev/null +++ b/modules/resultsmediaBidAdapter.js @@ -0,0 +1,269 @@ +'use strict'; + +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; + +function ResultsmediaAdapter() { + this.code = 'resultsmedia'; + this.aliases = ['resultsmedia']; + this.supportedMediaTypes = [VIDEO, BANNER]; + + let SUPPORTED_VIDEO_PROTOCOLS = [2, 3, 5, 6]; + let SUPPORTED_VIDEO_MIMES = ['video/mp4']; + let SUPPORTED_VIDEO_PLAYBACK_METHODS = [1, 2, 3, 4]; + let SUPPORTED_VIDEO_DELIVERY = [1]; + let SUPPORTED_VIDEO_API = [1, 2, 5]; + let slotsToBids = {}; + let that = this; + let version = '2.1'; + + this.isBidRequestValid = function (bid) { + return !!(bid.params && bid.params.zoneId); + }; + + this.getUserSyncs = function (syncOptions, responses, gdprConsent) { + return []; + }; + + function frameImp(BRs, bidderRequest) { + var impList = []; + var isSecure = 0; + if (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.stack.length) { + // clever trick to get the protocol + var el = document.createElement('a'); + el.href = bidderRequest.refererInfo.stack[0]; + isSecure = (el.protocol == 'https:') ? 1 : 0; + } + for (var i = 0; i < BRs.length; i++) { + slotsToBids[BRs[i].adUnitCode] = BRs[i]; + var impObj = {}; + impObj.id = BRs[i].adUnitCode; + impObj.secure = isSecure; + + if (utils.deepAccess(BRs[i], 'mediaTypes.banner') || utils.deepAccess(BRs[i], 'mediaType') === 'banner') { + let banner = frameBanner(BRs[i]); + if (banner) { + impObj.banner = banner; + } + } + if (utils.deepAccess(BRs[i], 'mediaTypes.video') || utils.deepAccess(BRs[i], 'mediaType') === 'video') { + impObj.video = frameVideo(BRs[i]); + } + if (!(impObj.banner || impObj.video)) { + continue; + } + impObj.ext = frameExt(BRs[i]); + impList.push(impObj); + } + return impList; + } + + function frameSite(bidderRequest) { + var site = { + domain: '', + page: '', + ref: '' + } + if (bidderRequest && bidderRequest.refererInfo) { + var ri = bidderRequest.refererInfo; + site.ref = ri.referer; + + if (ri.stack.length) { + site.page = ri.stack[ri.stack.length - 1]; + + // clever trick to get the domain + var el = document.createElement('a'); + el.href = ri.stack[0]; + site.domain = el.hostname; + } + } + return site; + } + + function frameDevice() { + return { + ua: navigator.userAgent, + ip: '', // Empty Ip string is required, server gets the ip from HTTP header + dnt: utils.getDNT() ? 1 : 0, + } + } + + function getValidSizeSet(dimensionList) { + let w = parseInt(dimensionList[0]); + let h = parseInt(dimensionList[1]); + // clever check for NaN + if (! (w !== w || h !== h)) { // eslint-disable-line + return [w, h]; + } + return false; + } + + function frameBanner(adUnit) { + // adUnit.sizes is scheduled to be deprecated, continue its support but prefer adUnit.mediaTypes.banner + var sizeList = adUnit.sizes; + if (adUnit.mediaTypes && adUnit.mediaTypes.banner) { + sizeList = adUnit.mediaTypes.banner.sizes; + } + var sizeStringList = utils.parseSizesInput(sizeList); + var format = []; + sizeStringList.forEach(function(size) { + if (size) { + var dimensionList = getValidSizeSet(size.split('x')); + if (dimensionList) { + format.push({ + 'w': dimensionList[0], + 'h': dimensionList[1], + }); + } + } + }); + if (format.length) { + return { + 'format': format + }; + } + + return false; + } + + function frameVideo(bid) { + var size = []; + if (utils.deepAccess(bid, 'mediaTypes.video.playerSize')) { + var dimensionSet = bid.mediaTypes.video.playerSize; + if (utils.isArray(bid.mediaTypes.video.playerSize[0])) { + dimensionSet = bid.mediaTypes.video.playerSize[0]; + } + var validSize = getValidSizeSet(dimensionSet) + if (validSize) { + size = validSize; + } + } + return { + mimes: utils.deepAccess(bid, 'mediaTypes.video.mimes') || SUPPORTED_VIDEO_MIMES, + protocols: utils.deepAccess(bid, 'mediaTypes.video.protocols') || SUPPORTED_VIDEO_PROTOCOLS, + w: size[0], + h: size[1], + startdelay: utils.deepAccess(bid, 'mediaTypes.video.startdelay') || 0, + skip: utils.deepAccess(bid, 'mediaTypes.video.skip') || 0, + playbackmethod: utils.deepAccess(bid, 'mediaTypes.video.playbackmethod') || SUPPORTED_VIDEO_PLAYBACK_METHODS, + delivery: utils.deepAccess(bid, 'mediaTypes.video.delivery') || SUPPORTED_VIDEO_DELIVERY, + api: utils.deepAccess(bid, 'mediaTypes.video.api') || SUPPORTED_VIDEO_API, + } + } + + function frameExt(bid) { + return { + bidder: { + zoneId: bid.params['zoneId'] + } + } + } + + function frameBid(BRs, bidderRequest) { + let bid = { + id: BRs[0].bidderRequestId, + imp: frameImp(BRs, bidderRequest), + site: frameSite(bidderRequest), + device: frameDevice(), + user: { + ext: { + consent: utils.deepAccess(bidderRequest, 'gdprConsent.gdprApplies') ? bidderRequest.gdprConsent.consentString : '' + } + }, + at: 1, + tmax: 1000, + regs: { + ext: { + gdpr: utils.deepAccess(bidderRequest, 'gdprConsent.gdprApplies') ? Boolean(bidderRequest.gdprConsent.gdprApplies & 1) : false + } + } + }; + if (BRs[0].schain) { + bid.source = { + 'ext': { + 'schain': BRs[0].schain + } + } + } + return bid; + } + + function getFirstParam(key, validBidRequests) { + for (let i = 0; i < validBidRequests.length; i++) { + if (validBidRequests[i].params && validBidRequests[i].params[key]) { + return validBidRequests[i].params[key]; + } + } + } + + this.buildRequests = function (BRs, bidderRequest) { + let fallbackZoneId = getFirstParam('zoneId', BRs); + if (fallbackZoneId === undefined || BRs.length < 1) { + return []; + } + + var uri = 'https://bid306.rtbsrv.com/bidder/?bid=3mhdom&zoneId=' + fallbackZoneId; + + var fat = /(^v|(\.0)+$)/gi; + var prebidVersion = '$prebid.version$'; + uri += '&hbv=' + prebidVersion.replace(fat, '') + ',' + version.replace(fat, ''); + + var bidRequest = frameBid(BRs, bidderRequest); + if (!bidRequest.imp.length) { + return {}; + } + + return { + method: 'POST', + url: uri, + data: JSON.stringify(bidRequest) + }; + }; + + this.interpretResponse = function (serverResponse) { + let responses = serverResponse.body || []; + let bids = []; + let i = 0; + + if (responses.seatbid) { + let temp = []; + for (i = 0; i < responses.seatbid.length; i++) { + for (let j = 0; j < responses.seatbid[i].bid.length; j++) { + temp.push(responses.seatbid[i].bid[j]); + } + } + responses = temp; + } + + for (i = 0; i < responses.length; i++) { + let bid = responses[i]; + let bidRequest = slotsToBids[bid.impid]; + let bidResponse = { + requestId: bidRequest.id, + bidderCode: that.code, + cpm: parseFloat(bid.price), + width: bid.w, + height: bid.h, + creativeId: bid.crid, + currency: 'USD', + netRevenue: true, + ttl: 350 + }; + + if (bidRequest.mediaTypes && bidRequest.mediaTypes.video) { + bidResponse.vastUrl = bid.adm; + bidResponse.mediaType = 'video'; + bidResponse.ttl = 600; + } else { + bidResponse.ad = bid.adm; + } + bids.push(bidResponse); + } + + return bids; + }; +} + +export const spec = new ResultsmediaAdapter(); +registerBidder(spec); diff --git a/modules/resultsmediaBidAdapter.md b/modules/resultsmediaBidAdapter.md new file mode 100644 index 00000000000..0b65264c8e4 --- /dev/null +++ b/modules/resultsmediaBidAdapter.md @@ -0,0 +1,47 @@ +# Overview + +``` +Module Name: ResultsMedia (resultsmedia.com) Bidder Adapter +Module Type: Bidder Adapter +Maintainer: prebid@resultsmedia.COM +``` + +# Description + +Prebid adapter for ResultsMedia RTB. Requires approval and account setup. + +# Test Parameters + +## Web +``` + var adUnits = [{ + code: 'banner-ad-div', + mediaTypes: { + banner: { + sizes: [ + [300, 200] // banner sizes + ], + } + }, + bids: [{ + bidder: 'resultsmedia', + params: { + zoneId: 9999 + } + }] + }, { + code: 'video-ad-player', + mediaTypes: { + video: { + context: 'instream', // or 'outstream' + playerSize: [640, 480] // video player size + } + }, + bids: [{ + bidder: 'resultsmedia', + params: { + zoneId: 9999 + } + }] + }]; +``` \ No newline at end of file diff --git a/modules/revcontentBidAdapter.js b/modules/revcontentBidAdapter.js index 8adc166caac..b429f94eae0 100644 --- a/modules/revcontentBidAdapter.js +++ b/modules/revcontentBidAdapter.js @@ -1,9 +1,8 @@ // jshint esversion: 6, es3: false, node: true 'use strict'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import * as utils from '../src/utils'; -import {ajax} from '../src/ajax'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; const BIDDER_CODE = 'revcontent'; const NATIVE_PARAMS = { @@ -56,6 +55,11 @@ export const spec = { endpoint = endpoint + '&widgetId=' + widgetId; } + let bidfloor = 0.1; + if (!isNaN(validBidRequests[0].params.bidfloor) && validBidRequests[0].params.bidfloor > 0) { + bidfloor = validBidRequests[0].params.bidfloor; + } + const imp = validBidRequests.map((bid, id) => { if (bid.hasOwnProperty('nativeParams')) { const assets = utils._map(bid.nativeParams, (bidParams, key) => { @@ -98,15 +102,15 @@ export const spec = { ver: '1.1', context: 2, contextsubtype: 21, - plcmttype: 4, - plcmtcnt: 4, + plcmttype: 1, + plcmtcnt: 1, assets: assets }, ver: '1.1', battr: [1, 3, 8, 11, 17] }, instl: 0, - bidfloor: 0.1, + bidfloor: bidfloor, secure: '1' }; } @@ -150,7 +154,6 @@ export const spec = { 'IAB26-4' ] }; - serverRequests.push({ method: 'POST', options: { @@ -167,7 +170,6 @@ export const spec = { if (!serverResponse.body) { return; } - const seatbid = serverResponse.body.seatbid[0]; const bidResponses = []; @@ -220,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; } }; @@ -277,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/revcontentBidAdapter.md b/modules/revcontentBidAdapter.md index 8f9e5ed48c7..d9f44e8036c 100644 --- a/modules/revcontentBidAdapter.md +++ b/modules/revcontentBidAdapter.md @@ -53,7 +53,8 @@ Revcontent Adpater userId: 69565, // Required widgetId: 599995, // Optional domain: 'test.com', // Optional - Default referral hostname - endpoint: 'trends.revcontent.com' // Optional/Debug - Set different endpoint + endpoint: 'trends.revcontent.com' // Optional - Debug - Set different endpoint + bidfloor: 0.1, // Optional - BidFloor - Default 0.1 /* Optional - Set different template. Template variables: {clickUrl} -> Target Url diff --git a/modules/rhythmoneBidAdapter.js b/modules/rhythmoneBidAdapter.js index f7102e4be5a..1acbcfd0463 100644 --- a/modules/rhythmoneBidAdapter.js +++ b/modules/rhythmoneBidAdapter.js @@ -1,8 +1,8 @@ 'use strict'; -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; function RhythmOneBidAdapter() { this.code = 'rhythmone'; diff --git a/modules/richaudienceBidAdapter.js b/modules/richaudienceBidAdapter.js index 2a4fa03c7d6..43bef356a73 100755 --- a/modules/richaudienceBidAdapter.js +++ b/modules/richaudienceBidAdapter.js @@ -1,7 +1,8 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; -import {config} from '../src/config'; -import {BANNER, VIDEO} from '../src/mediaTypes'; -import * as utils from '../src/utils'; +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 = ''; @@ -45,7 +46,9 @@ export const spec = { numIframes: (typeof bidderRequest.refererInfo.numIframes != 'undefined' ? bidderRequest.refererInfo.numIframes : null), transactionId: bid.transactionId, timeout: config.getConfig('bidderTimeout'), - user: raiSetEids(bid) + user: raiSetEids(bid), + demand: raiGetDemandType(bid), + videoData: raiGetVideoInfo(bid) }; REFERER = (typeof bidderRequest.refererInfo.referer != 'undefined' ? encodeURIComponent(bidderRequest.refererInfo.referer) : null) @@ -95,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); @@ -116,18 +129,31 @@ export const spec = { var rand = Math.floor(Math.random() * 9999999999); var syncUrl = ''; + var consent = ''; - gdprConsent && typeof gdprConsent.consentString === 'string' ? syncUrl = 'https://sync.richaudience.com/dcf3528a0b8aa83634892d50e91c306e/?ord=' + rand + '&pubconsent=' + gdprConsent.consentString + '&euconsent=' + gdprConsent.consentString : syncUrl = 'https://sync.richaudience.com/dcf3528a0b8aa83634892d50e91c306e/?ord=' + rand; + if (gdprConsent && typeof gdprConsent.consentString === 'string' && typeof gdprConsent.consentString != 'undefined') { + consent = `consentString=’${gdprConsent.consentString}` + } if (syncOptions.iframeEnabled) { + syncUrl = 'https://sync.richaudience.com/dcf3528a0b8aa83634892d50e91c306e/?ord=' + rand + if (consent != '') { + syncUrl += `&${consent}` + } syncs.push({ type: 'iframe', url: syncUrl }); - } else if (syncOptions.pixelEnabled && REFERER != null) { + } + + if (syncOptions.pixelEnabled && REFERER != null && syncs.length == 0) { + syncUrl = `https://sync.richaudience.com/bf7c142f4339da0278e83698a02b0854/?referrer=${REFERER}`; + if (consent != '') { + syncUrl += `&${consent}` + } syncs.push({ type: 'image', - url: `https://sync.richaudience.com/bf7c142f4339da0278e83698a02b0854/?euconsent=${gdprConsent.consentString}&referrer=${REFERER}` + url: syncUrl }); } return syncs @@ -140,8 +166,6 @@ function raiGetSizes(bid) { let raiNewSizes; if (bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes) { raiNewSizes = bid.mediaTypes.banner.sizes - } else { - raiNewSizes = bid.sizes } if (raiNewSizes != null) { return raiNewSizes.map(size => ({ @@ -151,6 +175,28 @@ function raiGetSizes(bid) { } } +function raiGetDemandType(bid) { + let raiFormat = 'display'; + if (bid.mediaTypes != undefined) { + if (bid.mediaTypes.video != undefined) { + raiFormat = 'video'; + } + } + return raiFormat; +} + +function raiGetVideoInfo(bid) { + let videoData; + if (raiGetDemandType(bid) == 'video') { + videoData = { + format: bid.mediaTypes.video.context, + playerSize: bid.mediaTypes.video.playerSize, + mimes: bid.mediaTypes.video.mimes + }; + } + return videoData; +} + function raiSetEids(bid) { let eids = []; @@ -174,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 11c60efc9dc..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,12 +45,43 @@ 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 = [ { code: 'test-div1', - sizes: [[300, 250],[300, 600]], + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, bids: [{ bidder: 'richaudience', params: { @@ -85,7 +116,18 @@ Rich Audience strongly recommends enabling user syncing through iframes. Be sure ```javascript pbjs.setConfig({ userSync: { - iframeEnabled: true - } + filterSettings: { + iframe: { + bidders: '*', + filter: 'include' + }, + image: { + bidders: '*', + filter: 'include' + } + }, + syncsPerBidder: 3, + syncDelay: 6000, + } }); ``` diff --git a/modules/rivrAnalyticsAdapter.js b/modules/rivrAnalyticsAdapter.js index e1cfa5c70bc..279b1b13051 100644 --- a/modules/rivrAnalyticsAdapter.js +++ b/modules/rivrAnalyticsAdapter.js @@ -1,7 +1,7 @@ -import {ajax} from '../src/ajax'; -import adapter from '../src/AnalyticsAdapter'; -import adapterManager from '../src/adapterManager'; -import * as utils from '../src/utils'; +import {ajax} from '../src/ajax.js'; +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; const analyticsType = 'endpoint'; diff --git a/modules/roxotAnalyticsAdapter.js b/modules/roxotAnalyticsAdapter.js index 45bcbc55947..b6857d69f45 100644 --- a/modules/roxotAnalyticsAdapter.js +++ b/modules/roxotAnalyticsAdapter.js @@ -1,10 +1,13 @@ -import adapter from '../src/AnalyticsAdapter'; +import adapter from '../src/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; -import adapterManager from '../src/adapterManager'; -import includes from 'core-js/library/fn/array/includes'; -import {ajaxBuilder} from '../src/ajax'; +import adapterManager from '../src/adapterManager.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import {ajaxBuilder} from '../src/ajax.js'; +import { getStorageManager } from '../src/storageManager.js'; -const utils = require('../src/utils'); +const storage = getStorageManager(); + +const utils = require('../src/utils.js'); let ajax = ajaxBuilder(0); const DEFAULT_EVENT_URL = 'pa.rxthdr.com/v3'; @@ -68,17 +71,17 @@ function detectDevice() { function checkIsNewFlag() { let key = buildLocalStorageKey(isNewKey); - let lastUpdate = Number(localStorage.getItem(key)); - localStorage.setItem(key, Date.now()); + let lastUpdate = Number(storage.getDataFromLocalStorage(key)); + storage.setDataInLocalStorage(key, Date.now()); return Date.now() - lastUpdate > isNewTtl; } function updateUtmTimeout() { - localStorage.setItem(buildLocalStorageKey(utmTtlKey), Date.now()); + storage.setDataInLocalStorage(buildLocalStorageKey(utmTtlKey), Date.now()); } function isUtmTimeoutExpired() { - let utmTimestamp = localStorage.getItem(buildLocalStorageKey(utmTtlKey)); + let utmTimestamp = storage.getDataFromLocalStorage(buildLocalStorageKey(utmTtlKey)); return (Date.now() - utmTimestamp) > utmTtl; } @@ -356,11 +359,11 @@ roxotAdapter.buildUtmTagData = function () { }); utmTags.forEach(function (utmTagKey) { if (utmTagsDetected) { - localStorage.setItem(buildLocalStorageKey(utmTagKey), utmTagData[utmTagKey]); + storage.setDataInLocalStorage(buildLocalStorageKey(utmTagKey), utmTagData[utmTagKey]); updateUtmTimeout(); } else { if (!isUtmTimeoutExpired()) { - utmTagData[utmTagKey] = localStorage.getItem(buildLocalStorageKey(utmTagKey)) ? localStorage.getItem(buildLocalStorageKey(utmTagKey)) : ''; + utmTagData[utmTagKey] = storage.getDataFromLocalStorage(buildLocalStorageKey(utmTagKey)) ? storage.getDataFromLocalStorage(buildLocalStorageKey(utmTagKey)) : ''; updateUtmTimeout(); } } diff --git a/modules/rtbdemandBidAdapter.js b/modules/rtbdemandBidAdapter.js index ac8e639ff03..be5fb39f53a 100644 --- a/modules/rtbdemandBidAdapter.js +++ b/modules/rtbdemandBidAdapter.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'rtbdemand'; const BIDDER_SERVER = 'bidding.rtbdemand.com'; diff --git a/modules/rtbhouseBidAdapter.js b/modules/rtbhouseBidAdapter.js index 36c08fc8626..3337c3f1b59 100644 --- a/modules/rtbhouseBidAdapter.js +++ b/modules/rtbhouseBidAdapter.js @@ -1,7 +1,7 @@ -import * as utils from '../src/utils'; -import { BANNER, NATIVE } from '../src/mediaTypes'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import includes from 'core-js/library/fn/array/includes'; +import * as utils from '../src/utils.js'; +import { BANNER, NATIVE } from '../src/mediaTypes.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import includes from 'core-js-pure/features/array/includes.js'; const BIDDER_CODE = 'rtbhouse'; const REGIONS = ['prebid-eu', 'prebid-us', 'prebid-asia']; @@ -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/rtbsolutionsBidAdapter.js b/modules/rtbsolutionsBidAdapter.js index ad75b9de25a..244ab8a4eba 100644 --- a/modules/rtbsolutionsBidAdapter.js +++ b/modules/rtbsolutionsBidAdapter.js @@ -1,6 +1,6 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import * as utils from '../src/utils'; -import { ajax } from '../src/ajax'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; +import { ajax } from '../src/ajax.js'; const BIDDER_CODE = 'rtbsolutions'; const ENDPOINT_URL = 'https://dsp-eu-lb.rtbsolutions.pro/bid/hb'; diff --git a/modules/rtdModule/index.js b/modules/rtdModule/index.js index e7ba364c0e5..3aa7753d204 100644 --- a/modules/rtdModule/index.js +++ b/modules/rtdModule/index.js @@ -47,14 +47,23 @@ * @type {Object} */ -import {getGlobal} from '../../src/prebidGlobal'; +/** + * @property + * @summary timeout (if no auction dealy) + * @name ModuleConfig#timeout + * @type {number} + */ + +import {getGlobal} from '../../src/prebidGlobal.js'; import {config} from '../../src/config.js'; -import {targeting} from '../../src/targeting'; -import {getHook, module} from '../../src/hook'; -import * as utils from '../../src/utils'; +import {targeting} from '../../src/targeting.js'; +import {getHook, module} from '../../src/hook.js'; +import * as utils from '../../src/utils.js'; /** @type {string} */ const MODULE_NAME = 'realTimeData'; +/** @type {number} */ +const DEF_TIMEOUT = 1000; /** @type {RtdSubmodule[]} */ let subModules = []; /** @type {ModuleConfig} */ @@ -100,7 +109,7 @@ function getProviderData(adUnits, callback) { const dataWaitTimeout = setTimeout(() => { processDone = true; callback(dataReceived); - }, _moduleConfig.auctionDelay); + }, _moduleConfig.auctionDelay || _moduleConfig.timeout || DEF_TIMEOUT); subModules.forEach(sm => { sm.getData(adUnits, onDataReceived); @@ -119,6 +128,32 @@ function getProviderData(adUnits, callback) { } } +/** + * delete invalid data received from provider + * this is to ensure working flow for GPT + * @param {Object} data received from provider + * @return {Object} valid data for GPT targeting + */ +export function validateProviderDataForGPT(data) { + // data must be an object, contains object with string as value + if (typeof data !== 'object') { + return {}; + } + for (let key in data) { + if (data.hasOwnProperty(key)) { + for (let innerKey in data[key]) { + if (data[key].hasOwnProperty(innerKey)) { + if (typeof data[key][innerKey] !== 'string') { + utils.logWarn(`removing ${key}: {${innerKey}:${data[key][innerKey]} } from GPT targeting because of invalid type (must be string)`); + delete data[key][innerKey]; + } + } + } + } + } + return data; +} + /** * run hook after bids request and before callback * get data from provider and set key values to primary ad server @@ -187,11 +222,16 @@ 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; + data = validateProviderDataForGPT(data); + 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); } /** diff --git a/modules/rubiconAnalyticsAdapter.js b/modules/rubiconAnalyticsAdapter.js index 9c57e956b78..00ad14dd316 100644 --- a/modules/rubiconAnalyticsAdapter.js +++ b/modules/rubiconAnalyticsAdapter.js @@ -1,9 +1,10 @@ -import adapter from '../src/AnalyticsAdapter'; -import adapterManager from '../src/adapterManager'; +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; import CONSTANTS from '../src/constants.json'; -import { ajax } from '../src/ajax'; -import { config } from '../src/config'; -import * as utils from '../src/utils'; +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'; const { EVENTS: { @@ -19,6 +20,9 @@ const { STATUS: { GOOD, NO_BID + }, + BID_STATUS: { + BID_REJECTED } } = CONSTANTS; @@ -36,6 +40,16 @@ const cache = { timeouts: {}, }; +export function getHostNameFromReferer(referer) { + try { + rubiconAdapter.referrerHostname = utils.parseUrl(referer, {noDecodeWholeURL: true}).hostname; + } catch (e) { + utils.logError('Rubicon Analytics: Unable to parse hostname from supplied url: ', referer, e); + rubiconAdapter.referrerHostname = ''; + } + return rubiconAdapter.referrerHostname +}; + function stringProperties(obj) { return Object.keys(obj).reduce((newObj, prop) => { let value = obj[prop]; @@ -73,7 +87,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) => { @@ -90,7 +104,9 @@ function sendMessage(auctionId, bidWonId) { 'bidPriceUSD', 'dealId', 'dimensions', - 'mediaType' + 'mediaType', + 'floorValue', + 'floorRule' ]) : undefined ]); } @@ -115,7 +131,8 @@ function sendMessage(auctionId, bidWonId) { eventTimeMillis: Date.now(), integration: config.getConfig('rubicon.int_type') || DEFAULT_INTEGRATION, version: '$prebid.version$', - referrerUri: referrer + referrerUri: referrer, + referrerHostname: rubiconAdapter.referrerHostname || getHostNameFromReferer(referrer) }; const wrapperName = config.getConfig('rubicon.wrapperName'); if (wrapperName) { @@ -131,9 +148,11 @@ function sendMessage(auctionId, bidWonId) { 'transactionId', 'mediaTypes', 'dimensions', - 'adserverTargeting', () => stringProperties(cache.targeting[bid.adUnit.adUnitCode] || {}) + 'adserverTargeting', () => stringProperties(cache.targeting[bid.adUnit.adUnitCode] || {}), + 'adSlot' ]); adUnit.bids = []; + adUnit.status = 'no-bid'; // default it to be no bid } // Add site and zone id if not there and if we found a rubicon bidder @@ -174,6 +193,19 @@ function sendMessage(auctionId, bidWonId) { adUnits: Object.keys(adUnitMap).map(i => adUnitMap[i]) }; + // 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'), + 'skipRate', skipRate => !isNaN(skipRate) ? skipRate : 0, + 'fetchStatus' + ]); + } + if (serverConfig) { auction.serverTimeoutMillis = serverConfig.timeout; } @@ -210,14 +242,31 @@ function sendMessage(auctionId, bidWonId) { } function getBidPrice(bid) { - if (typeof bid.currency === 'string' && bid.currency.toUpperCase() === 'USD') { + // get the cpm from bidResponse + let cpm; + let currency; + if (bid.status === BID_REJECTED && utils.deepAccess(bid, 'floorData.cpmAfterAdjustments')) { + // if bid was rejected and bid.floorData.cpmAfterAdjustments use it + cpm = bid.floorData.cpmAfterAdjustments; + currency = bid.floorData.floorCurrency; + } else if (typeof bid.currency === 'string' && bid.currency.toUpperCase() === 'USD') { + // bid is in USD use it return Number(bid.cpm); + } else { + // else grab cpm + cpm = bid.cpm; + currency = bid.currency; } - // use currency conversion function if present - if (typeof bid.getCpmInNewCurrency === 'function') { - return Number(bid.getCpmInNewCurrency('USD')); + // if after this it is still going and is USD then return it. + if (currency === 'USD') { + return Number(cpm); + } + // otherwise we convert and return + try { + return Number(getGlobal().convertCurrency(cpm, currency, 'USD')); + } catch (err) { + utils.logWarn('Rubicon Analytics Adapter: Could not determine the bidPriceUSD of the bid ', bid); } - utils.logWarn('Rubicon Analytics Adapter: Could not determine the bidPriceUSD of the bid ', bid); } export function parseBidResponse(bid, previousBidResponse) { @@ -237,6 +286,8 @@ export function parseBidResponse(bid, previousBidResponse) { 'height' ]), 'seatBidId', + 'floorValue', () => utils.deepAccess(bid, 'floorData.floorValue'), + 'floorRule', () => utils.debugTurnedOn() ? utils.deepAccess(bid, 'floorData.floorRule') : undefined ]); } @@ -260,6 +311,7 @@ function setRubiconAliases(aliasRegistry) { let baseAdapter = adapter({analyticsType: 'endpoint'}); let rubiconAdapter = Object.assign({}, baseAdapter, { + referrerHostname: '', enableAnalytics(config = {}) { let error = false; samplingFactor = 1; @@ -316,6 +368,9 @@ 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')}; + } cache.auctions[args.auctionId] = cacheEntry; break; case BID_REQUESTED: @@ -386,14 +441,23 @@ let rubiconAdapter = Object.assign({}, baseAdapter, { return Object.keys(types).filter(validMediaType); } return ['banner']; - } + }, ]) ]); return memo; }, {})); break; case BID_RESPONSE: - let bid = cache.auctions[args.auctionId].bids[args.requestId]; + 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 we have not set enforcements yet set it + if (!utils.deepAccess(auctionEntry, 'floorData.enforcements') && utils.deepAccess(args, 'floorData.enforcements')) { + auctionEntry.floorData.enforcements = {...args.floorData.enforcements}; + } if (!bid) { utils.logError('Rubicon Anlytics Adapter Error: Could not find associated bid request for bid response with requestId: ', args.requestId); break; @@ -405,7 +469,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 = 'no-bid'; + bid.status = args.status === BID_REJECTED ? 'rejected' : 'no-bid'; delete bid.error; break; default: diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index b76ca9e375d..cd621010a9b 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -1,15 +1,17 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {config} from '../src/config'; -import {BANNER, VIDEO} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {config} from '../src/config.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.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'; +const GVLID = 52; const DIGITRUST_PROP_NAMES = { FASTLANE: { id: 'dt.id', @@ -26,6 +28,7 @@ var sizeMap = { 1: '468x60', 2: '728x90', 5: '120x90', + 7: '125x125', 8: '120x600', 9: '160x600', 10: '300x600', @@ -67,7 +70,10 @@ var sizeMap = { 79: '980x300', 80: '980x400', 83: '480x300', + 85: '300x120', + 90: '548x150', 94: '970x310', + 95: '970x100', 96: '970x210', 101: '480x320', 102: '768x1024', @@ -91,19 +97,26 @@ var sizeMap = { 214: '980x360', 221: '1x1', 229: '320x180', + 230: '2000x1400', 232: '580x400', 234: '6x6', 251: '2x2', + 256: '480x820', 257: '400x600', + 258: '500x200', + 259: '998x200', 264: '970x1000', 265: '1920x1080', + 274: '1800x200', 278: '320x500', + 282: '320x400', 288: '640x380' }; utils._each(sizeMap, (item, key) => sizeMap[item] = key); export const spec = { code: 'rubicon', + gvlid: GVLID, supportedMediaTypes: [BANNER, VIDEO], /** * @param {object} bid @@ -171,6 +184,11 @@ export const spec = { // includebidderkeys always false for openrtb includebidderkeys: false, pricegranularity: getPriceGranularity(config) + }, + bidders: { + rubicon: { + integration: config.getConfig('rubicon.int_type') || DEFAULT_PBS_INTEGRATION + } } } } @@ -183,7 +201,17 @@ export const spec = { } } - const bidFloor = parseFloat(utils.deepAccess(bidRequest, 'params.floor')); + let bidFloor; + if (typeof bidRequest.getFloor === 'function' && !config.getConfig('rubicon.disableFloors')) { + let floorInfo = bidRequest.getFloor({ + currency: 'USD', + mediaType: 'video', + size: parseSizes(bidRequest, 'video') + }); + bidFloor = typeof floorInfo === 'object' && floorInfo.currency === 'USD' && !isNaN(parseInt(floorInfo.floor)) ? parseFloat(floorInfo.floor) : undefined; + } else { + bidFloor = parseFloat(utils.deepAccess(bidRequest, 'params.floor')); + } if (!isNaN(bidFloor)) { data.imp[0].bidfloor = bidFloor; } @@ -215,7 +243,7 @@ export const spec = { } if (bidRequest.userId && typeof bidRequest.userId === 'object' && - (bidRequest.userId.tdid || bidRequest.userId.pubcid || bidRequest.userId.lipb)) { + (bidRequest.userId.tdid || bidRequest.userId.pubcid || bidRequest.userId.lipb || bidRequest.userId.idl_env)) { utils.deepSetValue(data, 'user.ext.eids', []); if (bidRequest.userId.tdid) { @@ -257,6 +285,16 @@ export const spec = { utils.deepSetValue(data, 'rp.target.LIseg', bidRequest.userId.lipb.segments); } } + + // support identityLink (aka LiveRamp) + if (bidRequest.userId.idl_env) { + data.user.ext.eids.push({ + source: 'liveramp.com', + uids: [{ + id: bidRequest.userId.idl_env + }] + }); + } } if (config.getConfig('coppa') === true) { @@ -267,6 +305,27 @@ export const spec = { utils.deepSetValue(data, 'source.ext.schain', bidRequest.schain); } + const siteData = Object.assign({}, bidRequest.params.inventory, config.getConfig('fpd.context')); + const userData = Object.assign({}, bidRequest.params.visitor, config.getConfig('fpd.user')); + if (!utils.isEmpty(siteData) || !utils.isEmpty(userData)) { + const bidderData = { + bidders: [ bidderRequest.bidderCode ], + config: { + fpd: {} + } + }; + + if (!utils.isEmpty(siteData)) { + bidderData.config.fpd.site = siteData; + } + + if (!utils.isEmpty(userData)) { + bidderData.config.fpd.user = userData; + } + + utils.deepSetValue(data, 'ext.prebid.bidderconfig.0', bidderData); + } + /** * Prebid AdSlot * @type {(string|undefined)} @@ -276,6 +335,14 @@ export const spec = { utils.deepSetValue(data.imp[0].ext, 'context.data.adslot', pbAdSlot); } + // 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, @@ -442,7 +509,6 @@ export const spec = { 'x_source.tid': bidRequest.transactionId, 'x_source.pchain': params.pchain, 'p_screen_res': _getScreenResolution(), - 'kw': Array.isArray(params.keywords) ? params.keywords.join(',') : '', 'tk_user_key': params.userId, 'p_geo.latitude': isNaN(parseFloat(latitude)) ? undefined : parseFloat(latitude).toFixed(4), 'p_geo.longitude': isNaN(parseFloat(longitude)) ? undefined : parseFloat(longitude).toFixed(4), @@ -450,6 +516,16 @@ export const spec = { 'rf': _getPageUrl(bidRequest, bidderRequest) }; + // 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: '*' + }); + data['rp_hard_floor'] = typeof floorInfo === 'object' && floorInfo.currency === 'USD' && !isNaN(parseInt(floorInfo.floor)) ? floorInfo.floor : undefined; + } + // add p_pos only if specified and valid // 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 : ''; @@ -466,6 +542,11 @@ export const spec = { data['tg_v.LIseg'] = bidRequest.userId.lipb.segments.join(','); } } + + // support identityLink (aka LiveRamp) + if (bidRequest.userId.idl_env) { + data['tpid_liveramp.com'] = bidRequest.userId.idl_env; + } } if (bidderRequest.gdprConsent) { @@ -481,22 +562,30 @@ export const spec = { } // visitor properties - if (params.visitor !== null && typeof params.visitor === 'object') { - Object.keys(params.visitor).forEach((key) => { - if (params.visitor[key] != null) { - data[`tg_v.${key}`] = params.visitor[key].toString(); // initialize array; - } - }); - } + const visitorData = Object.assign({}, params.visitor, config.getConfig('fpd.user')); + Object.keys(visitorData).forEach((key) => { + if (visitorData[key] != null && key !== 'keywords') { + data[`tg_v.${key}`] = typeof visitorData[key] === 'object' && !Array.isArray(visitorData[key]) + ? JSON.stringify(visitorData[key]) + : visitorData[key].toString(); // initialize array; + } + }); // inventory properties - if (params.inventory !== null && typeof params.inventory === 'object') { - Object.keys(params.inventory).forEach((key) => { - if (params.inventory[key] != null) { - data[`tg_i.${key}`] = params.inventory[key].toString(); - } - }); - } + const inventoryData = Object.assign({}, params.inventory, config.getConfig('fpd.context')); + Object.keys(inventoryData).forEach((key) => { + if (inventoryData[key] != null && key !== 'keywords') { + data[`tg_i.${key}`] = typeof inventoryData[key] === 'object' && !Array.isArray(inventoryData[key]) + ? JSON.stringify(inventoryData[key]) + : inventoryData[key].toString(); + } + }); + + // keywords + const keywords = (params.keywords || []).concat( + utils.deepAccess(config.getConfig('fpd.user'), 'keywords') || [], + utils.deepAccess(config.getConfig('fpd.context'), 'keywords') || []); + data.kw = Array.isArray(keywords) && keywords.length ? keywords.join(',') : ''; /** * Prebid AdSlot @@ -604,7 +693,7 @@ export const spec = { bidObject.adserverTargeting = extPrebidTargeting; } - // try to get cache values from 'response.ext.prebid.cache' + // try to get cache values from 'response.ext.prebid.cache.js' // else try 'bid.ext.prebid.targeting' as fallback if (bid.ext.prebid.cache && typeof bid.ext.prebid.cache.vastXml === 'object' && bid.ext.prebid.cache.vastXml.cacheId && bid.ext.prebid.cache.vastXml.url) { bidObject.videoCacheKey = bid.ext.prebid.cache.vastXml.cacheId; diff --git a/modules/s2sTesting.js b/modules/s2sTesting.js index eccc3aa1f8a..98b3b86671c 100644 --- a/modules/s2sTesting.js +++ b/modules/s2sTesting.js @@ -1,5 +1,5 @@ -import { config } from '../src/config'; -import { setS2STestingModule } from '../src/adapterManager'; +import { config } from '../src/config.js'; +import { setS2STestingModule } from '../src/adapterManager.js'; let s2sTesting = {}; diff --git a/modules/scaleableAnalyticsAdapter.js b/modules/scaleableAnalyticsAdapter.js index c875dab7e18..955a08c065a 100644 --- a/modules/scaleableAnalyticsAdapter.js +++ b/modules/scaleableAnalyticsAdapter.js @@ -1,14 +1,23 @@ /* COPYRIGHT SCALEABLE LLC 2019 */ -import { ajax } from '../src/ajax'; +import { ajax } from '../src/ajax.js'; import CONSTANTS from '../src/constants.json'; -import adapter from '../src/AnalyticsAdapter'; -import adapterManager from '../src/adapterManager'; -import * as utils from '../src/utils'; +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; + +// Object.entries polyfill +const entries = Object.entries || function(obj) { + const ownProps = Object.keys(obj); + let i = ownProps.length; + let resArray = new Array(i); // preallocate the Array + while (i--) { resArray[i] = [ownProps[i], obj[ownProps[i]]]; } + + return resArray; +}; const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; const AUCTION_INIT = CONSTANTS.EVENTS.AUCTION_INIT; -const BID_RESPONSE = CONSTANTS.EVENTS.BID_RESPONSE; const BID_WON = CONSTANTS.EVENTS.BID_WON; const AUCTION_END = CONSTANTS.EVENTS.AUCTION_END; @@ -35,9 +44,6 @@ let scaleableAnalytics = Object.assign({}, case BID_WON: onBidWon(args); break; - case BID_RESPONSE: - onBidResponse(args); - break; case BID_TIMEOUT: onBidTimeout(args); break; @@ -70,22 +76,93 @@ const sendDataToServer = data => ajax(URL, () => {}, JSON.stringify(data)); const onAuctionInit = args => { const config = scaleableAnalytics.config || {options: {}}; - for (let idx = args.adUnitCodes.length; idx--;) { - const data = { - event: 'request', - site: config.options.site, - adunit: args.adUnitCodes[idx] - }; + let adunitObj = {}; + let adunits = []; + + // Loop through adunit codes first + args.adUnitCodes.forEach((code) => { + adunitObj[code] = [{ + bidder: 'scaleable_adunit_request' + }] + }); + + // Loop through bidder requests and bids + args.bidderRequests.forEach((bidderObj) => { + bidderObj.bids.forEach((bidObj) => { + adunitObj[bidObj.adUnitCode].push({ + bidder: bidObj.bidder, + params: bidObj.params + }) + }); + }); + + entries(adunitObj).forEach(([adunitCode, bidRequests]) => { + adunits.push({ + code: adunitCode, + bidRequests: bidRequests + }); + }); - sendDataToServer(data); + const data = { + event: 'request', + site: config.options.site, + adunits: adunits } + + sendDataToServer(data); } // Handle all events besides requests and wins const onAuctionEnd = args => { - for (let adunit in auctionData) { - sendDataToServer(auctionData[adunit]); + const config = scaleableAnalytics.config || {options: {}}; + + let adunitObj = {}; + let adunits = []; + + // Add Bids Received + args.bidsReceived.forEach((bidObj) => { + if (!adunitObj[bidObj.adUnitCode]) { adunitObj[bidObj.adUnitCode] = []; } + + adunitObj[bidObj.adUnitCode].push({ + bidder: bidObj.bidderCode || bidObj.bidder, + cpm: bidObj.cpm, + currency: bidObj.currency, + dealId: bidObj.dealId, + type: bidObj.mediaType, + ttr: bidObj.timeToRespond, + size: bidObj.size + }); + }); + + // Add in other data (timeouts) as we push to adunits + entries(adunitObj).forEach(([adunitCode, bidsReceived]) => { + const bidData = bidsReceived.concat(auctionData[adunitCode] || []); + adunits.push({ + code: adunitCode, + bidData: bidData + }); + + delete auctionData[adunitCode]; + }); + + // Add in any missed auction data + entries(auctionData).forEach(([adunitCode, bidData]) => { + adunits.push({ + code: adunitCode, + bidData: bidData + }) + }); + + const data = { + event: 'bids', + site: config.options.site, + adunits: adunits } + + if (adunits.length) { sendDataToServer(data); } + + // Reset auctionData + auctionData = {} } // Bid Win Events occur after auction end @@ -98,51 +175,24 @@ const onBidWon = args => { adunit: args.adUnitCode, code: args.bidderCode, cpm: args.cpm, - ttr: args.timeToRespond + ttr: args.timeToRespond, + params: args.params }; sendDataToServer(data); } -const onBidResponse = args => { - const config = scaleableAnalytics.config || {options: {}}; - - if (!auctionData[args.adUnitCode]) { - auctionData[args.adUnitCode] = { - event: 'bids', - bids: [], - adunit: args.adUnitCode, - site: config.options.site - }; - } - - const currBidData = { - code: args.bidderCode, - cpm: args.cpm, - ttr: args.timeToRespond - }; - - auctionData[args.adUnitCode].bids.push(currBidData); -} - const onBidTimeout = args => { - const config = scaleableAnalytics.config || {options: {}}; - - for (let i = args.length; i--;) { - let currObj = args[i]; - + args.forEach(currObj => { if (!auctionData[currObj.adUnitCode]) { - auctionData[currObj.adUnitCode] = { - event: 'bids', - bids: [], - timeouts: [], - adunit: currObj.adUnitCode, - site: config.options.site - }; + auctionData[currObj.adUnitCode] = [] } - auctionData[currObj.adUnitCode].timeouts.push(currObj.bidder); - } + auctionData[currObj.adUnitCode].push({ + timeouts: 1, + bidder: currObj.bidder + }); + }); } adapterManager.registerAnalyticsAdapter({ diff --git a/modules/schain.js b/modules/schain.js index b14e09bff11..d409e74df48 100644 --- a/modules/schain.js +++ b/modules/schain.js @@ -1,6 +1,6 @@ -import { config } from '../src/config'; -import adapterManager from '../src/adapterManager'; -import { isNumber, isStr, isArray, isPlainObject, hasOwn, logError, isInteger, _each, logWarn } from '../src/utils'; +import { config } from '../src/config.js'; +import adapterManager from '../src/adapterManager.js'; +import { isNumber, isStr, isArray, isPlainObject, hasOwn, logError, isInteger, _each, logWarn } from '../src/utils.js'; // https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/supplychainobject.md diff --git a/modules/seedingAllianceBidAdapter.js b/modules/seedingAllianceBidAdapter.js index e118849e666..b6acd7214a2 100755 --- a/modules/seedingAllianceBidAdapter.js +++ b/modules/seedingAllianceBidAdapter.js @@ -1,16 +1,16 @@ // jshint esversion: 6, es3: false, node: true 'use strict'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { NATIVE } from '../src/mediaTypes'; -import * as utils from '../src/utils'; -import { config } from '../src/config'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { NATIVE } from '../src/mediaTypes.js'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'seedingAlliance'; const DEFAULT_CUR = 'EUR'; const ENDPOINT_URL = 'https://b.nativendo.de/cds/rtb/bid?format=openrtb2.5&ssp=nativendo'; -const NATIVE_ASSET_IDS = {0: 'title', 1: 'body', 2: 'sponsoredBy', 3: 'image'}; +const NATIVE_ASSET_IDS = {0: 'title', 1: 'body', 2: 'sponsoredBy', 3: 'image', 4: 'cta', 5: 'icon'}; const NATIVE_PARAMS = { title: { @@ -34,6 +34,18 @@ const NATIVE_PARAMS = { id: 3, type: 3, name: 'img' + }, + + cta: { + id: 4, + type: 12, + name: 'data' + }, + + icon: { + id: 5, + type: 1, + name: 'img' } }; diff --git a/modules/seedtagBidAdapter.js b/modules/seedtagBidAdapter.js index 845d8ffec9d..018339fabe4 100644 --- a/modules/seedtagBidAdapter.js +++ b/modules/seedtagBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils' -import { registerBidder } from '../src/adapters/bidderFactory' -import { VIDEO, BANNER } from '../src/mediaTypes' +import * as utils from '../src/utils.js' +import { registerBidder } from '../src/adapters/bidderFactory.js' +import { VIDEO, BANNER } from '../src/mediaTypes.js' const BIDDER_CODE = 'seedtag'; const SEEDTAG_ALIAS = 'st'; diff --git a/modules/segmentoBidAdapter.js b/modules/segmentoBidAdapter.js index bb6fdfec413..a042bdf4942 100644 --- a/modules/segmentoBidAdapter.js +++ b/modules/segmentoBidAdapter.js @@ -1,4 +1,4 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'segmento'; const URL = 'https://prebid-bidder.rutarget.ru/bid'; diff --git a/modules/sekindoUMBidAdapter.js b/modules/sekindoUMBidAdapter.js index ad4da7a06cb..bea25173747 100644 --- a/modules/sekindoUMBidAdapter.js +++ b/modules/sekindoUMBidAdapter.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; export const spec = { code: 'sekindoUM', supportedMediaTypes: ['banner', 'video'], 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..acb076ed97f --- /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/sharethroughAnalyticsAdapter.js b/modules/sharethroughAnalyticsAdapter.js index d32000373d2..5147b2a4275 100644 --- a/modules/sharethroughAnalyticsAdapter.js +++ b/modules/sharethroughAnalyticsAdapter.js @@ -1,6 +1,6 @@ -import adapter from '../src/AnalyticsAdapter'; -import adapterManager from '../src/adapterManager'; -const utils = require('../src/utils'); +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; +const utils = require('../src/utils.js'); const emptyUrl = ''; const analyticsType = 'endpoint'; diff --git a/modules/sharethroughBidAdapter.js b/modules/sharethroughBidAdapter.js index e86f8d518bc..0d183be05df 100644 --- a/modules/sharethroughBidAdapter.js +++ b/modules/sharethroughBidAdapter.js @@ -1,6 +1,7 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; -const VERSION = '3.2.0'; +const VERSION = '3.2.1'; const BIDDER_CODE = 'sharethrough'; const STR_ENDPOINT = 'https://btlr.sharethrough.com/WYu2BXv1/v1'; const DEFAULT_SIZE = [1, 1]; @@ -153,7 +154,7 @@ function generateAd(body, req) { if (req.strData.skipIframeBusting) { // Don't break out of iframe - adMarkup = adMarkup + ``; + adMarkup = adMarkup + ``; } else { // Add logic to the markup that detects whether or not in top level document is accessible // this logic will deploy sfp.js and/or iframe buster script(s) as appropriate @@ -181,7 +182,7 @@ function handleIframe () { window.document.getElementsByTagName('body')[0].appendChild(sfpIframeBusterJs); iframeBusterLoaded = true; } catch (e) { - console.error(e); + utils.logError('Trouble writing frame buster script, error details:', e); } } @@ -199,7 +200,7 @@ function handleIframe () { window.document.getElementsByTagName('body')[0].appendChild(sfpJs); } } catch (e) { - console.error(e); + utils.logError('Trouble writing sfp script, error details:', e); } } } diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index 05ea2eb53de..d0eb8c6a589 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -1,11 +1,11 @@ -import * as utils from '../src/utils'; -import { config } from '../src/config'; -import { Renderer } from '../src/Renderer'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { VIDEO, BANNER } from '../src/mediaTypes'; -import { loadExternalScript } from '../src/adloader'; +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, BANNER } from '../src/mediaTypes.js'; +import { loadExternalScript } from '../src/adloader.js'; -const PROD_ENDPOINT = 'https://bs1.showheroes.com/api/v1/bid'; +const PROD_ENDPOINT = 'https://bs.showheroes.com/api/v1/bid'; const STAGE_ENDPOINT = 'https://bid-service.stage.showheroes.com/api/v1/bid'; const PROD_PUBLISHER_TAG = 'https://static.showheroes.com/publishertag.js'; const STAGE_PUBLISHER_TAG = 'https://pubtag.stage.showheroes.com/publishertag.js'; @@ -29,6 +29,7 @@ export const spec = { return !!bid.params.playerId; }, buildRequests: function(validBidRequests, bidderRequest) { + let adUnits = []; const pageURL = validBidRequests[0].params.contentPageUrl || bidderRequest.refererInfo.referer; const isStage = !!validBidRequests[0].params.stage; const isOutstream = utils.deepAccess(validBidRequests[0], 'mediaTypes.video.context') === 'outstream'; @@ -37,54 +38,56 @@ export const spec = { const isNativeRender = utils.deepAccess(validBidRequests[0], 'renderer'); const outstreamOptions = utils.deepAccess(validBidRequests[0], 'params.outstreamOptions'); const isBanner = !!validBidRequests[0].mediaTypes.banner || (isOutstream && !(isCustomRender || isNativeRender || isNodeRender)); + const defaultSchain = validBidRequests[0].schain || {}; - let adUnits = validBidRequests.map((bid) => { + validBidRequests.forEach((bid) => { + const videoSizes = getVideoSizes(bid); + const bannerSizes = getBannerSizes(bid); const vpaidMode = utils.getBidIdParameter('vpaidMode', bid.params); - let sizes = bid.sizes.length === 1 ? bid.sizes[0] : bid.sizes; - if (sizes && !sizes.length) { - let mediaSize; - let mediaVideoSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize'); - if (utils.isArray(mediaVideoSize)) { - mediaSize = mediaVideoSize; + const makeBids = (type, size) => { + let context = ''; + let streamType = 2; + + if (type === BANNER) { + streamType = 5; } else { - mediaSize = bid.mediaTypes.banner.sizes; - } - if (utils.isArray(mediaSize[0])) { - sizes = mediaSize[0]; - } else if (utils.isNumber(mediaSize[0])) { - sizes = mediaSize; + context = utils.deepAccess(bid, 'mediaTypes.video.context'); + if (vpaidMode && context === 'instream') { + streamType = 1; + } + if (context === 'outstream') { + streamType = 5; + } } - } - const context = utils.deepAccess(bid, 'mediaTypes.video.context'); - - let streamType = 2; + return { + type: streamType, + bidId: bid.bidId, + mediaType: type, + context: context, + playerId: utils.getBidIdParameter('playerId', bid.params), + auctionId: bidderRequest.auctionId, + bidderCode: BIDDER_CODE, + gdprConsent: bidderRequest.gdprConsent, + start: +new Date(), + timeout: 3000, + size: { + width: size[0], + height: size[1] + }, + params: bid.params, + schain: bid.schain || defaultSchain, + }; + }; - if (vpaidMode && context === 'instream') { - streamType = 1; - } - if (isBanner || context === 'outstream') { - streamType = 5; - } + videoSizes.forEach((size) => { + adUnits.push(makeBids(VIDEO, size)); + }); - return { - type: streamType, - bidId: bid.bidId, - mediaType: isBanner ? BANNER : VIDEO, - context: context, - playerId: utils.getBidIdParameter('playerId', bid.params), - auctionId: bidderRequest.auctionId, - bidderCode: BIDDER_CODE, - gdprConsent: bidderRequest.gdprConsent, - start: +new Date(), - timeout: 3000, - video: { - width: sizes[0], - height: sizes[1] - }, - params: bid.params, - }; + bannerSizes.forEach((size) => { + adUnits.push(makeBids(BANNER, size)); + }); }); return { @@ -94,6 +97,7 @@ export const spec = { data: { 'user': [], 'meta': { + 'adapterVersion': 2, 'pageURL': encodeURIComponent(pageURL), 'vastCacheEnabled': (!!config.getConfig('cache') && !isBanner && !outstreamOptions) || false, 'isDesktop': utils.getWindowTop().document.documentElement.clientWidth > 700, @@ -156,12 +160,12 @@ function createBids(bidRes, reqData) { bidUnit.cpm = bid.cpm; bidUnit.requestId = bid.bidId; bidUnit.currency = bid.currency; - bidUnit.mediaType = reqBid.mediaType || VIDEO; + bidUnit.mediaType = bid.mediaType || VIDEO; bidUnit.ttl = TTL; bidUnit.creativeId = 'c_' + bid.bidId; bidUnit.netRevenue = true; - bidUnit.width = bid.video.width; - bidUnit.height = bid.video.height; + bidUnit.width = bid.size.width; + bidUnit.height = bid.size.height; if (bid.vastXml) { bidUnit.vastXml = bid.vastXml; bidUnit.adResponse = { @@ -171,16 +175,16 @@ function createBids(bidRes, reqData) { if (bid.vastTag) { bidUnit.vastUrl = bid.vastTag; } - if (reqBid.mediaType === BANNER) { + if (bid.mediaType === BANNER) { bidUnit.ad = getBannerHtml(bid, reqBid, reqData); - } else if (reqBid.context === 'outstream') { + } else if (bid.context === 'outstream') { const renderer = Renderer.install({ id: bid.bidId, url: '//', config: { playerId: reqBid.playerId, - width: bid.video.width, - height: bid.video.height, + width: bid.size.width, + height: bid.size.height, vastUrl: bid.vastTag, vastXml: bid.vastXml, debug: reqData.debug, @@ -213,7 +217,7 @@ function outstreamRender(bid) { return; } - const slot = utils.getBidIdParameter('slot', bid.renderer.config); + const slot = utils.getBidIdParameter('slot', bid.renderer.config) || bid.adUnitCode; if (slot && window.document.getElementById(slot)) { window.document.getElementById(slot).appendChild(embedCode); } else if (slot) { @@ -267,4 +271,19 @@ function getBannerHtml (bid, reqBid, reqData) { `; } +function getVideoSizes(bidRequest) { + return formatSizes(utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize') || []); +} + +function getBannerSizes(bidRequest) { + return formatSizes(utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes') || []); +} + +function formatSizes(sizes) { + if (!sizes || !sizes.length) { + return [] + } + return Array.isArray(sizes[0]) ? sizes : [sizes]; +} + registerBidder(spec); diff --git a/modules/sigmoidAnalyticsAdapter.js b/modules/sigmoidAnalyticsAdapter.js index 95206fd2ea3..303fbbc8995 100644 --- a/modules/sigmoidAnalyticsAdapter.js +++ b/modules/sigmoidAnalyticsAdapter.js @@ -1,11 +1,14 @@ /* Sigmoid Analytics Adapter for prebid.js v1.1.0-pre Updated : 2018-03-28 */ -import includes from 'core-js/library/fn/array/includes'; -import adapter from '../src/AnalyticsAdapter'; +import includes from 'core-js-pure/features/array/includes.js'; +import adapter from '../src/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; -import adapterManager from '../src/adapterManager'; +import adapterManager from '../src/adapterManager.js'; +import { getStorageManager } from '../src/storageManager.js'; -const utils = require('../src/utils'); +const storage = getStorageManager(); + +const utils = require('../src/utils.js'); const url = 'https://kinesis.us-east-1.amazonaws.com/'; const analyticsType = 'endpoint'; @@ -54,31 +57,31 @@ function buildSessionIdTimeoutLocalStorageKey() { function updateSessionId() { if (isSessionIdTimeoutExpired()) { let newSessionId = utils.generateUUID(); - localStorage.setItem(buildSessionIdLocalStorageKey(), newSessionId); + storage.setDataInLocalStorage(buildSessionIdLocalStorageKey(), newSessionId); } initOptions.sessionId = getSessionId(); updateSessionIdTimeout(); } function updateSessionIdTimeout() { - localStorage.setItem(buildSessionIdTimeoutLocalStorageKey(), Date.now()); + storage.setDataInLocalStorage(buildSessionIdTimeoutLocalStorageKey(), Date.now()); } function isSessionIdTimeoutExpired() { - let cpmSessionTimestamp = localStorage.getItem(buildSessionIdTimeoutLocalStorageKey()); + let cpmSessionTimestamp = storage.getDataFromLocalStorage(buildSessionIdTimeoutLocalStorageKey()); return Date.now() - cpmSessionTimestamp > sessionTimeout; } function getSessionId() { - return localStorage.getItem(buildSessionIdLocalStorageKey()) ? localStorage.getItem(buildSessionIdLocalStorageKey()) : ''; + return storage.getDataFromLocalStorage(buildSessionIdLocalStorageKey()) ? storage.getDataFromLocalStorage(buildSessionIdLocalStorageKey()) : ''; } function updateUtmTimeout() { - localStorage.setItem(buildUtmLocalStorageTimeoutKey(), Date.now()); + storage.setDataInLocalStorage(buildUtmLocalStorageTimeoutKey(), Date.now()); } function isUtmTimeoutExpired() { - let utmTimestamp = localStorage.getItem(buildUtmLocalStorageTimeoutKey()); + let utmTimestamp = storage.getDataFromLocalStorage(buildUtmLocalStorageTimeoutKey()); return (Date.now() - utmTimestamp) > utmTimeout; } @@ -219,11 +222,11 @@ sigmoidAdapter.buildUtmTagData = function () { }); utmTags.forEach(function(utmTagKey) { if (utmTagsDetected) { - localStorage.setItem(buildUtmLocalStorageKey(utmTagKey), utmTagData[utmTagKey]); + storage.setDataInLocalStorage(buildUtmLocalStorageKey(utmTagKey), utmTagData[utmTagKey]); updateUtmTimeout(); } else { if (!isUtmTimeoutExpired()) { - utmTagData[utmTagKey] = localStorage.getItem(buildUtmLocalStorageKey(utmTagKey)) ? localStorage.getItem(buildUtmLocalStorageKey(utmTagKey)) : ''; + utmTagData[utmTagKey] = storage.getDataFromLocalStorage(buildUtmLocalStorageKey(utmTagKey)) ? storage.getDataFromLocalStorage(buildUtmLocalStorageKey(utmTagKey)) : ''; updateUtmTimeout(); } } diff --git a/modules/sizeMappingV2.js b/modules/sizeMappingV2.js new file mode 100644 index 00000000000..20ab640990b --- /dev/null +++ b/modules/sizeMappingV2.js @@ -0,0 +1,554 @@ +/** + * 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. + */ + +import * as utils from '../src/utils.js'; +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'; + +// allows for sinon.spy, sinon.stub, etc to unit test calls made to these functions internally +export const internal = { + checkBidderSizeConfigFormat, + getActiveSizeBucket, + getFilteredMediaTypes, + getAdUnitDetail, + getRelevantMediaTypesForBidder, + 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. +export const sizeMappingInternalStore = createSizeMappingInternalStore(); + +function createSizeMappingInternalStore() { + const sizeMappingInternalStore = {}; + + return { + initializeStore: function (auctionId, isUsingSizeMappingBool) { + sizeMappingInternalStore[auctionId] = { + usingSizeMappingV2: isUsingSizeMappingBool, + adUnits: [] + }; + }, + getAuctionDetail: function (auctionId) { + return sizeMappingInternalStore[auctionId]; + }, + 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 +export function isUsingNewSizeMapping(adUnits) { + let isUsingSizeMappingBool = false; + adUnits.forEach(adUnit => { + if (adUnit.mediaTypes) { + // checks for the presence of sizeConfig property at the adUnit.mediaTypes object + Object.keys(adUnit.mediaTypes).forEach(mediaType => { + if (adUnit.mediaTypes[mediaType].sizeConfig) { + if (isUsingSizeMappingBool === false) { + isUsingSizeMappingBool = true; + } + } + }); + + // checks for the presence of sizeConfig property at the adUnit.bids[].bidder object + adUnit.bids.forEach(bidder => { + if (bidder.sizeConfig) { + if (isUsingSizeMappingBool === false) { + isUsingSizeMappingBool = true; + } + } + }); + } + }); + return isUsingSizeMappingBool; +} + +// returns "adUnits" array which have passed sizeConfig validation checks in addition to mediaTypes checks +// deletes properties from adUnit which fail validation. +export function checkAdUnitSetupHook(adUnits) { + return adUnits.filter(adUnit => { + const mediaTypes = adUnit.mediaTypes; + 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; + } + + 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 (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; + } + } + + 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 (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); + + 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; + } + }); + } + } + + return true; + }); +} + +getHook('checkAdUnitSetup').before(function (fn, adUnits) { + const usingNewSizeMapping = isUsingNewSizeMapping(adUnits); + if (usingNewSizeMapping) { + // if adUnits are found using the sizeMappingV2 spec, we run additional checks on them for checking the validity of sizeConfig object + // in addition to running the base checks on the mediaType object and return the adUnit without calling the base function. + adUnits = checkAdUnitSetupHook(adUnits); + return fn.bail(adUnits); + } else { + // if presence of sizeMappingV2 spec is not detected on adUnits, we default back to the original checks defined in the base function. + return fn.call(this, adUnits); + } +}); + +// checks if the sizeConfig object declared at the Bidder level is in the right format or not. +export function checkBidderSizeConfigFormat(sizeConfig) { + let didCheckPass = true; + if (Array.isArray(sizeConfig) && sizeConfig.length > 0) { + sizeConfig.forEach(config => { + const keys = Object.keys(config); + if ((includes(keys, 'minViewPort') && + includes(keys, 'relevantMediaTypes')) && + utils.isArrayOfNums(config.minViewPort, 2) && + 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))) { + didCheckPass = didCheckPass && true; + } else { + didCheckPass = false; + } + }); + } else { + didCheckPass = false; + } + return didCheckPass; +} + +getHook('getBids').before(function (fn, bidderInfo) { + // check if the adUnit is using sizeMappingV2 specs and store the result in _sizeMappingUsageMap. + if (typeof sizeMappingInternalStore.getAuctionDetail(bidderInfo.auctionId) === 'undefined') { + const isUsingSizeMappingBool = isUsingNewSizeMapping(bidderInfo.adUnits); + + // initialize sizeMappingInternalStore for the first time for a particular auction + sizeMappingInternalStore.initializeStore(bidderInfo.auctionId, isUsingSizeMappingBool); + } + 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 { + // if not using sizeMappingV2, default back to the getBids function defined in adapterManager. + return fn.call(this, 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 {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, 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}(${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}(${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}(${adUnitInstance}) => Ad unit has declared property 'labelAny' with an empty array.`); + return true; + } + return bidOrAdUnit.labelAny.some(label => includes(activeLabels, label)); + } + return true; +} + +/** + * Processes the MediaTypes object and calculates the active size buckets for each Media Type. Uses `window.innerWidth` and `window.innerHeight` + * to calculate the width and height of the active Viewport. + * @param {MediaTypes} mediaTypes Contains information about supported media types for an Ad Unit and size information for each of those types + * @returns {FilteredMediaTypes} Filtered mediaTypes object with relevant media types filtered by size buckets based on activeViewPort size + */ +export function getFilteredMediaTypes(mediaTypes) { + let + activeViewportWidth, + activeViewportHeight, + transformedMediaTypes; + + transformedMediaTypes = utils.deepClone(mediaTypes); + + let activeSizeBucket = { + banner: undefined, + video: undefined, + native: undefined + } + + try { + activeViewportWidth = utils.getWindowTop().innerWidth; + activeViewportHeight = utils.getWindowTop().innerHeight; + } catch (e) { + utils.logWarn(`SizeMappingv2:: Unfriendly iframe blocks viewport size to be evaluated correctly`); + activeViewportWidth = window.innerWidth; + activeViewportHeight = window.innerHeight; + } + const activeViewport = [activeViewportWidth, activeViewportHeight]; + Object.keys(mediaTypes).map(mediaType => { + const sizeConfig = mediaTypes[mediaType].sizeConfig; + if (sizeConfig) { + activeSizeBucket[mediaType] = getActiveSizeBucket(sizeConfig, activeViewport); + const filteredSizeConfig = sizeConfig.filter(config => config.minViewPort === activeSizeBucket[mediaType] && isSizeConfigActivated(mediaType, config)); + transformedMediaTypes[mediaType] = Object.assign({ filteredSizeConfig }, mediaTypes[mediaType]); + + // transform mediaTypes object + const config = { + banner: 'sizes', + video: 'playerSize' + }; + + if (transformedMediaTypes[mediaType].filteredSizeConfig.length > 0) { + // map sizes or playerSize property in filteredSizeConfig object to transformedMediaTypes.banner.sizes if mediaType is banner + // or transformedMediaTypes.video.playerSize if the mediaType in video. + // doesn't apply to native mediaType since native doesn't have any property defining 'sizes' or 'playerSize'. + if (mediaType !== 'native') { + transformedMediaTypes[mediaType][config[mediaType]] = transformedMediaTypes[mediaType].filteredSizeConfig[0][config[mediaType]]; + } + } else { + delete transformedMediaTypes[mediaType]; + } + } + }) + + // filter out 'undefined' values from activeSizeBucket object and attach sizes/playerSize information against the active size bucket. + const sizeBucketToSizeMap = Object + .keys(activeSizeBucket) + .filter(mediaType => activeSizeBucket[mediaType] !== undefined) + .reduce((sizeBucketToSizeMap, mediaType) => { + sizeBucketToSizeMap[mediaType] = { + activeSizeBucket: activeSizeBucket[mediaType], + activeSizeDimensions: (mediaType === 'banner') ? ( + // 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 + (transformedMediaTypes.video) ? (transformedMediaTypes.video.playerSize) : ([]) + ) : ('NA')) + }; + return sizeBucketToSizeMap; + }, {}); + + return { mediaTypes, sizeBucketToSizeMap, activeViewport, transformedMediaTypes }; +}; + +/** + * Evaluates the given sizeConfig object and checks for various properties to determine if the sizeConfig is active or not. For example, + * let's suppose the sizeConfig is for a Banner media type. Then, if the sizes property is found empty, it returns false, else returns true. + * In case of a Video media type, it checks the playerSize property. If found empty, returns false, else returns true. + * In case of a Native media type, it checks the active property. If found false, returns false, if found true, returns true. + * @param {string} mediaType It can be 'banner', 'native' or 'video' + * @param {Object} sizeConfig Represents the sizeConfig object which is active based on the current viewport size + * @returns {boolean} Represents if the size config is active or not + */ +export function isSizeConfigActivated(mediaType, sizeConfig) { + switch (mediaType) { + case 'banner': + // we need this check, sizeConfig.sizes[0].length > 0, in place because a sizeBucket can have sizes: [], + // gets converted to sizes: [[]] in the checkAdUnitSetupHook function + return sizeConfig.sizes && sizeConfig.sizes.length > 0 && sizeConfig.sizes[0].length > 0; + case 'video': + // for why we need the last check, read the above comment + return sizeConfig.playerSize && sizeConfig.playerSize.length > 0 && sizeConfig.playerSize[0].length > 0; + case 'native': + return sizeConfig.active; + default: + return false; + } +} + +/** + * Returns the active size bucket for a given media type + * @param {Array} sizeConfig SizeConfig defines the characteristics of an Ad Unit categorised into multiple size buckets per media type + * @param {Array} activeViewport Viewport size of the browser in the form [w, h] (w -> width, h -> height) + * Calculated at the time of making call to pbjs.requestBids function + * @returns {Array} The active size bucket matching the activeViewPort, for example: [750, 0] + */ +export function getActiveSizeBucket(sizeConfig, activeViewport) { + let activeSizeBucket = []; + sizeConfig + .sort((a, b) => a.minViewPort[0] - b.minViewPort[0]) + .forEach(config => { + if (activeViewport[0] >= config.minViewPort[0]) { + if (activeViewport[1] >= config.minViewPort[1]) { + activeSizeBucket = config.minViewPort; + } else { + activeSizeBucket = []; + } + } + }) + return activeSizeBucket; +} + +export function getRelevantMediaTypesForBidder(sizeConfig, activeViewport) { + if (internal.checkBidderSizeConfigFormat(sizeConfig)) { + const activeSizeBucket = internal.getActiveSizeBucket(sizeConfig, activeViewport); + return sizeConfig.filter(config => config.minViewPort === activeSizeBucket)[0]['relevantMediaTypes']; + } + return []; +} + +// 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, labels) { + // fetch all adUnits for an auction from the sizeMappingInternalStore + const adUnitsForAuction = sizeMappingInternalStore.getAuctionDetail(auctionId).adUnits; + + // check if the adUnit exists already in the sizeMappingInterStore (check for equivalence of 'code' && 'mediaTypes' properties) + 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 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, + instance: adUnitInstance, + isLabelActivated, + cacheHits: 0 + }; + + // set adUnitDetail in sizeMappingInternalStore against the correct 'auctionId'. + sizeMappingInternalStore.setAuctionDetail(auctionId, adUnitDetail); + isLabelActivated && utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}(${adUnitInstance}) => Active size buckets after filtration: `, sizeBucketToSizeMap); + + return adUnitDetail; + } +} + +export function getBids({ bidderCode, auctionId, bidderRequestId, adUnits, labels, src }) { + return adUnits.reduce((result, 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) { + 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, adUnitInstance)) { + // handle native params + const nativeParams = adUnit.nativeParams || utils.deepAccess(adUnit, 'mediaTypes.native'); + if (nativeParams) { + bid = Object.assign({}, bid, { + nativeParams: processNativeAdUnitParams(nativeParams) + }); + } + + bid = Object.assign({}, bid, utils.getDefinedParams(adUnit, ['mediaType', 'renderer'])); + + if (bid.sizeConfig) { + const relevantMediaTypes = internal.getRelevantMediaTypesForBidder(bid.sizeConfig, activeViewport); + if (relevantMediaTypes.length === 0) { + 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 + .keys(transformedMediaTypes) + .filter(mt => relevantMediaTypes.indexOf(mt) > -1) + .reduce((mediaTypes, mediaType) => { + mediaTypes[mediaType] = transformedMediaTypes[mediaType]; + return mediaTypes; + }, {}); + + if (Object.keys(bidderMediaTypes).length > 0) { + bid = Object.assign({}, bid, { mediaTypes: bidderMediaTypes }); + } else { + 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}(${adUnitInstance}), Bidder: ${bid.bidder} => 'relevantMediaTypes' is set to 'none' in sizeConfig for current viewport size. This bidder is disabled.`); + return bids; + } + } + bids.push(Object.assign({}, bid, { + adUnitCode: adUnit.code, + transactionId: adUnit.transactionId, + sizes: utils.deepAccess(transformedMediaTypes, 'banner.sizes') || utils.deepAccess(transformedMediaTypes, 'video.playerSize') || [], + mediaTypes: bid.mediaTypes || transformedMediaTypes, + bidId: bid.bid_id || utils.getUniqueIdentifierStr(), + bidderRequestId, + auctionId, + src, + bidRequestsCount: adunitCounter.getRequestsCounter(adUnit.code), + bidderRequestsCount: adunitCounter.getBidderRequestsCounter(adUnit.code, bid.bidder), + bidderWinsCount: adunitCounter.getBidderWinsCounter(adUnit.code, bid.bidder) + })); + return bids; + } else { + 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 { + cacheHits === 0 && utils.logInfo(`Size Mapping V2:: Ad Unit: ${adUnit.code}(${adUnitInstance}) => Ad unit is disabled due to failing label check.`); + } + } else { + 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; + }, []).reduce(utils.flatten, []).filter(val => val !== ''); +} diff --git a/modules/slimcutBidAdapter.js b/modules/slimcutBidAdapter.js index 2aa75853301..d717f3a88bd 100644 --- a/modules/slimcutBidAdapter.js +++ b/modules/slimcutBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { ajax } from '../src/ajax'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { ajax } from '../src/ajax.js'; const BIDDER_CODE = 'slimcut'; const ENDPOINT_URL = 'https://sb.freeskreen.com/pbr'; diff --git a/modules/smartadserverBidAdapter.js b/modules/smartadserverBidAdapter.js index 1e14195d38a..97dd43fc5ba 100644 --- a/modules/smartadserverBidAdapter.js +++ b/modules/smartadserverBidAdapter.js @@ -1,14 +1,17 @@ -import * as utils from '../src/utils'; +import * as utils from '../src/utils.js'; import { BANNER, VIDEO -} from '../src/mediaTypes'; +} from '../src/mediaTypes.js'; import { config -} from '../src/config'; +} from '../src/config.js'; import { registerBidder -} from '../src/adapters/bidderFactory'; +} from '../src/adapters/bidderFactory.js'; +import { + createEidsArray +} from './userId/eids.js'; const BIDDER_CODE = 'smartadserver'; export const spec = { code: BIDDER_CODE, @@ -23,38 +26,54 @@ export const spec = { isBidRequestValid: function (bid) { return !!(bid.params && bid.params.siteId && bid.params.pageId && bid.params.formatId); }, + + /** + * Serialize a supply chain object to a string uri encoded + * + * @param {*} schain object + */ + serializeSupplyChain: function(schain) { + if (!schain || !schain.nodes) return null; + const nodesProperties = ['asi', 'sid', 'hp', 'rid', 'name', 'domain']; + return `${schain.ver},${schain.complete}!` + + schain.nodes.map(node => nodesProperties.map(prop => + node[prop] ? encodeURIComponent(node[prop]) : '') + .join(',')) + .join('!'); + }, + /** * Make a server request from the list of BidRequests. * - * @param {validBidRequests[]} - an array of bids - * @param {bidderRequest} - bidder request object - * @return ServerRequest Info describing the request to the server. + * @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. - var payload = { + let payload = { siteid: bid.params.siteId, pageid: bid.params.pageId, formatid: bid.params.formatId, currencyCode: config.getConfig('currency.adServerCurrency'), bidfloor: bid.params.bidfloor || 0.0, - targeting: bid.params.target && bid.params.target != '' ? bid.params.target : undefined, - buid: bid.params.buId && bid.params.buId != '' ? bid.params.buId : undefined, - appname: bid.params.appName && bid.params.appName != '' ? bid.params.appName : undefined, + targeting: bid.params.target && bid.params.target !== '' ? bid.params.target : undefined, + buid: bid.params.buId && bid.params.buId !== '' ? bid.params.buId : undefined, + appname: bid.params.appName && bid.params.appName !== '' ? bid.params.appName : undefined, ckid: bid.params.ckId || 0, tagId: bid.adUnitCode, pageDomain: bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer ? bidderRequest.refererInfo.referer : undefined, transactionId: bid.transactionId, timeout: config.getConfig('bidderTimeout'), bidId: bid.bidId, - prebidVersion: '$prebid.version$' + prebidVersion: '$prebid.version$', + schain: spec.serializeSupplyChain(bid.schain) }; const videoMediaType = utils.deepAccess(bid, 'mediaTypes.video'); @@ -66,13 +85,13 @@ export const spec = { })); } else if (videoMediaType && videoMediaType.context === 'instream') { // Specific attributes for instream. - var playerSize = videoMediaType.playerSize[0]; + let playerSize = videoMediaType.playerSize[0]; payload.isVideo = true; payload.videoData = { 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 {}; @@ -83,7 +102,16 @@ 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; + } + var payloadString = JSON.stringify(payload); + return { method: 'POST', url: (bid.params.domain !== undefined ? bid.params.domain : 'https://prg.smartadserver.com') + '/prebid/v1', @@ -91,20 +119,22 @@ export const spec = { }; }); }, + /** * 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 = []; - var response = serverResponse.body; + let response = serverResponse.body; try { if (response) { const bidRequest = JSON.parse(bidRequestString.data); - var bidResponse = { + let bidResponse = { requestId: bidRequest.bidId, cpm: response.cpm, width: response.width, @@ -132,15 +162,16 @@ export const spec = { } return bidResponses; }, + /** * User syncs. * * @param {*} syncOptions Publisher prebid configuration. * @param {*} serverResponses A successful response from the server. - * @return {Syncs[]} An array of syncs that should be executed. + * @return {syncs[]} An array of syncs that should be executed. */ getUserSyncs: function (syncOptions, serverResponses) { - const syncs = [] + const syncs = []; if (syncOptions.iframeEnabled && serverResponses.length > 0) { syncs.push({ type: 'iframe', @@ -149,5 +180,6 @@ export const spec = { } return syncs; } -} +}; + registerBidder(spec); diff --git a/modules/smartadserverBidAdapter.md b/modules/smartadserverBidAdapter.md index 84fe5ff8afc..c6f68363d7c 100644 --- a/modules/smartadserverBidAdapter.md +++ b/modules/smartadserverBidAdapter.md @@ -29,7 +29,7 @@ Please reach out to your Technical account manager for more information. { bidder: "smart", params: { - domain: 'https://ww251.smartadserver.com', + domain: 'https://prg.smartadserver.com', siteId: 207435, pageId: 896536, formatId: 62913, @@ -55,7 +55,7 @@ Please reach out to your Technical account manager for more information. { bidder: "smart", params: { - domain: 'https://ww251.smartadserver.com', + domain: 'https://prg.smartadserver.com', siteId: 207435, pageId: 896536, formatId: 65906, @@ -82,14 +82,14 @@ Please reach out to your Technical account manager for more information. bids: [{ bidder: "smart", params: { - domain: 'https://ww251.smartadserver.com', + domain: 'https://prg.smartadserver.com', siteId: 326147, pageId: 1153895, - formatId: 55710 + formatId: 55710, bidfloor: 5, video: { protocol: 6, - startDelay: 0 + startDelay: 1 } } }] diff --git a/modules/smartrtbBidAdapter.js b/modules/smartrtbBidAdapter.js index 43304aa50c0..12d5a0ae7da 100644 --- a/modules/smartrtbBidAdapter.js +++ b/modules/smartrtbBidAdapter.js @@ -1,7 +1,7 @@ -import * as utils from '../src/utils'; -import { config } from '../src/config'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'smartrtb'; function getDomain () { diff --git a/modules/smartyadsBidAdapter.js b/modules/smartyadsBidAdapter.js new file mode 100644 index 00000000000..ff60d08e48b --- /dev/null +++ b/modules/smartyadsBidAdapter.js @@ -0,0 +1,106 @@ +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 = 'smartyads'; +const AD_URL = 'https://ssp-nj.webtradehub.com/?c=o&m=multi'; +const URL_SYNC = 'https://ssp-nj.webtradehub.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(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 : '', + 'secure': 1, + 'host': location.host, + 'page': location.pathname, + 'placements': placements + }; + request.language.indexOf('-') != -1 && (request.language = request.language.split('-')[0]) + if (bidderRequest) { + if (bidderRequest.uspConsent) { + request.ccpa = bidderRequest.uspConsent; + } + if (bidderRequest.gdprConsent) { + request.gdpr = bidderRequest.gdprConsent + } + } + const len = validBidRequests.length; + + for (let i = 0; i < len; i++) { + let bid = validBidRequests[i]; + let traff = bid.params.traffic || BANNER + placements.push({ + placementId: bid.params.placementId, + bidId: bid.bidId, + sizes: bid.mediaTypes && bid.mediaTypes[traff] && bid.mediaTypes[traff].sizes ? bid.mediaTypes[traff].sizes : [], + traffic: traff + }); + if (bid.schain) { + placements.schain = bid.schain; + } + } + return { + method: 'POST', + url: AD_URL, + data: request + }; + }, + + interpretResponse: (serverResponse) => { + let response = []; + serverResponse = serverResponse.body; + for (let i = 0; i < serverResponse.length; i++) { + let resItem = serverResponse[i]; + if (isBidResponseValid(resItem)) { + response.push(resItem); + } + } + return response; + }, + + getUserSyncs: (syncOptions, serverResponses) => { + return [{ + type: 'image', + url: URL_SYNC + }]; + } + +}; + +registerBidder(spec); diff --git a/modules/smartyadsBidAdapter.md b/modules/smartyadsBidAdapter.md index 5102a6fd128..4fe4d51a2e6 100644 --- a/modules/smartyadsBidAdapter.md +++ b/modules/smartyadsBidAdapter.md @@ -12,16 +12,59 @@ Module that connects to SmartyAds' demand sources # Test Parameters ``` - var adUnits = [{ - code: 'placementId_0', - sizes: [[300, 250]], - bids: [{ - bidder: 'smartyads', - params: { - placementId: 0, - traffic: 'banner' + var adUnits = [ + // Will return static native ad. Assets are stored through user UI for each placement separetly + { + code: 'placementId_0', + mediaTypes: { + native: {} + }, + bids: [ + { + bidder: 'smartyads', + params: { + placementId: 0, + traffic: 'native' + } } - }] + ] + }, + // Will return static test banner + { + code: 'placementId_0', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: 'smartyads', + 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: 'smartyads', + params: { + placementId: 0, + traffic: 'video' + } + } + ] } ]; -``` \ No newline at end of file +``` diff --git a/modules/smilewantedBidAdapter.js b/modules/smilewantedBidAdapter.js index ed7e02a51a8..f965310abdd 100644 --- a/modules/smilewantedBidAdapter.js +++ b/modules/smilewantedBidAdapter.js @@ -1,8 +1,8 @@ -import * as utils from '../src/utils'; -import { Renderer } from '../src/Renderer'; -import { config } from '../src/config'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import { Renderer } from '../src/Renderer.js'; +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; export const spec = { code: 'smilewanted', diff --git a/modules/smmsBidAdapter.js b/modules/smmsBidAdapter.js index 2f856d0f96e..670caebe61b 100644 --- a/modules/smmsBidAdapter.js +++ b/modules/smmsBidAdapter.js @@ -1,5 +1,5 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'smms'; const ENDPOINT_BANNER = 'https://bidder.mediams.mb.softbank.jp/api/v1/prebid/banner'; diff --git a/modules/somoBidAdapter.js b/modules/somoBidAdapter.js index e043ad83f7b..c6e31790005 100644 --- a/modules/somoBidAdapter.js +++ b/modules/somoBidAdapter.js @@ -1,7 +1,7 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import includes from 'core-js/library/fn/array/includes'; -import {BANNER, VIDEO} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; const VIDEO_TARGETING = ['mimes', 'minduration', 'maxduration', 'protocols', 'startdelay', 'linearity', 'skip', 'delivery', diff --git a/modules/sonobiAnalyticsAdapter.js b/modules/sonobiAnalyticsAdapter.js index ab110cb4d01..d69276e915c 100644 --- a/modules/sonobiAnalyticsAdapter.js +++ b/modules/sonobiAnalyticsAdapter.js @@ -1,9 +1,9 @@ -import adapter from '../src/AnalyticsAdapter'; +import adapter from '../src/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; -import adapterManager from '../src/adapterManager'; -import {ajaxBuilder} from '../src/ajax'; +import adapterManager from '../src/adapterManager.js'; +import {ajaxBuilder} from '../src/ajax.js'; -const utils = require('../src/utils'); +const utils = require('../src/utils.js'); let ajax = ajaxBuilder(0); const DEFAULT_EVENT_URL = 'apex.go.sonobi.com/keymaker'; diff --git a/modules/sonobiBidAdapter.js b/modules/sonobiBidAdapter.js index 65565a0d962..a55992cec22 100644 --- a/modules/sonobiBidAdapter.js +++ b/modules/sonobiBidAdapter.js @@ -1,14 +1,13 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { parseSizesInput, logError, generateUUID, isEmpty, deepAccess, logWarn, logMessage } from '../src/utils'; -import { BANNER, VIDEO } from '../src/mediaTypes'; -import { config } from '../src/config'; -import { Renderer } from '../src/Renderer'; -import { userSync } from '../src/userSync'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { parseSizesInput, logError, generateUUID, isEmpty, deepAccess, logWarn, logMessage } from '../src/utils.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; +import { Renderer } from '../src/Renderer.js'; +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) } @@ -143,9 +135,15 @@ export const spec = { return null; } + let url = STR_ENDPOINT; + + if (deepAccess(validBidRequests[0], 'params.bid_request_url')) { + url = deepAccess(validBidRequests[0], 'params.bid_request_url'); + } + return { method: 'GET', - url: STR_ENDPOINT, + url: url, withCredentials: true, data: payload, bidderRequests: validBidRequests @@ -330,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/sortableAnalyticsAdapter.js b/modules/sortableAnalyticsAdapter.js index 17458065f9a..73ce1393c23 100644 --- a/modules/sortableAnalyticsAdapter.js +++ b/modules/sortableAnalyticsAdapter.js @@ -1,10 +1,10 @@ -import adapter from '../src/AnalyticsAdapter'; +import adapter from '../src/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; -import adapterManager from '../src/adapterManager'; -import * as utils from '../src/utils'; -import {ajax} from '../src/ajax'; -import {getGlobal} from '../src/prebidGlobal'; -import { config } from '../src/config'; +import adapterManager from '../src/adapterManager.js'; +import * as utils from '../src/utils.js'; +import {ajax} from '../src/ajax.js'; +import {getGlobal} from '../src/prebidGlobal.js'; +import { config } from '../src/config.js'; const DEFAULT_PROTOCOL = 'https'; const DEFAULT_HOST = 'pa.deployads.com'; diff --git a/modules/sortableBidAdapter.js b/modules/sortableBidAdapter.js new file mode 100644 index 00000000000..f5d3a6b1bb5 --- /dev/null +++ b/modules/sortableBidAdapter.js @@ -0,0 +1,342 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'sortable'; +const SERVER_URL = 'https://c.deployads.com'; + +function setAssetRequired(native, asset) { + if (native.required) { + asset.required = 1; + } + return asset; +} + +function buildNativeRequest(nativeMediaType) { + const assets = []; + const title = nativeMediaType.title; + if (title) { + assets.push(setAssetRequired(title, { + title: {len: title.len} + })); + } + const img = nativeMediaType.image; + if (img) { + assets.push(setAssetRequired(img, { + img: { + type: 3, // Main + wmin: 1, + hmin: 1 + } + })); + } + const icon = nativeMediaType.icon; + if (icon) { + assets.push(setAssetRequired(icon, { + img: { + type: 1, // Icon + wmin: 1, + hmin: 1 + } + })); + } + const body = nativeMediaType.body; + if (body) { + assets.push(setAssetRequired(body, {data: {type: 2}})); + } + const cta = nativeMediaType.cta; + if (cta) { + assets.push(setAssetRequired(cta, {data: {type: 12}})); + } + const sponsoredBy = nativeMediaType.sponsoredBy; + if (sponsoredBy) { + assets.push(setAssetRequired(sponsoredBy, {data: {type: 1}})); + } + + utils._each(assets, (asset, id) => asset.id = id); + return { + ver: '1', + request: JSON.stringify({ + ver: '1', + assets + }) + }; +} + +function tryParseNativeResponse(adm) { + let native = null; + try { + native = JSON.parse(adm); + } catch (e) { + utils.logError('Sortable bid adapter unable to parse native bid response:\n\n' + e); + } + return native && native.native; +} + +function createImgObject(img) { + if (img.w || img.h) { + return { + url: img.url, + width: img.w, + height: img.h + }; + } else { + return img.url; + } +} + +function interpretNativeResponse(response) { + const native = {}; + if (response.link) { + native.clickUrl = response.link.url; + } + utils._each(response.assets, asset => { + switch (asset.id) { + case 1: + native.title = asset.title.text; + break; + case 2: + native.image = createImgObject(asset.img); + break; + case 3: + native.icon = createImgObject(asset.img); + break; + case 4: + native.body = asset.data.value; + break; + case 5: + native.cta = asset.data.value; + break; + case 6: + native.sponsoredBy = asset.data.value; + break; + } + }); + return native; +} + +function transformSyncs(responses, type, syncs) { + utils._each(responses, res => { + if (res.body && res.body.ext && res.body.ext.sync_dsps && res.body.ext.sync_dsps.length) { + utils._each(res.body.ext.sync_dsps, sync => { + if (sync[0] === type && sync[1]) { + syncs.push({type, url: sync[1]}); + } + }); + } + }); +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, NATIVE, VIDEO], + + isBidRequestValid: function(bid) { + const sortableConfig = config.getConfig('sortable'); + const haveSiteId = (sortableConfig && !!sortableConfig.siteId) || bid.params.siteId; + const validFloor = !bid.params.floor || utils.isNumber(bid.params.floor); + const validSize = /\d+x\d+/; + const validFloorSizeMap = !bid.params.floorSizeMap || + (utils.isPlainObject(bid.params.floorSizeMap) && + Object.keys(bid.params.floorSizeMap).every(size => + size.match(validSize) && utils.isNumber(bid.params.floorSizeMap[size]) + )) + const validKeywords = !bid.params.keywords || + (utils.isPlainObject(bid.params.keywords) && + Object.keys(bid.params.keywords).every(key => + utils.isStr(key) && utils.isStr(bid.params.keywords[key]) + )) + const isBanner = !bid.mediaTypes || bid.mediaTypes[BANNER] || !(bid.mediaTypes[NATIVE] || bid.mediaTypes[VIDEO]); + const bannerSizes = isBanner ? utils.deepAccess(bid, `mediaType.${BANNER}.sizes`) || bid.sizes : null; + return !!(bid.params.tagId && haveSiteId && validFloor && validFloorSizeMap && validKeywords && (!isBanner || + (bannerSizes && bannerSizes.length > 0 && bannerSizes.every(sizeArr => sizeArr.length == 2 && sizeArr.every(num => utils.isNumber(num)))))); + }, + + buildRequests: function(validBidReqs, bidderRequest) { + const sortableConfig = config.getConfig('sortable') || {}; + const globalSiteId = sortableConfig.siteId; + let loc = utils.parseUrl(bidderRequest.refererInfo.referer); + + const sortableImps = utils._map(validBidReqs, bid => { + const rv = { + id: bid.bidId, + tagid: bid.params.tagId, + ext: {} + }; + const bannerMediaType = utils.deepAccess(bid, `mediaTypes.${BANNER}`); + const nativeMediaType = utils.deepAccess(bid, `mediaTypes.${NATIVE}`); + const videoMediaType = utils.deepAccess(bid, `mediaTypes.${VIDEO}`); + if (bannerMediaType || !(nativeMediaType || videoMediaType)) { + const bannerSizes = (bannerMediaType && bannerMediaType.sizes) || bid.sizes; + rv.banner = { + format: utils._map(bannerSizes, ([width, height]) => ({w: width, h: height})) + }; + } + if (nativeMediaType) { + rv.native = buildNativeRequest(nativeMediaType); + } + if (videoMediaType && videoMediaType.context === 'instream') { + const video = {placement: 1}; + video.mimes = videoMediaType.mimes || []; + video.minduration = utils.deepAccess(bid, 'params.video.minduration') || 10; + video.maxduration = utils.deepAccess(bid, 'params.video.maxduration') || 60; + const startDelay = utils.deepAccess(bid, 'params.video.startdelay'); + if (startDelay != null) { + video.startdelay = startDelay; + } + if (videoMediaType.playerSize && videoMediaType.playerSize.length) { + const size = videoMediaType.playerSize[0]; + video.w = size[0]; + video.h = size[1]; + } + if (videoMediaType.api) { + video.api = videoMediaType.api; + } + if (videoMediaType.protocols) { + video.protocols = videoMediaType.protocols; + } + if (videoMediaType.playbackmethod) { + video.playbackmethod = videoMediaType.playbackmethod; + } + rv.video = video; + } + if (bid.params.floor) { + rv.bidfloor = bid.params.floor; + } + if (bid.params.keywords) { + rv.ext.keywords = bid.params.keywords; + } + if (bid.params.bidderParams) { + utils._each(bid.params.bidderParams, (params, partner) => { + rv.ext[partner] = params; + }); + } + if (bid.params.floorSizeMap) { + rv.ext.floorSizeMap = bid.params.floorSizeMap; + } + return rv; + }); + const gdprConsent = bidderRequest && bidderRequest.gdprConsent; + const sortableBidReq = { + id: utils.getUniqueIdentifierStr(), + imp: sortableImps, + source: { + ext: { + schain: validBidReqs[0].schain + } + }, + regs: { + ext: {} + }, + site: { + domain: loc.hostname, + page: loc.href, + ref: loc.href, + publisher: { + id: globalSiteId || validBidReqs[0].params.siteId, + }, + device: { + w: screen.width, + h: screen.height + }, + }, + }; + if (bidderRequest && bidderRequest.timeout > 0) { + sortableBidReq.tmax = bidderRequest.timeout; + } + if (gdprConsent) { + sortableBidReq.user = { + ext: { + consent: gdprConsent.consentString + } + }; + if (typeof gdprConsent.gdprApplies == 'boolean') { + sortableBidReq.regs.ext.gdpr = gdprConsent.gdprApplies ? 1 : 0 + } + } + if (bidderRequest.uspConsent) { + sortableBidReq.regs.ext.us_privacy = bidderRequest.uspConsent; + } + return { + method: 'POST', + url: `${SERVER_URL}/openrtb2/auction?src=$$REPO_AND_VERSION$$&host=${loc.hostname}`, + data: JSON.stringify(sortableBidReq), + options: {contentType: 'text/plain'} + }; + }, + + interpretResponse: function(serverResponse) { + const { body: {id, seatbid} } = serverResponse; + const sortableBids = []; + if (id && seatbid) { + utils._each(seatbid, seatbid => { + utils._each(seatbid.bid, bid => { + const bidObj = { + requestId: bid.impid, + cpm: parseFloat(bid.price), + width: parseInt(bid.w), + height: parseInt(bid.h), + creativeId: bid.crid || bid.id, + dealId: bid.dealid || null, + currency: 'USD', + netRevenue: true, + mediaType: BANNER, + ttl: 60 + }; + if (bid.adm) { + const adFormat = utils.deepAccess(bid, 'ext.ad_format') + if (adFormat === 'native') { + let native = tryParseNativeResponse(bid.adm); + if (!native) { + return; + } + bidObj.mediaType = NATIVE; + bidObj.native = interpretNativeResponse(native); + } else if (adFormat === 'instream') { + bidObj.mediaType = VIDEO; + bidObj.vastXml = bid.adm; + } else { + bidObj.mediaType = BANNER; + bidObj.ad = bid.adm; + if (bid.nurl) { + bidObj.ad += utils.createTrackPixelHtml(decodeURIComponent(bid.nurl)); + } + } + } else if (bid.nurl) { + bidObj.adUrl = bid.nurl; + } + if (bid.ext) { + bidObj[BIDDER_CODE] = bid.ext; + } + sortableBids.push(bidObj); + }); + }); + } + return sortableBids; + }, + + getUserSyncs: (syncOptions, responses) => { + const syncs = []; + if (syncOptions.iframeEnabled) { + transformSyncs(responses, 'iframe', syncs); + } + if (syncOptions.pixelEnabled) { + transformSyncs(responses, 'image', syncs); + } + return syncs; + }, + + onTimeout(details) { + fetch(`${SERVER_URL}/prebid/timeout`, { + method: 'POST', + body: JSON.stringify(details), + mode: 'no-cors', + headers: new Headers({ + 'Content-Type': 'text/plain' + }) + }); + } +}; + +registerBidder(spec); diff --git a/modules/sortableBidAdapter.md b/modules/sortableBidAdapter.md index 027d6390e87..c24ad85b752 100644 --- a/modules/sortableBidAdapter.md +++ b/modules/sortableBidAdapter.md @@ -16,7 +16,11 @@ Sortable's adapter integration to the Prebid library. Posts plain-text JSON to t var adUnits = [ { code: 'test-pb-leaderboard', - sizes: [[728, 90]], + mediaTypes: { + banner: { + sizes: [[728, 90]], + } + }, bids: [{ bidder: 'sortable', params: { @@ -30,7 +34,11 @@ var adUnits = [ }] }, { code: 'test-pb-banner', - sizes: [[300, 250]], + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, bids: [{ bidder: 'sortable', params: { @@ -40,7 +48,11 @@ var adUnits = [ }] }, { code: 'test-pb-sidebar', - size: [[160, 600]], + mediaTypes: { + banner: { + sizes: [[160, 600]], + } + }, bids: [{ bidder: 'sortable', params: { @@ -51,6 +63,47 @@ var adUnits = [ } } }] + }, { + code: 'test-pb-native', + mediaTypes: { + native: { + title: { + required: true, + len: 800 + }, + image: { + required: true, + sizes: [790, 294], + }, + sponsoredBy: { + required: true + } + } + }, + bids: [{ + bidder: 'sortable', + params: { + tagId: 'test-pb-native', + siteId: 'prebid.example.com' + } + }] + }, { + code: 'test-pb-video', + mediaTypes: { + video: { + playerSize: [640,480], + context: 'instream' + } + }, + bids: [ + { + bidder: 'sortable', + params: { + tagId: 'test-pb-video', + siteId: 'prebid.example.com' + } + } + ] } ] ``` diff --git a/modules/sovrnAnalyticsAdapter.js b/modules/sovrnAnalyticsAdapter.js index bfbad937206..0d2576edb05 100644 --- a/modules/sovrnAnalyticsAdapter.js +++ b/modules/sovrnAnalyticsAdapter.js @@ -1,11 +1,11 @@ -import adapter from '../src/AnalyticsAdapter' -import adaptermanager from '../src/adapterManager' +import adapter from '../src/AnalyticsAdapter.js' +import adaptermanager from '../src/adapterManager.js' import CONSTANTS from '../src/constants.json' -import {ajaxBuilder} from '../src/ajax' -import * as utils from '../src/utils' -import {config} from '../src/config' -import find from 'core-js/library/fn/array/find' -import includes from 'core-js/library/fn/array/includes' +import {ajaxBuilder} from '../src/ajax.js' +import * as utils from '../src/utils.js' +import {config} from '../src/config.js' +import find from 'core-js-pure/features/array/find.js' +import includes from 'core-js-pure/features/array/includes.js' const ajax = ajaxBuilder(0) diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index 5cd76981e8d..f3260668b74 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -1,7 +1,6 @@ -import * as utils from '../src/utils' -import {parse} from '../src/url' -import { registerBidder } from '../src/adapters/bidderFactory' -import { BANNER } from '../src/mediaTypes' +import * as utils from '../src/utils.js' +import { registerBidder } from '../src/adapters/bidderFactory.js' +import { BANNER } from '../src/mediaTypes.js' export const spec = { code: 'sovrn', @@ -26,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; } @@ -48,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, @@ -62,7 +57,7 @@ export const spec = { const page = bidderRequest.refererInfo.referer // clever trick to get the domain - const domain = parse(page).hostname + const domain = utils.parseUrl(page).hostname const sovrnBidReq = { id: utils.getUniqueIdentifierStr(), @@ -89,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 { @@ -107,8 +109,7 @@ export const spec = { options: {contentType: 'text/plain'} } } catch (e) { - console.log('error in build:') - console.log(e) + utils.logError('Could not build bidrequest, error deatils:', e); } }, @@ -143,8 +144,7 @@ export const spec = { } return sovrnBidResponses } catch (e) { - console.log('error in interpret:') - console.log(e) + utils.logError('Could not intrepret bidresponse, error deatils:', e); } }, @@ -179,7 +179,6 @@ export const spec = { .forEach(url => tracks.push({ type: 'image', url })) } } - return tracks } catch (e) { return [] diff --git a/modules/sovrnBidAdapter.md b/modules/sovrnBidAdapter.md index 3b189016a9f..2b5d21d5515 100644 --- a/modules/sovrnBidAdapter.md +++ b/modules/sovrnBidAdapter.md @@ -3,7 +3,7 @@ ``` Module Name: Sovrn Bid Adapter Module Type: Bidder Adapter -Maintainer: trand@sovrn.com +Maintainer: jrosendahl@sovrn.com ``` # Description @@ -44,4 +44,4 @@ var adUnits = [ }] } ] -``` \ No newline at end of file +``` diff --git a/modules/spotxBidAdapter.js b/modules/spotxBidAdapter.js index 8e62c276e5e..1733a176eba 100644 --- a/modules/spotxBidAdapter.js +++ b/modules/spotxBidAdapter.js @@ -1,7 +1,7 @@ -import * as utils from '../src/utils'; -import { Renderer } from '../src/Renderer'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { VIDEO } from '../src/mediaTypes'; +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 = 'spotx'; const URL = 'https://search.spotxchange.com/openrtb/2.3/dados/'; @@ -10,6 +10,7 @@ export const GOOGLE_CONSENT = { consented_providers: ['3', '7', '11', '12', '15' export const spec = { code: BIDDER_CODE, + gvlid: 165, aliases: ['spotx'], supportedMediaTypes: [VIDEO], @@ -159,6 +160,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; } diff --git a/modules/staqAnalyticsAdapter.js b/modules/staqAnalyticsAdapter.js index eeeef700a7e..4e3914bccdd 100644 --- a/modules/staqAnalyticsAdapter.js +++ b/modules/staqAnalyticsAdapter.js @@ -1,10 +1,12 @@ -import adapter from '../src/AnalyticsAdapter'; +import adapter from '../src/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; -import adapterManager from '../src/adapterManager'; -import { getRefererInfo } from '../src/refererDetection'; -import { parse } from '../src/url'; -import * as utils from '../src/utils'; -import { ajax } from '../src/ajax'; +import adapterManager from '../src/adapterManager.js'; +import { getRefererInfo } from '../src/refererDetection.js'; +import * as utils from '../src/utils.js'; +import { ajax } from '../src/ajax.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const storageObj = getStorageManager(); const ANALYTICS_VERSION = '1.0.0'; const DEFAULT_QUEUE_TIMEOUT = 4000; @@ -212,10 +214,10 @@ const ORGANIC = '(organic)'; export let storage = { getItem: (name) => { - return localStorage.getItem(name); + return storageObj.getDataFromLocalStorage(name); }, setItem: (name, value) => { - localStorage.setItem(name, value); + storageObj.setDataInLocalStorage(name, value); } }; @@ -246,7 +248,7 @@ export function getUmtSource(pageUrl, referrer) { if (se) { return asUtm(se, ORGANIC, ORGANIC); } - let parsedUrl = parse(pageUrl); + let parsedUrl = utils.parseUrl(pageUrl); let [refHost, refPath] = getReferrer(referrer); if (refHost && refHost !== parsedUrl.hostname) { return asUtm(refHost, REFERRAL, REFERRAL, '', refPath); @@ -273,12 +275,12 @@ export function getUmtSource(pageUrl, referrer) { } function getReferrer(referrer) { - let ref = parse(referrer); + let ref = utils.parseUrl(referrer); return [ref.hostname, ref.pathname]; } function getUTM(pageUrl) { - let urlParameters = parse(pageUrl).search; + let urlParameters = utils.parseUrl(pageUrl).search; if (!urlParameters['utm_campaign'] || !urlParameters['utm_source']) { return; } diff --git a/modules/stvBidAdapter.js b/modules/stvBidAdapter.js index b8fb58c0ab3..2200e01b089 100644 --- a/modules/stvBidAdapter.js +++ b/modules/stvBidAdapter.js @@ -1,8 +1,8 @@ -import * as utils from '../src/utils'; -import {config} from '../src/config'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; +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 = 'stv'; const VADS_ENDPOINT_URL = 'https://ads.smartstream.tv/r/'; diff --git a/modules/sublimeBidAdapter.js b/modules/sublimeBidAdapter.js index fce3df7675b..1f8cb59f442 100644 --- a/modules/sublimeBidAdapter.js +++ b/modules/sublimeBidAdapter.js @@ -1,135 +1,217 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import { config } from '../src/config'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import * as utils from '../src/utils.js'; const BIDDER_CODE = 'sublime'; +const BIDDER_GVLID = 114; const DEFAULT_BID_HOST = 'pbjs.sskzlabs.com'; const DEFAULT_CURRENCY = 'EUR'; const DEFAULT_PROTOCOL = 'https'; const DEFAULT_TTL = 600; -const SUBLIME_VERSION = '0.4.0'; +const SUBLIME_ANTENNA = 'antenna.ayads.co'; +const SUBLIME_VERSION = '0.5.2'; + +/** + * Debug log message + * @param {String} msg + * @param {Object=} obj + */ +export function log(msg, obj) { + utils.logInfo('SublimeBidAdapter - ' + msg, obj); +} + +// Default state +export const state = { + zoneId: '', + transactionId: '' +}; -export const spec = { - code: BIDDER_CODE, - aliases: [], +/** + * Set a new state + * @param {Object} value + */ +export function setState(value) { + Object.assign(state, value); + log('State has been updated :', state); +} + +/** + * Send pixel to our debug endpoint + * @param {string} eventName - Event name that will be send in the e= query string + */ +export function sendEvent(eventName) { + const ts = Date.now(); + const eventObject = { + t: ts, + tse: ts, + z: state.zoneId, + e: eventName, + src: 'pa', + puid: state.transactionId, + trId: state.transactionId, + ver: SUBLIME_VERSION, + }; + + log('Sending pixel for event: ' + eventName, eventObject); + + const queryString = utils.formatQS(eventObject); + utils.triggerPixel('https://' + SUBLIME_ANTENNA + '/?' + queryString); +} + +/** + * 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. + */ +function isBidRequestValid(bid) { + return !!Number(bid.params.zoneId); +} + +/** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests - An array of bids + * @param {Object} bidderRequest - Info describing the request to the server. + * @return {ServerRequest|ServerRequest[]} - Info describing the request to the server. + */ +function buildRequests(validBidRequests, bidderRequest) { + const commonPayload = { + pbav: SUBLIME_VERSION, + // Current Prebid params + prebidVersion: '$prebid.version$', + currencyCode: config.getConfig('currency.adServerCurrency') || DEFAULT_CURRENCY, + timeout: (typeof bidderRequest === 'object' && !!bidderRequest) ? bidderRequest.timeout : config.getConfig('bidderTimeout'), + }; + + // RefererInfo + if (bidderRequest && bidderRequest.refererInfo) { + commonPayload.referer = bidderRequest.refererInfo.referer; + commonPayload.numIframes = bidderRequest.refererInfo.numIframes; + } + // GDPR handling + if (bidderRequest && bidderRequest.gdprConsent) { + commonPayload.gdprConsent = bidderRequest.gdprConsent.consentString; + commonPayload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side + } + + return validBidRequests.map(bid => { + const bidHost = bid.params.bidHost || DEFAULT_BID_HOST; + const protocol = bid.params.protocol || DEFAULT_PROTOCOL; + + setState({ + transactionId: bid.transactionId, + zoneId: bid.params.zoneId, + debug: bid.params.debug || false, + }); - /** - * Determines whether or not the given bid request is valid. - * - * @param {BidRequest} bid The bid params to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ - isBidRequestValid: (bid) => { - return !!bid.params.zoneId; - }, - - /** - * Make a server request from the list of BidRequests. - * - * @param {BidRequest[]} validBidRequests An array of bids - * @param {Object} bidderRequest - Info describing the request to the server. - * @return ServerRequest Info describing the request to the server. - */ - buildRequests: (validBidRequests, bidderRequest) => { - let commonPayload = { - sublimeVersion: SUBLIME_VERSION, - // Current Prebid params - prebidVersion: '$prebid.version$', - currencyCode: config.getConfig('currency.adServerCurrency') || DEFAULT_CURRENCY, - timeout: config.getConfig('bidderTimeout'), + const bidPayload = { + adUnitCode: bid.adUnitCode, + auctionId: bid.auctionId, + bidder: bid.bidder, + bidderRequestId: bid.bidderRequestId, + bidRequestsCount: bid.bidRequestsCount, + requestId: bid.bidId, + sizes: bid.sizes.map(size => ({ + w: size[0], + h: size[1], + })), + transactionId: bid.transactionId, + zoneId: bid.params.zoneId, }; - // RefererInfo - if (bidderRequest && bidderRequest.refererInfo) { - commonPayload.referer = bidderRequest.refererInfo.referer; - commonPayload.numIframes = bidderRequest.refererInfo.numIframes; + const payload = Object.assign({}, commonPayload, bidPayload); + + return { + method: 'POST', + url: protocol + '://' + bidHost + '/bid', + data: payload, + options: { + contentType: 'application/json', + withCredentials: true + }, } - // GDPR handling - if (bidderRequest && bidderRequest.gdprConsent) { - commonPayload.gdprConsent = bidderRequest.gdprConsent.consentString; - commonPayload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side + }); +} + +/** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @param {*} bidRequest An object with bid request informations + * @return {Bid[]} An array of bids which were nested inside the server. + */ +function interpretResponse(serverResponse, bidRequest) { + const bidResponses = []; + const response = serverResponse.body; + + if (response) { + if (response.timeout || !response.ad || //gmi.test(response.ad)) { + return bidResponses; } - return validBidRequests.map(bid => { - let bidPayload = { - adUnitCode: bid.adUnitCode, - auctionId: bid.auctionId, - bidder: bid.bidder, - bidderRequestId: bid.bidderRequestId, - bidRequestsCount: bid.bidRequestsCount, - requestId: bid.bidId, - sizes: bid.sizes.map(size => ({ - w: size[0], - h: size[1], - })), - transactionId: bid.transactionId, - zoneId: bid.params.zoneId, - }; + // Setting our returned sizes object to default values + let returnedSizes = { + width: 1800, + height: 1000 + }; - let protocol = bid.params.protocol || DEFAULT_PROTOCOL; - let bidHost = bid.params.bidHost || DEFAULT_BID_HOST; - let payload = Object.assign({}, commonPayload, bidPayload); - - return { - method: 'POST', - url: protocol + '://' + bidHost + '/bid', - data: payload, - options: { - contentType: 'application/json', - withCredentials: true - }, - }; - }); - }, - - /** - * Unpack the response from the server into a list of bids. - * - * @param {*} serverResponse A successful response from the server. - * @param {*} bidRequest An object with bid request informations - * @return {Bid[]} An array of bids which were nested inside the server. - */ - interpretResponse: (serverResponse, bidRequest) => { - const bidResponses = []; - const response = serverResponse.body; - - if (response) { - if (response.timeout || !response.ad || response.ad.match(//gmi)) { - return bidResponses; - } - - // Setting our returned sizes object to default values - let returnedSizes = { - width: 1800, - height: 1000 + // Verifying Banner sizes + if (bidRequest && bidRequest.data && bidRequest.data.w === 1 && bidRequest.data.h === 1) { + // If banner sizes are 1x1 we set our default size object to 1x1 + returnedSizes = { + width: 1, + height: 1 }; + } - // Verifying Banner sizes - if (bidRequest && bidRequest.data && bidRequest.data.w === 1 && bidRequest.data.h === 1) { - // If banner sizes are 1x1 we set our default size object to 1x1 - returnedSizes = { - width: 1, - height: 1 - }; - } - - const bidResponse = { - requestId: response.requestId || '', - cpm: response.cpm || 0, - width: response.width || returnedSizes.width, - height: response.height || returnedSizes.height, - creativeId: response.creativeId || 1, - dealId: response.dealId || 1, - currency: response.currency || DEFAULT_CURRENCY, - netRevenue: response.netRevenue || true, - ttl: response.ttl || DEFAULT_TTL, - ad: response.ad, - }; + const bidResponse = { + requestId: response.requestId || '', + cpm: response.cpm || 0, + width: response.width || returnedSizes.width, + height: response.height || returnedSizes.height, + creativeId: response.creativeId || 1, + dealId: response.dealId || 1, + currency: response.currency || DEFAULT_CURRENCY, + netRevenue: response.netRevenue || true, + ttl: response.ttl || DEFAULT_TTL, + ad: response.ad, + pbav: SUBLIME_VERSION + }; - bidResponses.push(bidResponse); - } + bidResponses.push(bidResponse); + } + + return bidResponses; +} + +/** + * Send pixel when bidWon event is triggered + * @param {Object} timeoutData + */ +function onBidWon(bid) { + log('Bid won', bid); + sendEvent('bidwon'); +} + +/** + * Send debug when we timeout + * @param {Object} timeoutData + */ +function onTimeout(timeoutData) { + log('Timeout from adapter', timeoutData); + sendEvent('bidtimeout'); +} - return bidResponses; - }, +export const spec = { + code: BIDDER_CODE, + gvlid: BIDDER_GVLID, + aliases: [], + isBidRequestValid: isBidRequestValid, + buildRequests: buildRequests, + interpretResponse: interpretResponse, + onBidWon: onBidWon, + onTimeout: onTimeout, }; registerBidder(spec); diff --git a/modules/synacormediaBidAdapter.js b/modules/synacormediaBidAdapter.js index 3064ac2063b..8f069f551ee 100644 --- a/modules/synacormediaBidAdapter.js +++ b/modules/synacormediaBidAdapter.js @@ -1,9 +1,10 @@ 'use strict'; -import { getAdUnitSizes, logWarn } from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, VIDEO } from '../src/mediaTypes'; -import includes from 'core-js/library/fn/array/includes'; +import { getAdUnitSizes, logWarn } 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 USER_SYNC_HOST = 'https://ad-cdn.technoratimedia.com'; @@ -44,6 +45,12 @@ export const spec = { }, imp: [] }; + + const schain = validBidReqs[0].schain; + if (schain) { + openRtbBidRequest.source = { ext: { schain } }; + } + let seatId = null; validBidReqs.forEach((bid, i) => { @@ -58,44 +65,24 @@ export const spec = { if (isNaN(bidFloor)) { logWarn(`Synacormedia: there is an invalid bid floor: ${bid.params.bidfloor}`); } - let pos = parseInt(bid.params.pos); + let pos = parseInt(bid.params.pos, 10); if (isNaN(pos)) { logWarn(`Synacormedia: there is an invalid POS: ${bid.params.pos}`); 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)); + } }); if (openRtbBidRequest.imp.length && seatId) { @@ -111,6 +98,70 @@ 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))) @@ -150,7 +201,9 @@ export const spec = { }; if (isVideo) { const [, uuid] = nurl.match(/ID=([^&]*)&?/); - bidObj.videoCacheKey = encodeURIComponent(uuid); + if (!config.getConfig('cache.url')) { + bidObj.videoCacheKey = encodeURIComponent(uuid); + } bidObj.vastUrl = nurl; } bids.push(bidObj); diff --git a/modules/synacormediaBidAdapter.md b/modules/synacormediaBidAdapter.md index 3a00aa45fed..fd71f07b3a3 100644 --- a/modules/synacormediaBidAdapter.md +++ b/modules/synacormediaBidAdapter.md @@ -24,9 +24,11 @@ https://track.technoratimedia.com/openrtb/tags?ID=%%PATTERN:hb_cache_id_synacorm ``` var adUnits = [{ code: 'test-div', - sizes: [ - [300, 250] - ], + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, bids: [{ bidder: "synacormedia", params: { @@ -40,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/taphypeBidAdapter.js b/modules/taphypeBidAdapter.js index 63224596e3d..65c5a728127 100644 --- a/modules/taphypeBidAdapter.js +++ b/modules/taphypeBidAdapter.js @@ -1,4 +1,4 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; export const spec = { code: 'taphype', diff --git a/modules/teadsBidAdapter.js b/modules/teadsBidAdapter.js index c35c0df2d05..dbeed4aceae 100644 --- a/modules/teadsBidAdapter.js +++ b/modules/teadsBidAdapter.js @@ -1,5 +1,5 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; -const utils = require('../src/utils'); +import {registerBidder} from '../src/adapters/bidderFactory.js'; +const utils = require('../src/utils.js'); const BIDDER_CODE = 'teads'; const ENDPOINT_URL = 'https://a.teads.tv/hb/bid-request'; const gdprStatus = { @@ -41,6 +41,8 @@ export const spec = { const bids = validBidRequests.map(buildRequestObject); const payload = { referrer: getReferrerInfo(bidderRequest), + pageReferrer: document.referrer, + networkBandwidth: getConnectionDownLink(window.navigator), data: bids, deviceWidth: screen.width, hb_version: '$prebid.version$' @@ -54,10 +56,13 @@ export const spec = { if (bidderRequest && gdpr) { let isCmp = (typeof gdpr.gdprApplies === 'boolean') let isConsentString = (typeof gdpr.consentString === 'string') - let status = isCmp ? findGdprStatus(gdpr.gdprApplies, gdpr.vendorData) : gdprStatus.CMP_NOT_FOUND_OR_ERROR + let status = isCmp + ? findGdprStatus(gdpr.gdprApplies, gdpr.vendorData, gdpr.apiVersion) + : gdprStatus.CMP_NOT_FOUND_OR_ERROR payload.gdpr_iab = { consent: isConsentString ? gdpr.consentString : '', - status: status + status: status, + apiVersion: gdpr.apiVersion }; } @@ -96,38 +101,14 @@ export const spec = { creativeId: bid.creativeId, placementId: bid.placementId }; + if (bid.dealId) { + bidResponse.dealId = bid.dealId + } bidResponses.push(bidResponse); }); } return bidResponses; }, - - getUserSyncs: function(syncOptions, responses, gdprConsent) { - let queryParams = { - hb_provider: 'prebid', - hb_version: '$prebid.version$' - }; - - if (gdprConsent) { - let gdprIab = { - status: findGdprStatus(gdprConsent.gdprApplies, gdprConsent.vendorData), - consent: gdprConsent.consentString - }; - - queryParams.gdprIab = JSON.stringify(gdprIab) - } - - if (utils.deepAccess(responses[0], 'body.responses.0.placementId')) { - queryParams.placementId = responses[0].body.responses[0].placementId - }; - - if (syncOptions.iframeEnabled) { - return [{ - type: 'iframe', - url: 'https://sync.teads.tv/iframe?' + utils.parseQueryStringParameters(queryParams) - }]; - } - } }; function getReferrerInfo(bidderRequest) { @@ -138,15 +119,26 @@ function getReferrerInfo(bidderRequest) { return ref; } -function findGdprStatus(gdprApplies, gdprData) { - let status = gdprStatus.GDPR_APPLIES_PUBLISHER; +function getConnectionDownLink(nav) { + return nav && nav.connection && nav.connection.downlink >= 0 ? nav.connection.downlink.toString() : ''; +} +function findGdprStatus(gdprApplies, gdprData, apiVersion) { + let status = gdprStatus.GDPR_APPLIES_PUBLISHER if (gdprApplies) { - if (gdprData.hasGlobalScope || gdprData.hasGlobalConsent) status = gdprStatus.GDPR_APPLIES_GLOBAL + if (isGlobalConsent(gdprData, apiVersion)) status = gdprStatus.GDPR_APPLIES_GLOBAL } else status = gdprStatus.GDPR_DOESNT_APPLY return status; } +function isGlobalConsent(gdprData, apiVersion) { + return gdprData && apiVersion === 1 + ? (gdprData.hasGlobalScope || gdprData.hasGlobalConsent) + : gdprData && apiVersion === 2 + ? !gdprData.isServiceSpecific + : false +} + function buildRequestObject(bid) { const reqObj = {}; let placementId = utils.getValue(bid.params, 'placementId'); diff --git a/modules/telariaBidAdapter.js b/modules/telariaBidAdapter.js index 842abbf1015..74c97f34b74 100644 --- a/modules/telariaBidAdapter.js +++ b/modules/telariaBidAdapter.js @@ -1,8 +1,8 @@ -import * as utils from '../src/utils'; -import {createBid as createBidFactory} from '../src/bidfactory'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {VIDEO} from '../src/mediaTypes'; -import {STATUS} from '../src/constants'; +import * as utils from '../src/utils.js'; +import {createBid as createBidFactory} from '../src/bidfactory.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {VIDEO} from '../src/mediaTypes.js'; +import {STATUS} from '../src/constants.json'; const BIDDER_CODE = 'telaria'; const DOMAIN = 'tremorhub.com'; @@ -119,8 +119,8 @@ export const spec = { } }; -function getSrcPageUrl(params) { - return (params && params['srcPageUrl']) || encodeURIComponent(document.location.href); +function getDefaultSrcPageUrl() { + return encodeURIComponent(document.location.href); } function getEncodedValIfNotEmpty(val) { @@ -175,7 +175,10 @@ export const getTimeoutUrl = function(timeoutData) { if (!utils.isEmpty(params)) { let url = `https://${EVENTS_ENDPOINT}`; - url += `?srcPageUrl=${getSrcPageUrl(params)}`; + params = Object.assign({ + srcPageUrl: getDefaultSrcPageUrl() + }, params); + url += `${getUrlParams(params)}`; url += '&hb=1&evt=TO'; @@ -221,9 +224,12 @@ function generateUrl(bid, bidderRequest) { url += (`&playerHeight=${height}`); } - url += `${getUrlParams(bid.params, bid.schain)}`; + const params = Object.assign({ + srcPageUrl: getDefaultSrcPageUrl() + }, bid.params); + delete params.adCode; - url += `&srcPageUrl=${getSrcPageUrl(bid.params)}`; + url += `${getUrlParams(params, bid.schain)}`; url += (`&transactionId=${bid.transactionId}`); diff --git a/modules/terceptAnalyticsAdapter.js b/modules/terceptAnalyticsAdapter.js new file mode 100644 index 00000000000..54da2bd06d2 --- /dev/null +++ b/modules/terceptAnalyticsAdapter.js @@ -0,0 +1,144 @@ +import { ajax } from '../src/ajax.js'; +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'; + +const emptyUrl = ''; +const analyticsType = 'endpoint'; +const terceptAnalyticsVersion = 'v1.0.0'; +const defaultHostName = 'us-central1-quikr-ebay.cloudfunctions.net'; +const defaultPathName = '/prebid-analytics'; + +let initOptions; +let auctionTimestamp; +let events = { + bids: [] +}; + +var terceptAnalyticsAdapter = 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'); + } + } + + if (eventType === CONSTANTS.EVENTS.AUCTION_END) { + send(events, 'auctionEnd'); + } + } +}); + +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 + }); + }); + } + return arr; +} + +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 { + 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 send(data, status) { + let location = utils.getWindowLocation(); + if (typeof data !== 'undefined' && typeof data.auctionInit !== 'undefined') { + Object.assign(data.auctionInit, { host: location.host, path: location.pathname, search: location.search }); + } + data.initOptions = initOptions; + + let terceptAnalyticsRequestUrl = utils.buildUrl({ + protocol: 'https', + hostname: (initOptions && initOptions.hostName) || defaultHostName, + pathname: (initOptions && initOptions.pathName) || defaultPathName, + search: { + auctionTimestamp: auctionTimestamp, + terceptAnalyticsVersion: terceptAnalyticsVersion, + prebidVersion: $$PREBID_GLOBAL$$.version + } + }); + + ajax(terceptAnalyticsRequestUrl, undefined, JSON.stringify(data), { method: 'POST', contentType: 'text/plain' }); +} + +terceptAnalyticsAdapter.originEnableAnalytics = terceptAnalyticsAdapter.enableAnalytics; +terceptAnalyticsAdapter.enableAnalytics = function (config) { + initOptions = config.options; + terceptAnalyticsAdapter.originEnableAnalytics(config); +}; + +adapterManager.registerAnalyticsAdapter({ + adapter: terceptAnalyticsAdapter, + code: 'tercept' +}); + +export default terceptAnalyticsAdapter; diff --git a/modules/terceptAnalyticsAdapter.md b/modules/terceptAnalyticsAdapter.md new file mode 100644 index 00000000000..39578d06730 --- /dev/null +++ b/modules/terceptAnalyticsAdapter.md @@ -0,0 +1,22 @@ +# Overview +Module Name: Tercept Analytics Adapter +Module Type: Analytics Adapter +Maintainer: gourav.chindlur@tercept.com + +# Description + +Analytics adapter for prebid provided by Tercept. Contact gourav.chindlur@tercept.com for information. + +# Test Parameters + +``` +{ + provider: 'Tercept', + options : { + pubId : 50357 //id provided by Tercept + pubKey: 'xxx' //key provided by Tercept + hostName: 'us-central1-quikr-ebay.cloudfunctions.net' //Tercept endpoint host + pathName: '/prebid-analytics' //Tercept endpoint path + } +} +``` diff --git a/modules/theAdxBidAdapter.js b/modules/theAdxBidAdapter.js index 61dfec86662..91e36077e88 100644 --- a/modules/theAdxBidAdapter.js +++ b/modules/theAdxBidAdapter.js @@ -1,15 +1,12 @@ -import * as utils from '../src/utils'; +import * as utils from '../src/utils.js'; import { BANNER, NATIVE, VIDEO -} from '../src/mediaTypes'; +} from '../src/mediaTypes.js'; import { registerBidder -} from '../src/adapters/bidderFactory'; -import { - parse as parseUrl -} from '../src/url'; +} from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'theadx'; const ENDPOINT_URL = 'https://ssp.theadx.com/request'; @@ -317,7 +314,7 @@ export const spec = { } let buildSiteComponent = (bidRequest, bidderRequest) => { - let loc = parseUrl(bidderRequest.refererInfo.referer, { + let loc = utils.parseUrl(bidderRequest.refererInfo.referer, { decodeSearchAsString: true }); diff --git a/modules/timBidAdapter.js b/modules/timBidAdapter.js index b615140ce7c..68c711f9935 100644 --- a/modules/timBidAdapter.js +++ b/modules/timBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import * as bidfactory from '../src/bidfactory'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import * as bidfactory from '../src/bidfactory.js'; var CONSTANTS = require('../src/constants.json'); const BIDDER_CODE = 'tim'; diff --git a/modules/topRTBBidAdapter.js b/modules/topRTBBidAdapter.js index 783d4008b33..c93bd8ccaac 100644 --- a/modules/topRTBBidAdapter.js +++ b/modules/topRTBBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER, VIDEO} from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; const BIDDER_CODE = 'topRTB'; const ENDPOINT_URL = 'https://ssp.toprtb.com/ssp/rest/ReqAd?ref=www.google.com&hbid=0&adUnitId='; diff --git a/modules/tpmnBidAdapter.js b/modules/tpmnBidAdapter.js index 081638c0adb..ec9d30c0e29 100644 --- a/modules/tpmnBidAdapter.js +++ b/modules/tpmnBidAdapter.js @@ -1,8 +1,7 @@ /* eslint-disable no-tabs */ -import { registerBidder } from '../src/adapters/bidderFactory'; -import * as utils from '../src/utils'; -import { BANNER } from '../src/mediaTypes'; -import {parse as parseUrl} from '../src/url'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; +import { BANNER } from '../src/mediaTypes.js'; export const ADAPTER_VERSION = '1'; const SUPPORTED_AD_TYPES = [BANNER]; @@ -73,7 +72,7 @@ registerBidder(spec); * Creates site description object */ function createSite(refInfo) { - let url = parseUrl(refInfo.referer); + let url = utils.parseUrl(refInfo.referer); let site = { 'domain': url.hostname, 'page': url.protocol + '://' + url.hostname + url.pathname diff --git a/modules/trendqubeBidAdapter.js b/modules/trendqubeBidAdapter.js new file mode 100644 index 00000000000..d0364b4acec --- /dev/null +++ b/modules/trendqubeBidAdapter.js @@ -0,0 +1,102 @@ +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 = 'trendqube'; +const AD_URL = 'https://ads.trendqube.com/?c=o&m=multi'; + +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; + }, +}; + +registerBidder(spec); diff --git a/modules/trendqubeBidAdapter.md b/modules/trendqubeBidAdapter.md new file mode 100644 index 00000000000..8b72c225575 --- /dev/null +++ b/modules/trendqubeBidAdapter.md @@ -0,0 +1,53 @@ +# Overview + +``` +Module Name: trendqube Bidder Adapter +Module Type: trendqube Bidder Adapter +``` + +# Description + +Module that connects to trendqube demand sources + +# Test Parameters +``` + var adUnits = [ + // Will return static test banner + { + code: 'placementId_0', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: 'trendqube', + 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: 'trendqube', + params: { + placementId: 0, + traffic: 'video' + } + } + ] + } + ]; +``` diff --git a/modules/tribeosBidAdapter.js b/modules/tribeosBidAdapter.js new file mode 100644 index 00000000000..80361aa3fdb --- /dev/null +++ b/modules/tribeosBidAdapter.js @@ -0,0 +1,165 @@ +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import * as bidfactory from '../src/bidfactory.js'; +import {BANNER} from '../src/mediaTypes.js'; +var CONSTANTS = require('../src/constants.json'); + +const BIDDER_CODE = 'tribeos'; +const ENDPOINT_URL = 'https://bidder.tribeos.tech/prebid/'; +const LOG_PREFIX = 'TRIBEOS: '; +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) { + if (utils.isEmpty(bid.params.placementId)) { + utils.logError(LOG_PREFIX, 'placementId is required, please contact tribeOS for placementId. Bid details: ', JSON.stringify(bid)); + return false; + } + return true; + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - + * an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests) { + var requests = []; + for (var i = 0; i < validBidRequests.length; i++) { + requests.push(this.buidRTBRequest(validBidRequests[i])); + } + return requests; + }, + buidRTBRequest: function(bidReq) { + // build bid request object + + var placementId = bidReq.params.placementId; + var bidFloor = bidReq.params.bidfloor; + var placementCode = bidReq.params.placementCode; + + var adWidth = bidReq.mediaTypes.banner.sizes[0][0]; + var adHeight = bidReq.mediaTypes.banner.sizes[0][1]; + + // build bid request with impressions + var bidRequest = { + id: utils.getUniqueIdentifierStr(), + imp: [{ + id: bidReq.bidId, + banner: { + w: adWidth, + h: adHeight + }, + tagid: placementCode, + bidfloor: bidFloor + }], + site: { + domain: window.location.host, + page: window.location.href, + publisher: { + id: placementId + } + }, + device: { + 'language': (navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage), + 'w': adWidth, + 'h': adHeight, + 'js': 1, + 'ua': navigator.userAgent + } + }; + + // apply gdpr + if (bidReq.gdprConsent) { + bidRequest.regs = {ext: {gdpr: bidReq.gdprConsent.gdprApplies ? 1 : 0}}; + bidRequest.user = {ext: {consent: bidReq.gdprConsent.consentString}}; + } + + bidRequest.bidId = bidReq.bidId; + var url = ENDPOINT_URL + placementId + '/requests'; + if (!utils.isEmpty(bidReq.params.endpointUrl)) { + url = bidReq.params.endpointUrl + placementId + '/requests'; + } + + return { + method: 'POST', + url: url, + data: JSON.stringify(bidRequest), + options: { withCredentials: true, contentType: 'application/json' }, + }; + }, + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} + * serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse, bidRequest) { + const responseBody = serverResponse.body; + + utils.logInfo(LOG_PREFIX, 'response body: ', JSON.stringify(serverResponse)); + + if ((!responseBody || !responseBody.id)) { + return []; + } + const bidResponses = []; + responseBody.seatbid[0].bid.forEach(function(bidderBid) { + var responsePrice; + var placementCode = ''; + if (bidRequest) { + var bidResponse = bidfactory.createBid(1); + placementCode = bidRequest.placementCode; + bidRequest.status = CONSTANTS.STATUS.GOOD; + responsePrice = parseFloat(bidderBid.price); + if (responsePrice === 0) { + var bid = bidfactory.createBid(2); + bid.bidderCode = BIDDER_CODE; + bidResponses.push(bid); + + utils.logInfo(LOG_PREFIX, 'response price is zero. Response data: ', JSON.stringify(bidRequest)); + + return bidResponses; + } + bidResponse.placementCode = placementCode; + bidResponse.size = bidRequest.sizes; + bidResponse.creativeId = bidderBid.crid; + bidResponse.bidderCode = BIDDER_CODE; + bidResponse.cpm = responsePrice; + bidResponse.ad = bidderBid.adm; + bidResponse.width = parseInt(bidderBid.w); + bidResponse.height = parseInt(bidderBid.h); + bidResponse.currency = responseBody.cur; + bidResponse.netRevenue = true; + bidResponse.requestId = bidderBid.impid; + bidResponse.ttl = 180; + + utils.logInfo(LOG_PREFIX, 'bid response data: ', JSON.stringify(bidResponse)); + utils.logInfo(LOG_PREFIX, 'bid request data: ', JSON.stringify(bidRequest)); + + bidResponses.push(bidResponse); + } + }); + return bidResponses; + }, + /** + * 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) { +// ajax(this.nurls[bid.requestId], null); +// } + +} +registerBidder(spec); diff --git a/modules/tribeosBidAdapter.md b/modules/tribeosBidAdapter.md new file mode 100644 index 00000000000..670810abec9 --- /dev/null +++ b/modules/tribeosBidAdapter.md @@ -0,0 +1,31 @@ +# Overview + +``` +Module Name: tribeOS Bidder Adapter +Module Type: Bidder Adapter +Maintainer: dev@tribeos.io +``` + +# Description + +tribeOS adapter + +# Test Parameters +``` + var adUnits = [{ + code: 'test-tribeos', + mediaTypes: { + banner: { + sizes: [ + [300, 250] + ], + } + }, + bids: [{ + bidder: "tribeos", + params: { + placementId: '12345' // REQUIRED + } + }] + }]; +``` diff --git a/modules/trionBidAdapter.js b/modules/trionBidAdapter.js index 6d564a66e2d..37d54e60cd2 100644 --- a/modules/trionBidAdapter.js +++ b/modules/trionBidAdapter.js @@ -1,5 +1,8 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const storage = getStorageManager(); const BID_REQUEST_BASE_URL = 'https://in-appadvertising.com/api/bidRequest'; const USER_SYNC_URL = 'https://in-appadvertising.com/api/userSync.html'; @@ -108,12 +111,11 @@ function getPublisherUrl() { function buildTrionUrlParams(bid, bidderRequest) { var pubId = utils.getBidIdParameter('pubId', bid.params); var sectionId = utils.getBidIdParameter('sectionId', bid.params); - var re = utils.getBidIdParameter('re', bid.params); var url = getPublisherUrl(); var bidSizes = getBidSizesFromBidRequest(bid); var sizes = utils.parseSizesInput(bidSizes).join(','); - var isAutomated = (navigator && navigator.webdriver) ? 1 : 0; - var isHidden = (document.hidden) ? 1 : 0; + var isAutomated = (navigator && navigator.webdriver) ? '1' : '0'; + var isHidden = (document.hidden) ? '1' : '0'; var visibilityState = encodeURIComponent(document.visibilityState); var intT = window.TR_INT_T && window.TR_INT_T != -1 ? window.TR_INT_T : null; @@ -129,7 +131,7 @@ function buildTrionUrlParams(bid, bidderRequest) { trionUrl = utils.tryAppendQueryString(trionUrl, 'bidId', bid.bidId); trionUrl = utils.tryAppendQueryString(trionUrl, 'pubId', pubId); trionUrl = utils.tryAppendQueryString(trionUrl, 'sectionId', sectionId); - trionUrl = utils.tryAppendQueryString(trionUrl, 're', re); + trionUrl = utils.tryAppendQueryString(trionUrl, 'vers', '$prebid.version$'); if (url) { trionUrl += 'url=' + url + '&'; } @@ -177,8 +179,8 @@ function handlePostMessage() { export function getStorageData(key) { var item = null; try { - if (window.localStorage) { - item = window.localStorage.getItem(key); + if (storage.hasLocalStorage()) { + item = storage.getDataFromLocalStorage(key); } } catch (e) { } @@ -187,8 +189,8 @@ export function getStorageData(key) { export function setStorageData(key, item) { try { - if (window.localStorage) { - window.localStorage.setItem(key, item); + if (storage.hasLocalStorage()) { + storage.setDataInLocalStorage(key, item); } } catch (e) { } diff --git a/modules/tripleliftBidAdapter.js b/modules/tripleliftBidAdapter.js index 7120929059d..af904aedc11 100644 --- a/modules/tripleliftBidAdapter.js +++ b/modules/tripleliftBidAdapter.js @@ -1,6 +1,7 @@ -import { BANNER } from '../src/mediaTypes'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import * as utils from '../src/utils'; +import { BANNER } from '../src/mediaTypes.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'triplelift'; const STR_ENDPOINT = 'https://tlx.3lift.com/header/auction?'; @@ -46,6 +47,10 @@ export const tripleliftAdapterSpec = { tlCall = utils.tryAppendQueryString(tlCall, 'us_privacy', bidderRequest.uspConsent); } + if (config.getConfig('coppa') === true) { + tlCall = utils.tryAppendQueryString(tlCall, 'coppa', true); + } + if (tlCall.lastIndexOf('&') === tlCall.length - 1) { tlCall = tlCall.substring(0, tlCall.length - 1); } @@ -106,7 +111,7 @@ function _buildPostBody(bidRequests) { return { id: index, tagid: bid.params.inventoryCode, - floor: bid.params.floor, + floor: _getFloor(bid), banner: { format: _sizes(bid.sizes) } @@ -115,7 +120,8 @@ function _buildPostBody(bidRequests) { let eids = [ ...getUnifiedIdEids(bidRequests), - ...getIdentityLinkEids(bidRequests) + ...getIdentityLinkEids(bidRequests), + ...getCriteoEids(bidRequests) ]; if (eids.length > 0) { @@ -132,6 +138,22 @@ function _buildPostBody(bidRequests) { return data; } +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 getUnifiedIdEids(bidRequests) { return getEids(bidRequests, 'tdid', 'adserver.org', 'TDID'); } @@ -140,6 +162,10 @@ function getIdentityLinkEids(bidRequests) { return getEids(bidRequests, 'idl_env', 'liveramp.com', 'idl'); } +function getCriteoEids(bidRequests) { + return getEids(bidRequests, 'criteoId', 'criteo.com', 'criteoId'); +} + function getEids(bidRequests, type, source, rtiPartner) { return bidRequests .map(getUserId(type)) // bids -> userIds of a certain type @@ -193,7 +219,8 @@ function _buildResponseObject(bidderRequest, bid) { creativeId: creativeId, dealId: dealId, currency: 'USD', - ttl: 33, + ttl: 300, + tl_source: bid.tl_source, }; }; return bidResponse; 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/trustxBidAdapter.js b/modules/trustxBidAdapter.js index 1e7b9ef5ef4..f412fa21a05 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -1,7 +1,7 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { Renderer } from '../src/Renderer'; -import { VIDEO, BANNER } from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; const BIDDER_CODE = 'trustx'; const ENDPOINT_URL = 'https://sofia.trustx.org/hb'; diff --git a/modules/turktelekomBidAdapter.js b/modules/turktelekomBidAdapter.js index cfb1c24052a..852e557290c 100644 --- a/modules/turktelekomBidAdapter.js +++ b/modules/turktelekomBidAdapter.js @@ -1,7 +1,7 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { Renderer } from '../src/Renderer'; -import { VIDEO, BANNER } from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; +import { VIDEO, BANNER } from '../src/mediaTypes.js'; const BIDDER_CODE = 'turktelekom'; const ENDPOINT_URL = 'https://ssp.programattik.com/hb'; diff --git a/modules/ucfunnelAnalyticsAdapter.js b/modules/ucfunnelAnalyticsAdapter.js index 525d1bdf615..7a471a1d3b4 100644 --- a/modules/ucfunnelAnalyticsAdapter.js +++ b/modules/ucfunnelAnalyticsAdapter.js @@ -1,9 +1,9 @@ -import {ajax} from '../src/ajax'; -import adapter from '../src/AnalyticsAdapter'; +import {ajax} from '../src/ajax.js'; +import adapter from '../src/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; -import adapterManager from '../src/adapterManager'; -import {getGlobal} from '../src/prebidGlobal'; -import {logError, logInfo, deepClone} from '../src/utils'; +import adapterManager from '../src/adapterManager.js'; +import {getGlobal} from '../src/prebidGlobal.js'; +import {logError, logInfo, deepClone} from '../src/utils.js'; const analyticsType = 'endpoint'; diff --git a/modules/ucfunnelBidAdapter.js b/modules/ucfunnelBidAdapter.js index e2c642862fd..f9982edef36 100644 --- a/modules/ucfunnelBidAdapter.js +++ b/modules/ucfunnelBidAdapter.js @@ -1,6 +1,9 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes'; - +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/underdogmediaBidAdapter.js b/modules/underdogmediaBidAdapter.js index 0cda14d3849..8368077a627 100644 --- a/modules/underdogmediaBidAdapter.js +++ b/modules/underdogmediaBidAdapter.js @@ -1,13 +1,19 @@ -import * as utils from '../src/utils'; -import { config } from '../src/config'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { config } from '../src/config.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'underdogmedia'; -const UDM_ADAPTER_VERSION = '3.0V'; +const UDM_ADAPTER_VERSION = '3.5V'; const UDM_VENDOR_ID = '159'; const prebidVersion = '$prebid.version$'; +let USER_SYNCED = false; utils.logMessage(`Initializing UDM Adapter. PBJS Version: ${prebidVersion} with adapter version: ${UDM_ADAPTER_VERSION} Updated 20191028`); +// helper function for testing user syncs +export function resetUserSync() { + USER_SYNCED = false; +} + export const spec = { code: BIDDER_CODE, bidParams: [], @@ -31,7 +37,8 @@ export const spec = { tid: 1, dt: 10, sid: siteId, - sizes: sizes.join(',') + sizes: sizes.join(','), + version: UDM_ADAPTER_VERSION } if (bidderRequest && bidderRequest.gdprConsent) { @@ -61,6 +68,23 @@ export const spec = { } }, + getUserSyncs: function (syncOptions, serverResponses) { + if (!USER_SYNCED && serverResponses.length > 0 && serverResponses[0].body && serverResponses[0].body.userSyncs && serverResponses[0].body.userSyncs.length > 0) { + USER_SYNCED = true; + const userSyncs = serverResponses[0].body.userSyncs; + const syncs = userSyncs.filter(sync => { + const {type} = sync; + if (syncOptions.iframeEnabled && type === 'iframe') { + return true + } + if (syncOptions.pixelEnabled && type === 'image') { + return true + } + }) + return syncs; + } + }, + interpretResponse: function (serverResponse, bidRequest) { const bidResponses = []; bidRequest.bidParams.forEach(bidParam => { @@ -95,7 +119,7 @@ export const spec = { creativeId: mid.mid, currency: 'USD', netRevenue: false, - ttl: config.getConfig('_bidderTimeout'), + ttl: mid.ttl || 60, }; if (bidResponse.cpm <= 0) { @@ -118,9 +142,14 @@ export const spec = { }; function makeNotification(bid, mid, bidParam) { - var url = mid.notification_url; + let url = mid.notification_url; + + const versionIndex = url.indexOf(';version=') + if (versionIndex + 1) { + url = url.substring(0, versionIndex) + } - url += UDM_ADAPTER_VERSION; + url += `;version=${UDM_ADAPTER_VERSION}`; url += ';cb=' + Math.random(); url += ';qqq=' + (1 / bid.cpm); url += ';hbt=' + config.getConfig('_bidderTimeout'); diff --git a/modules/undertoneBidAdapter.js b/modules/undertoneBidAdapter.js index 0daa6d83e26..6ead453b622 100644 --- a/modules/undertoneBidAdapter.js +++ b/modules/undertoneBidAdapter.js @@ -2,8 +2,8 @@ * Adapter to send bids to Undertone */ -import * as urlUtils from '../src/url'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import { parseUrl } from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'undertone'; const URL = 'https://hb.undertone.com/hb'; @@ -51,6 +51,26 @@ function getGdprQueryParams(gdprConsent) { return `gdpr=${gdpr}&gdprstr=${gdprstr}`; } +function getBannerCoords(id) { + let element = document.getElementById(id); + let left = -1; + let top = -1; + if (element) { + left = element.offsetLeft; + top = element.offsetTop; + + let parent = element.offsetParent; + if (parent) { + left += parent.offsetLeft; + top += parent.offsetTop; + } + + return [left, top]; + } else { + return null; + } +} + export const spec = { code: BIDDER_CODE, isBidRequestValid: function(bid) { @@ -60,15 +80,19 @@ export const spec = { } }, buildRequests: function(validBidRequests, bidderRequest) { + const vw = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); + const vh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); + const pageSizeArray = vw == 0 || vh == 0 ? null : [vw, vh]; const payload = { 'x-ut-hb-params': [], 'commons': { 'adapterVersion': '$prebid.version$', - 'uids': validBidRequests[0].userId + 'uids': validBidRequests[0].userId, + 'pageSize': pageSizeArray } }; const referer = bidderRequest.refererInfo.referer; - const hostname = urlUtils.parse(referer).hostname; + const hostname = parseUrl(referer).hostname; let domain = extractDomainFromHost(hostname); const pageUrl = getCanonicalUrl() || referer; @@ -87,6 +111,7 @@ export const spec = { validBidRequests.map(bidReq => { const bid = { bidRequestId: bidReq.bidId, + coordinates: getBannerCoords(bidReq.adUnitCode), hbadaptor: 'prebid', url: pageUrl, domain: domain, diff --git a/modules/unicornBidAdapter.js b/modules/unicornBidAdapter.js new file mode 100644 index 00000000000..33e60ad2789 --- /dev/null +++ b/modules/unicornBidAdapter.js @@ -0,0 +1,150 @@ +import * as utils from '../src/utils.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { getStorageManager } from '../src/storageManager.js'; + +const storage = getStorageManager(); +const BIDDER_CODE = 'unicorn'; +const UNICORN_ENDPOINT = 'https://ds.uncn.jp/pb/0/bid.json'; +const UNICORN_DEFAULT_CURRENCY = 'JPY'; +const UNICORN_PB_COOKIE_KEY = '__pb_unicorn_aud'; + +/** + * Placement ID and Account ID are required. + * @param {BidRequest} bidRequest + * @returns {boolean} + */ +const isBidRequestValid = bidRequest => { + return !!bidRequest.adUnitCode && !!bidRequest.params.accountId; +}; + +/** + * @param {Array} validBidRequests + * @param {any} bidderRequest + * @returns {ServerRequest} + */ +export const buildRequests = (validBidRequests, bidderRequest) => { + return { + method: 'POST', + url: UNICORN_ENDPOINT, + data: buildOpenRtbBidRequestPayload(validBidRequests, bidderRequest) + }; +}; + +/** + * Transform BidRequest to OpenRTB-formatted BidRequest Object + * @param {Array} validBidRequests + * @param {any} bidderRequest + * @returns {string} + */ +function buildOpenRtbBidRequestPayload(validBidRequests, bidderRequest) { + utils.logInfo( + '[UNICORN] buildOpenRtbBidRequestPayload.validBidRequests:', + validBidRequests + ); + utils.logInfo( + '[UNICORN] buildOpenRtbBidRequestPayload.bidderRequest:', + bidderRequest + ); + const imp = validBidRequests.map(br => { + const sizes = utils.parseSizesInput(br.sizes)[0]; + return { + id: br.bidId, + banner: { + w: sizes.split('x')[0], + h: sizes.split('x')[1] + }, + tagid: utils.deepAccess(br, 'params.placementId') || br.adUnitCode, + secure: 1, + bidfloor: parseFloat(utils.deepAccess(br, 'params.bidfloorCpm') || 0) + }; + }); + const request = { + id: bidderRequest.auctionId, + at: 1, + imp, + cur: UNICORN_DEFAULT_CURRENCY, + site: { + id: utils.deepAccess(validBidRequests[0], 'params.mediaId') || '', + publisher: { + id: utils.deepAccess(validBidRequests[0], 'params.publisherId') || 0 + }, + domain: window.location.hostname, + page: window.location.href, + ref: bidderRequest.refererInfo.referer + }, + device: { + language: navigator.language, + ua: navigator.userAgent + }, + user: { + id: getUid() + }, + bcat: utils.deepAccess(validBidRequests[0], 'params.bcat') || [], + source: { + ext: { + stype: 'prebid_uncn', + bidder: BIDDER_CODE + } + }, + ext: { + accountId: utils.deepAccess(validBidRequests[0], 'params.accountId') + } + }; + utils.logInfo('[UNICORN] OpenRTB Formatted Request:', request); + return JSON.stringify(request); +} + +const interpretResponse = (serverResponse, request) => { + utils.logInfo('[UNICORN] interpretResponse.serverResponse:', serverResponse); + utils.logInfo('[UNICORN] interpretResponse.request:', request); + const res = serverResponse.body; + var bids = [] + if (res) { + res.seatbid.forEach(sb => { + sb.bid.forEach(b => { + bids.push({ + requestId: b.impid, + cpm: b.price || 0, + width: b.w, + height: b.h, + ad: b.adm, + ttl: 1000, + creativeId: b.crid, + netRevenue: false, + currency: res.cur + }) + }) + }); + } + utils.logInfo('[UNICORN] interpretResponse bids:', bids); + return bids; +}; + +/** + * Get or Create Uid for First Party Cookie + */ +const getUid = () => { + const ck = storage.getCookie(UNICORN_PB_COOKIE_KEY); + if (ck) { + return JSON.parse(ck)['uid']; + } else { + const newCk = { + uid: utils.generateUUID() + }; + const expireIn = new Date(Date.now() + 24 * 60 * 60 * 10000).toUTCString(); + storage.setCookie(UNICORN_PB_COOKIE_KEY, JSON.stringify(newCk), expireIn); + return newCk.uid; + } +}; + +export const spec = { + code: BIDDER_CODE, + aliases: ['uncn'], + supportedMediaTypes: [BANNER], + isBidRequestValid, + buildRequests, + interpretResponse, +}; + +registerBidder(spec); diff --git a/modules/unicornBidAdapter.md b/modules/unicornBidAdapter.md new file mode 100644 index 00000000000..5b8c8268bcf --- /dev/null +++ b/modules/unicornBidAdapter.md @@ -0,0 +1,33 @@ +# Overview + +**Module Name**: UNICORN Bid Adapter +**Module Type**: Bidder Adapter +**Maintainer**: service+prebid.js@bulbit.jp + +# Description + +Module that connects to UNICORN. + +# Test Parameters + +```js + const adUnits = [{ + code: 'test-adunit1', // REQUIRED: adunit code + mediaTypes: { + banner: { + sizes: [[300, 250]] // a banner size + } + }, + bids: [{ + bidder: 'unicorn', + params: { + placementId: 'rectangle-ad-1', // OPTIONAL: If placementId is empty, adunit code will be used as placementId. + bidfloorCpm: 0.2, // OPTIONAL: Floor CPM (JPY) defaults to 0 + publisherId: 99999 // OPTIONAL: Account specific publisher id + mediaId: "uc" // OPTIONAL: Publisher specific media id + accountId: 12345, // REQUIRED: Account ID for charge request + bcat: ['IAB-1', 'IAB-2'] // OPTIONAL: blocked IAB categories + } + }] + }]; +``` diff --git a/modules/unifiedIdSystem.js b/modules/unifiedIdSystem.js index 12aa646a5d9..f916030d643 100644 --- a/modules/unifiedIdSystem.js +++ b/modules/unifiedIdSystem.js @@ -5,9 +5,9 @@ * @requires module:modules/userId */ -import * as utils from '../src/utils' -import {ajax} from '../src/ajax'; -import {submodule} from '../src/hook' +import * as utils from '../src/utils.js' +import {ajax} from '../src/ajax.js'; +import {submodule} from '../src/hook.js' const MODULE_NAME = 'unifiedId'; @@ -39,20 +39,27 @@ export const unifiedIdSubmodule = { return; } // use protocol relative urls for http or https - const url = configParams.url || `//match.adsrvr.org/track/rid?ttd_pid=${configParams.partner}&fmt=json`; + const url = configParams.url || `https://match.adsrvr.org/track/rid?ttd_pid=${configParams.partner}&fmt=json`; const resp = function (callback) { - ajax(url, response => { - let responseObj; - if (response) { - try { - responseObj = JSON.parse(response); - } catch (error) { - utils.logError(error); + 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(); } - callback(responseObj); - }, undefined, {method: 'GET', withCredentials: true}); + }; + ajax(url, callbacks, undefined, {method: 'GET', withCredentials: true}); }; return {callback: resp}; } diff --git a/modules/unrulyBidAdapter.js b/modules/unrulyBidAdapter.js index 580357a1978..15fe0fefe8b 100644 --- a/modules/unrulyBidAdapter.js +++ b/modules/unrulyBidAdapter.js @@ -1,7 +1,7 @@ -import * as utils from '../src/utils' -import { Renderer } from '../src/Renderer' -import { registerBidder } from '../src/adapters/bidderFactory' -import { VIDEO } from '../src/mediaTypes' +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' function configureUniversalTag (exchangeRenderer) { if (!exchangeRenderer.config) throw new Error('UnrulyBidAdapter: Missing renderer config.') diff --git a/modules/userId/eids.js b/modules/userId/eids.js new file mode 100644 index 00000000000..d3f32fbdd31 --- /dev/null +++ b/modules/userId/eids.js @@ -0,0 +1,160 @@ +import * as utils from '../../src/utils.js'; + +// Each user-id sub-module is expected to mention respective config here +const USER_IDS_CONFIG = { + + // key-name : {config} + + // intentIqId + 'intentIqId': { + source: 'intentiq.com', + atype: 1 + }, + + // pubCommonId + 'pubcid': { + source: 'pubcid.org', + atype: 1 + }, + + // unifiedId + 'tdid': { + source: 'adserver.org', + atype: 1, + getUidExt: function() { + return { + rtiPartner: 'TDID' + }; + } + }, + + // id5Id + 'id5id': { + source: 'id5-sync.com', + atype: 1 + }, + + // parrableId + 'parrableid': { + source: 'parrable.com', + atype: 1 + }, + + // identityLink + 'idl_env': { + source: 'liveramp.com', + atype: 1 + }, + + // liveIntentId + 'lipb': { + getValue: function(data) { + return data.lipbid; + }, + source: 'liveintent.com', + atype: 1, + getEidExt: function(data) { + if (Array.isArray(data.segments) && data.segments.length) { + return { + segments: data.segments + }; + } + } + }, + + // britepoolId + 'britepoolid': { + source: 'britepool.com', + atype: 1 + }, + + // lotamePanoramaId + lotamePanoramaId: { + source: 'crwdcntrl.net', + atype: 1, + }, + + // DigiTrust + 'digitrustid': { + getValue: function (data) { + var id = null; + if (data && data.data && data.data.id != null) { + id = data.data.id; + } + return id; + }, + source: 'digitru.st', + atype: 1 + }, + + // criteo + 'criteoId': { + source: 'criteo.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; + } + } +}; + +// this function will create an eid object for the given UserId sub-module +function createEidObject(userIdData, subModuleKey) { + const conf = USER_IDS_CONFIG[subModuleKey]; + if (conf && userIdData) { + let eid = {}; + eid.source = conf['source']; + const value = utils.isFn(conf['getValue']) ? conf['getValue'](userIdData) : userIdData; + if (utils.isStr(value)) { + const uid = { id: value, atype: conf['atype'] }; + // getUidExt + if (utils.isFn(conf['getUidExt'])) { + const uidExt = conf['getUidExt'](userIdData); + if (uidExt) { + uid.ext = uidExt; + } + } + eid.uids = [uid]; + // getEidExt + if (utils.isFn(conf['getEidExt'])) { + const eidExt = conf['getEidExt'](userIdData); + if (eidExt) { + eid.ext = eidExt; + } + } + return eid; + } + } + return null; +} + +// this function will generate eids array for all available IDs in bidRequest.userId +// this function will be called by userId module +// if any adapter does not want any particular userId to be passed then adapter can use Array.filter(e => e.source != 'tdid') +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); + } + } + } + return eids; +} diff --git a/modules/userId/eids.md b/modules/userId/eids.md new file mode 100644 index 00000000000..60f450e9328 --- /dev/null +++ b/modules/userId/eids.md @@ -0,0 +1,100 @@ +## Example of eids array generated by UserId Module. +``` +userIdAsEids = [ + { + source: 'pubcid.org', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, + + { + source: 'adserver.org', + uids: [{ + id: 'some-random-id-value', + atype: 1, + ext: { + rtiPartner: 'TDID' + } + }] + }, + + { + source: 'id5-sync.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, + + { + source: 'parrable.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, + + { + source: 'liveramp.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, + + { + source: 'liveintent.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }], + ext: { + segments: ['s1', 's2'] + } + }, + + { + source: 'britepool.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, + + { + source: 'digitru.st', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, + + { + source: 'criteo.com', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, + + { + source: 'netid.de', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, + { + source: 'sharedid.org', + uids: [{ + id: 'some-random-id-value', + atype: 1, + ext: { + third: 'some-random-id-value' + } + }] + } +] +``` diff --git a/modules/userId/index.js b/modules/userId/index.js index cbe5e4de55f..1c5768edae1 100644 --- a/modules/userId/index.js +++ b/modules/userId/index.js @@ -37,6 +37,7 @@ * @summary decode a stored value for passing to bid requests * @name Submodule#decode * @param {Object|string} value + * @param {SubmoduleParams|undefined} configParams * @return {(Object|undefined)} */ @@ -63,6 +64,14 @@ * @property {(number|undefined)} refreshInSeconds - if not empty, this value defines the maximum time span in seconds before refreshing user ID stored in browser */ +/** + * @typedef {Object} LiveIntentCollectConfig + * @property {(string|undefined)} fpiStorageStrategy - defines whether the first party identifiers that LiveConnect creates and updates are stored in a cookie jar, local storage, or not created at all + * @property {(number|undefined)} fpiExpirationDays - the expiration time of an identifier created and updated by LiveConnect + * @property {(string|undefined)} collectorUrl - defines where the LiveIntentId signal pixels are pointing to + * @property {(string|undefined)} appId - the unique identifier of the application in question + */ + /** * @typedef {Object} SubmoduleParams * @property {(string|undefined)} partner - partner url param value @@ -72,7 +81,10 @@ * @property {(boolean|undefined)} extend - extend expiration time on each access. default is false. * @property {(string|undefined)} pid - placement id url param value * @property {(string|undefined)} publisherId - the unique identifier of the publisher in question + * @property {(string|undefined)} ajaxTimeout - the number of milliseconds a resolution request can take before automatically being terminated * @property {(array|undefined)} identifiersToResolve - the identifiers from either ls|cookie to be attached to the getId query + * @property {(string|undefined)} providedIdentifierName - defines the name of an identifier that can be found in local storage or in the cookie jar that can be sent along with the getId request. This parameter should be used whenever a customer is able to provide the most stable identifier possible + * @property {(LiveIntentCollectConfig|undefined)} liCollectConfig - the config for LiveIntent's collect requests */ /** @@ -96,20 +108,23 @@ * @property {(function|undefined)} callback - function that will return an id */ -import find from 'core-js/library/fn/array/find'; -import {config} from '../../src/config'; -import events from '../../src/events'; -import * as utils from '../../src/utils'; -import {getGlobal} from '../../src/prebidGlobal'; -import {gdprDataHandler} from '../../src/adapterManager'; +import find from 'core-js-pure/features/array/find.js'; +import {config} from '../../src/config.js'; +import events from '../../src/events.js'; +import * as utils from '../../src/utils.js'; +import {getGlobal} from '../../src/prebidGlobal.js'; +import {gdprDataHandler} from '../../src/adapterManager.js'; import CONSTANTS from '../../src/constants.json'; -import {module} from '../../src/hook'; +import {module, hook} from '../../src/hook.js'; +import {createEidsArray} from './eids.js'; +import { getCoreStorageManager } from '../../src/storageManager.js'; const MODULE_NAME = 'User ID'; const COOKIE = 'cookie'; const LOCAL_STORAGE = 'html5'; const DEFAULT_SYNC_DELAY = 500; const NO_AUCTION_DELAY = 0; +export const coreStorage = getCoreStorageManager('userid'); /** @type {string[]} */ let validStorageTypes = []; @@ -129,6 +144,9 @@ let configRegistry = []; /** @type {Submodule[]} */ let submoduleRegistry = []; +/** @type {(number|undefined)} */ +let timeoutID; + /** @type {(number|undefined)} */ export let syncDelay; @@ -149,15 +167,15 @@ function setStoredValue(storage, value) { 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) { - utils.setCookie(storage.name, valueStr, expiresStr, 'Lax'); + coreStorage.setCookie(storage.name, valueStr, expiresStr, 'Lax'); if (typeof storage.refreshInSeconds === 'number') { - utils.setCookie(`${storage.name}_last`, new Date().toUTCString(), expiresStr); + coreStorage.setCookie(`${storage.name}_last`, new Date().toUTCString(), expiresStr); } } else if (storage.type === LOCAL_STORAGE) { - localStorage.setItem(`${storage.name}_exp`, expiresStr); - localStorage.setItem(storage.name, encodeURIComponent(valueStr)); + coreStorage.setDataInLocalStorage(`${storage.name}_exp`, expiresStr); + coreStorage.setDataInLocalStorage(storage.name, encodeURIComponent(valueStr)); if (typeof storage.refreshInSeconds === 'number') { - localStorage.setItem(`${storage.name}_last`, new Date().toUTCString()); + coreStorage.setDataInLocalStorage(`${storage.name}_last`, new Date().toUTCString()); } } } catch (error) { @@ -175,15 +193,15 @@ function getStoredValue(storage, key = undefined) { let storedValue; try { if (storage.type === COOKIE) { - storedValue = utils.getCookie(storedKey); + storedValue = coreStorage.getCookie(storedKey); } else if (storage.type === LOCAL_STORAGE) { - const storedValueExp = localStorage.getItem(`${storage.name}_exp`); + const storedValueExp = coreStorage.getDataFromLocalStorage(`${storage.name}_exp`); // empty string means no expiration set if (storedValueExp === '') { - storedValue = localStorage.getItem(storedKey); + storedValue = coreStorage.getDataFromLocalStorage(storedKey); } else if (storedValueExp) { if ((new Date(storedValueExp)).getTime() - Date.now() > 0) { - storedValue = decodeURIComponent(localStorage.getItem(storedKey)); + storedValue = decodeURIComponent(coreStorage.getDataFromLocalStorage(storedKey)); } } } @@ -207,7 +225,10 @@ function hasGDPRConsent(consentData) { if (!consentData.consentString) { return false; } - if (consentData.vendorData && consentData.vendorData.purposeConsents && consentData.vendorData.purposeConsents['1'] === false) { + if (consentData.apiVersion === 1 && utils.deepAccess(consentData, 'vendorData.purposeConsents.1') === false) { + return false; + } + if (consentData.apiVersion === 2 && utils.deepAccess(consentData, 'vendorData.purpose.consents.1') === false) { return false; } } @@ -230,7 +251,7 @@ function processSubmoduleCallbacks(submodules, cb) { // 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(); }); @@ -238,6 +259,7 @@ function processSubmoduleCallbacks(submodules, cb) { // clear callback, this prop is used to test if all submodule callbacks are complete below submodule.callback = undefined; }); + clearTimeout(timeoutID); } /** @@ -267,11 +289,13 @@ function addIdDataToAdUnitBids(adUnits, submodules) { return; } const combinedSubmoduleIds = getCombinedSubmoduleIds(submodules); + const combinedSubmoduleIdsAsEids = createEidsArray(combinedSubmoduleIds); if (Object.keys(combinedSubmoduleIds).length) { adUnits.forEach(adUnit => { adUnit.bids.forEach(bid => { // create a User ID object on the bid, bid.userId = combinedSubmoduleIds; + bid.userIdAsEids = combinedSubmoduleIdsAsEids; }); }); } @@ -302,9 +326,9 @@ function initializeSubmodulesAndExecuteCallbacks(continueAuction) { } } utils.logInfo(`${MODULE_NAME} - auction delayed by ${auctionDelay} at most to fetch ids`); - processSubmoduleCallbacks(submodulesWithCallbacks, continueCallback); - setTimeout(continueCallback, auctionDelay); + timeoutID = setTimeout(continueCallback, auctionDelay); + processSubmoduleCallbacks(submodulesWithCallbacks, continueCallback); } else { // wait for auction complete before processing submodule callbacks events.on(CONSTANTS.EVENTS.AUCTION_END, function auctionEndHandler() { @@ -358,6 +382,23 @@ function getUserIds() { return getCombinedSubmoduleIds(initializedSubmodules); } +/** + * This function will be exposed in global-name-space so that userIds stored by Prebid UserId module can be used by external codes as well. + * Simple use case will be passing these UserIds to A9 wrapper solution + */ +function getUserIdsAsEids() { + // initialize submodules only when undefined + initializeSubmodulesAndExecuteCallbacks(); + return createEidsArray(getCombinedSubmoduleIds(initializedSubmodules)); +} + +/** + * 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 {userIdModules: submodules, hasValidated: consentData && consentData.hasValidated}; +}, 'validateGdprEnforcement'); + /** * @param {SubmoduleContainer[]} submodules * @param {ConsentData} consentData @@ -365,12 +406,13 @@ function getUserIds() { */ function initSubmodules(submodules, consentData) { // gdpr consent with purpose one is required, otherwise exit immediately - 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 []; } - return submodules.reduce((carry, submodule) => { + return userIdModules.reduce((carry, submodule) => { // There are two submodule configuration types to handle: storage or value // 1. storage: retrieve user id data from cookie/html storage or with the submodule's getId method // 2. value: pass directly to bids @@ -384,10 +426,6 @@ 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. response = submodule.submodule.getId(submodule.config.params, consentData, storedId); @@ -411,7 +449,7 @@ function initSubmodules(submodules, consentData) { if (storedId) { // cache decoded value (this is copied to every adUnit bid) - submodule.idObj = submodule.submodule.decode(storedId); + submodule.idObj = submodule.submodule.decode(storedId, submodule.config.params); } } else if (submodule.config.value) { // cache decoded value (this is copied to every adUnit bid) @@ -420,7 +458,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); } + if (response.id) { submodule.idObj = submodule.submodule.decode(response.id, submodule.config.params); } } } carry.push(submodule); @@ -516,17 +554,17 @@ export function init(config) { // list of browser enabled storage types validStorageTypes = [ - utils.localStorageIsEnabled() ? LOCAL_STORAGE : null, - utils.cookiesAreEnabled() ? COOKIE : null + coreStorage.localStorageIsEnabled() ? LOCAL_STORAGE : null, + coreStorage.cookiesAreEnabled() ? COOKIE : null ].filter(i => i !== null); // exit immediately if opt out cookie or local storage keys exists. - if (validStorageTypes.indexOf(COOKIE) !== -1 && (utils.getCookie('_pbjs_id_optout') || utils.getCookie('_pubcid_optout'))) { + if (validStorageTypes.indexOf(COOKIE) !== -1 && (coreStorage.getCookie('_pbjs_id_optout') || coreStorage.getCookie('_pubcid_optout'))) { utils.logInfo(`${MODULE_NAME} - opt-out cookie found, exit module`); return; } // _pubcid_optout is checked for compatiblility with pubCommonId - if (validStorageTypes.indexOf(LOCAL_STORAGE) !== -1 && (localStorage.getItem('_pbjs_id_optout') || localStorage.getItem('_pubcid_optout'))) { + 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; } @@ -544,6 +582,7 @@ export function init(config) { // exposing getUserIds function in global-name-space so that userIds stored in Prebid can be used by external codes. (getGlobal()).getUserIds = getUserIds; + (getGlobal()).getUserIdsAsEids = getUserIdsAsEids; } // init config update listener to start the application diff --git a/modules/userId/userId.md b/modules/userId/userId.md index b10aa2adc20..566d719c90d 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://console.id5.io/docs/public/prebid 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,11 +39,6 @@ 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', @@ -64,6 +60,16 @@ pbjs.setConfig({ 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 @@ -113,6 +119,16 @@ pbjs.setConfig({ 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 } @@ -132,6 +148,10 @@ pbjs.setConfig({ { name: "id5Id", value: { "id5id": "ID5-abcdef" } + }, + { + name: "netId", + value: { "netId": "fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg" } }], syncDelay: 5000 } diff --git a/modules/userIdTargeting.js b/modules/userIdTargeting.js index 2a19bd62fbb..3ed8b2a14b5 100644 --- a/modules/userIdTargeting.js +++ b/modules/userIdTargeting.js @@ -1,8 +1,8 @@ -import {config} from '../src/config'; -import {getGlobal} from '../src/prebidGlobal'; +import {config} from '../src/config.js'; +import {getGlobal} from '../src/prebidGlobal.js'; import CONSTANTS from '../src/constants.json'; -import events from '../src/events'; -import { isStr, isPlainObject, isBoolean, isFn, hasOwn, logInfo } from '../src/utils'; +import events from '../src/events.js'; +import { isStr, isPlainObject, isBoolean, isFn, hasOwn, logInfo } from '../src/utils.js'; const MODULE_NAME = 'userIdTargeting'; const GAM = 'GAM'; diff --git a/modules/vdoaiBidAdapter.js b/modules/vdoaiBidAdapter.js new file mode 100644 index 00000000000..395953fb737 --- /dev/null +++ b/modules/vdoaiBidAdapter.js @@ -0,0 +1,119 @@ +import * as utils from '../src/utils.js'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'vdo.ai'; +const ENDPOINT_URL = 'https://prebid.vdo.ai/auction'; + +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. + * + * @return Array Info describing the request to the server. + * @param validBidRequests + * @param bidderRequest + */ + buildRequests: function (validBidRequests, bidderRequest) { + if (validBidRequests.length === 0) { + return []; + } + return validBidRequests.map(bidRequest => { + const sizes = utils.parseSizesInput(bidRequest.params.size || bidRequest.sizes)[0]; + const width = sizes.split('x')[0]; + const height = sizes.split('x')[1]; + const payload = { + placementId: bidRequest.params.placementId, + width: width, + height: height, + bidId: bidRequest.bidId, + referer: bidderRequest.refererInfo.referer, + id: bidRequest.auctionId + }; + bidRequest.params.bidFloor && (payload['bidFloor'] = bidRequest.params.bidFloor); + 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; + const creativeId = response.adid || 0; + // const width = response.w || 0; + const width = bidRequest.data.width; + // const height = response.h || 0; + const height = bidRequest.data.height; + const cpm = response.price || 0; + + response.rWidth = width; + response.rHeight = height; + + const adCreative = response.vdoCreative; + + if (width !== 0 && height !== 0 && cpm !== 0 && creativeId !== 0) { + // const dealId = response.dealid || ''; + const currency = response.cur || 'USD'; + const netRevenue = true; + // const referrer = bidRequest.data.referer; + const bidResponse = { + requestId: response.bidId, + cpm: cpm, + width: width, + height: height, + creativeId: creativeId, + // dealId: dealId, + currency: currency, + netRevenue: netRevenue, + ttl: config.getConfig('_bidderTimeout'), + // referrer: referrer, + // ad: response.adm + ad: adCreative + }; + bidResponses.push(bidResponse); + } + return bidResponses; + }, + + getUserSyncs: function(syncOptions, serverResponse) { + let syncUrls = serverResponse[0] && serverResponse[0].body && serverResponse[0].body.cookiesync && serverResponse[0].body.cookiesync.bidder_status; + + if (syncOptions.iframeEnabled && syncUrls && syncUrls.length > 0) { + let prebidSyncUrls = syncUrls.map(syncObj => { + return { + url: syncObj.usersync.url, + type: 'iframe' + } + }) + return prebidSyncUrls; + } + return []; + }, + + onTImeout: function(data) {}, + onBidWon: function(bid) {}, + onSetTargeting: function(bid) {} +}; +registerBidder(spec); diff --git a/modules/vdoaiBidAdapter.md b/modules/vdoaiBidAdapter.md new file mode 100644 index 00000000000..81bd8e69c1d --- /dev/null +++ b/modules/vdoaiBidAdapter.md @@ -0,0 +1,34 @@ +# Overview + +``` +Module Name: VDO.AI Bidder Adapter +Module Type: Bidder Adapter +Maintainer: arjit@z1media.com +``` + +# Description + +Module that connects to VDO.AI's demand sources + +# Test Parameters +``` + var adUnits = [ + { + code: 'test-div', + mediaTypes: { + banner: { + sizes: [[300, 250]] // a display size + } + }, + bids: [ + { + bidder: "vdo.ai", + params: { + placement: 'newsdv77', + bidFloor: 0.01 // Optional + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/modules/viBidAdapter.js b/modules/viBidAdapter.js index 8d8cb06e47e..4a09a2d2fc1 100644 --- a/modules/viBidAdapter.js +++ b/modules/viBidAdapter.js @@ -1,5 +1,5 @@ -import { registerBidder } from '../src/adapters/bidderFactory'; -import * as mediaTypes from '../src/mediaTypes'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import * as mediaTypes from '../src/mediaTypes.js'; export function get(path, obj, notFound) { path = typeof path === 'string' ? path.split('.') : path; diff --git a/modules/vidazooBidAdapter.js b/modules/vidazooBidAdapter.js index 4c1abd1c390..3eea270dc8d 100644 --- a/modules/vidazooBidAdapter.js +++ b/modules/vidazooBidAdapter.js @@ -1,8 +1,10 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {BANNER} from '../src/mediaTypes'; -export const URL = 'https://prebid.cootlogix.com'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; + +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 = { @@ -13,31 +15,65 @@ const EXTERNAL_SYNC_TYPE = { IFRAME: 'iframe', IMAGE: 'image' }; +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, +}; + +export function createDomain(subDomain = DEFAULT_SUB_DOMAIN) { + return `https://${subDomain}.cootlogix.com`; +} function isBidRequestValid(bid) { const params = bid.params || {}; return !!(params.cId && params.pId); } -function buildRequest(bid, topWindowUrl, size, bidderRequest) { - const {params, bidId} = bid; - const {bidFloor, cId, pId, ext} = params; - // Prebid's util function returns AppNexus style sizes (i.e. 300x250) - const [width, height] = size.split('x'); +function buildRequest(bid, topWindowUrl, sizes, bidderRequest) { + const { params, bidId, userId, adUnitCode } = bid; + const { bidFloor, cId, pId, ext, subDomain } = params; + const hashUrl = hashCode(topWindowUrl); + const dealId = getNextDealId(hashUrl); - const dto = { - method: 'GET', - url: `${URL}/prebid/${cId}`, - data: { - url: encodeURIComponent(topWindowUrl), - cb: Date.now(), - bidFloor: bidFloor, - bidId: bidId, - publisherId: pId, - consent: bidderRequest.gdprConsent && bidderRequest.gdprConsent.consentString, - width, - height + let data = { + url: encodeURIComponent(topWindowUrl), + cb: Date.now(), + bidFloor: bidFloor, + bidId: bidId, + adUnitCode: adUnitCode, + publisherId: pId, + sizes: sizes, + dealId: dealId, + 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; + } + if (bidderRequest.gdprConsent.gdprApplies !== undefined) { + data.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; } + } + if (bidderRequest.uspConsent) { + data.usPrivacy = bidderRequest.uspConsent + } + const dto = { + method: 'POST', + url: `${createDomain(subDomain)}/prebid/multi/${cId}`, + data: data }; utils._each(ext, (value, key) => { @@ -47,15 +83,33 @@ function buildRequest(bid, topWindowUrl, size, 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; + default: + payloadRef[key] = userId; + } + } + }); +} + function buildRequests(validBidRequests, bidderRequest) { const topWindowUrl = bidderRequest.refererInfo.referer; const requests = []; validBidRequests.forEach(validBidRequest => { const sizes = utils.parseSizesInput(validBidRequest.sizes); - sizes.forEach(size => { - const request = buildRequest(validBidRequest, topWindowUrl, size, bidderRequest); - requests.push(request); - }); + const request = buildRequest(validBidRequest, topWindowUrl, sizes, bidderRequest); + requests.push(request); }); return requests; } @@ -64,30 +118,37 @@ function interpretResponse(serverResponse, request) { if (!serverResponse || !serverResponse.body) { return []; } - const {creativeId, ad, price, exp} = serverResponse.body; - if (!ad || !price) { - return []; - } - const {bidId, width, height} = request.data; + const { bidId } = request.data; + const { results } = serverResponse.body; + + let output = []; + try { - return [{ - requestId: bidId, - cpm: price, - width: width, - height: height, - creativeId: creativeId, - currency: CURRENCY, - netRevenue: true, - ttl: exp || TTL_SECONDS, - ad: ad - }]; + results.forEach(result => { + const { creativeId, ad, price, exp, width, height, currency } = result; + if (!ad || !price) { + return; + } + output.push({ + requestId: bidId, + cpm: price, + width: width, + height: height, + creativeId: creativeId, + currency: currency || CURRENCY, + netRevenue: true, + ttl: exp || TTL_SECONDS, + ad: ad + }) + }); + return output; } catch (e) { return []; } } function getUserSyncs(syncOptions, responses) { - const {iframeEnabled, pixelEnabled} = syncOptions; + const { iframeEnabled, pixelEnabled } = syncOptions; if (iframeEnabled) { return [{ @@ -100,21 +161,19 @@ function getUserSyncs(syncOptions, responses) { const lookup = {}; const syncs = []; responses.forEach(response => { - const {body} = response; - const cookies = body ? body.cookies || [] : []; - cookies.forEach(cookie => { - switch (cookie.type) { - case INTERNAL_SYNC_TYPE.IFRAME: - break; - case INTERNAL_SYNC_TYPE.IMAGE: + 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 }); } - break; - } + } + }); }); }); return syncs; @@ -123,8 +182,48 @@ function getUserSyncs(syncOptions, responses) { return []; } +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; +} + +function getNextDealId(key) { + try { + const currentValue = Number(getStorageItem(key) || 0); + const nextValue = currentValue + 1; + setStorageItem(key, nextValue); + return nextValue; + } catch (e) { + return 0; + } +} + +function getStorage() { + return window['sessionStorage']; +} + +function getStorageItem(key) { + try { + return getStorage().getItem(key); + } catch (e) { + return null; + } +} + +function setStorageItem(key, value) { + try { + getStorage().setItem(key, String(value)); + } catch (e) { } +} + export const spec = { code: BIDDER_CODE, + version: BIDDER_VERSION, supportedMediaTypes: [BANNER], isBidRequestValid, buildRequests, diff --git a/modules/vidazooBidAdapter.md b/modules/vidazooBidAdapter.md index 1e9dc47dd51..df7700cb05a 100644 --- a/modules/vidazooBidAdapter.md +++ b/modules/vidazooBidAdapter.md @@ -4,7 +4,7 @@ **Module Type:** Bidder Adapter -**Maintainer:** server-dev@getintent.com +**Maintainer:** dev@vidazoo.com # Description diff --git a/modules/videoNowBidAdapter.js b/modules/videoNowBidAdapter.js index 5c5d0893248..b391af08d49 100644 --- a/modules/videoNowBidAdapter.js +++ b/modules/videoNowBidAdapter.js @@ -1,7 +1,7 @@ -import * as utils from '../src/utils' -import { registerBidder } from '../src/adapters/bidderFactory' -import { BANNER } from '../src/mediaTypes' -import { loadExternalScript } from '../src/adloader' +import * as utils from '../src/utils.js' +import { registerBidder } from '../src/adapters/bidderFactory.js' +import { BANNER } from '../src/mediaTypes.js' +import { loadExternalScript } from '../src/adloader.js' const RTB_URL = 'https://bidder.videonow.ru/prebid' 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/videoreachBidAdapter.js b/modules/videoreachBidAdapter.js index 8de32633eb0..710920c54fc 100644 --- a/modules/videoreachBidAdapter.js +++ b/modules/videoreachBidAdapter.js @@ -1,5 +1,5 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; -const utils = require('../src/utils'); +import {registerBidder} from '../src/adapters/bidderFactory.js'; +const utils = require('../src/utils.js'); const BIDDER_CODE = 'videoreach'; const ENDPOINT_URL = 'https://a.videoreach.com/hb/'; diff --git a/modules/viewdeosDXBidAdapter.js b/modules/viewdeosDXBidAdapter.js index 1de93aad95a..52894ef2dd9 100644 --- a/modules/viewdeosDXBidAdapter.js +++ b/modules/viewdeosDXBidAdapter.js @@ -1,10 +1,10 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import {VIDEO, BANNER} from '../src/mediaTypes'; -import {Renderer} from '../src/Renderer'; -import findIndex from 'core-js/library/fn/array/find-index'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {VIDEO, BANNER} from '../src/mediaTypes.js'; +import {Renderer} from '../src/Renderer.js'; +import findIndex from 'core-js-pure/features/array/find-index.js'; -const URL = 'https://hb.sync.viewdeos.com/auction/'; +const URL = 'https://ghb.sync.viewdeos.com/auction/'; const OUTSTREAM_SRC = 'https://player.sync.viewdeos.com/outstream-unit/2.01/outstream.min.js'; const BIDDER_CODE = 'viewdeosDX'; const OUTSTREAM = 'outstream'; @@ -112,7 +112,8 @@ function parseRTBResponse(serverResponse, bidderRequest) { }); if (serverBid.cpm !== 0 && requestId !== -1) { - const bid = createBid(serverBid, getMediaType(bidderRequest.bids[requestId])); + const bidReq = bidderRequest.bids[requestId]; + const bid = createBid(serverBid, getMediaType(bidReq), bidReq.params); bids.push(bid); } @@ -131,6 +132,10 @@ function bidToTag(bidRequests, bidderRequest) { tag.gdpr_consent = utils.deepAccess(bidderRequest, 'gdprConsent.consentString'); } + if (utils.deepAccess(bidderRequest, 'bidderRequest.uspConsent')) { + tag.us_privacy = bidderRequest.uspConsent; + } + for (let i = 0, length = bidRequests.length; i < length; i++) { Object.assign(tag, prepareRTBRequestParams(i, bidRequests[i])); } @@ -174,7 +179,7 @@ function getMediaType(bidderRequest) { * @param mediaType {Object} * @returns {object} */ -function createBid(bidResponse, mediaType) { +function createBid(bidResponse, mediaType, bidderParams) { const bid = { requestId: bidResponse.requestId, creativeId: bidResponse.cmpId, @@ -201,7 +206,7 @@ function createBid(bidResponse, mediaType) { Object.assign(bid, { mediaType: 'video', adResponse: bidResponse, - renderer: newRenderer(bidResponse.requestId) + renderer: newRenderer(bidResponse.requestId, bidderParams) }); } @@ -213,10 +218,11 @@ function createBid(bidResponse, mediaType) { * @param requestId * @returns {*} */ -function newRenderer(requestId) { +function newRenderer(requestId, bidderParams) { const renderer = Renderer.install({ id: requestId, url: OUTSTREAM_SRC, + config: bidderParams.outstream || {}, loaded: false }); @@ -231,12 +237,13 @@ function newRenderer(requestId) { */ function outstreamRender(bid) { bid.renderer.push(() => { - window.VOutstreamAPI.initOutstreams([{ + const opts = Object.assign({}, bid.renderer.getConfig(), { width: bid.width, height: bid.height, vastUrl: bid.vastUrl, elId: bid.adUnitCode - }]); + }); + window.VOutstreamAPI.initOutstreams([opts]); }); } diff --git a/modules/viewdeosDXBidAdapter.md b/modules/viewdeosDXBidAdapter.md index d9ede8cc312..a3fa34525b8 100644 --- a/modules/viewdeosDXBidAdapter.md +++ b/modules/viewdeosDXBidAdapter.md @@ -14,10 +14,10 @@ Get access to multiple demand partners across Viewdeos and maximize your yield w // Video instream adUnit { code: 'div-test-div', - sizes: [[640, 480]], mediaTypes: { video: { - context: 'instream' + context: 'instream', + playerSize: [[640, 480]] } }, bids: [{ @@ -31,16 +31,20 @@ Get access to multiple demand partners across Viewdeos and maximize your yield w // Video outstream adUnit { code: 'outstream-test-div', - sizes: [[640, 480]], mediaTypes: { video: { - context: 'outstream' + context: 'outstream', + playerSize: [[640, 480]] } }, bids: [{ bidder: 'viewdeosDX', params: { - aid: 331133 + aid: 331133, + outstream: { + default_volume:50, + video_controls:'show' + } } }] }, diff --git a/modules/visxBidAdapter.js b/modules/visxBidAdapter.js index b043d2b7709..511e658c947 100644 --- a/modules/visxBidAdapter.js +++ b/modules/visxBidAdapter.js @@ -1,6 +1,6 @@ -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { config } from '../src/config'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; const BIDDER_CODE = 'visx'; const ENDPOINT_URL = 'https://t.visx.net/hb'; const TIME_TO_LIVE = 360; @@ -36,6 +36,8 @@ export const spec = { config.getConfig('currency.adServerCurrency') || DEFAULT_CUR; let reqId; + let payloadSchain; + let payloadUserId; if (currencyWhiteList.indexOf(currency) === -1) { utils.logError(LOG_ERROR_MESS.notAllowedCurrency + currency); @@ -44,8 +46,14 @@ export const spec = { bids.forEach(bid => { reqId = bid.bidderRequestId; - const {params: {uid}, adUnitCode} = bid; + const {params: {uid}, adUnitCode, schain, userId} = bid; auids.push(uid); + if (!payloadSchain && schain) { + payloadSchain = schain; + } + if (!payloadUserId && userId) { + payloadUserId = userId; + } const sizesId = utils.parseSizesInput(bid.sizes); if (!slotsMapByUid[uid]) { @@ -84,6 +92,22 @@ export const spec = { wrapperVersion: '$prebid.version$' }; + if (payloadSchain) { + payload.schain = JSON.stringify(payloadSchain); + } + + if (payloadUserId) { + if (payloadUserId.tdid) { + payload.tdid = payloadUserId.tdid; + } + if (payloadUserId.id5id) { + payload.id5 = payloadUserId.id5id; + } + if (payloadUserId.digitrustid && payloadUserId.digitrustid.data && payloadUserId.digitrustid.data.id) { + payload.dtid = payloadUserId.digitrustid.data.id; + } + } + if (bidderRequest) { if (bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { payload.u = bidderRequest.refererInfo.referer; @@ -179,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/vmgBidAdapter.js b/modules/vmgBidAdapter.js index 2bed62c5d67..57a812ec466 100644 --- a/modules/vmgBidAdapter.js +++ b/modules/vmgBidAdapter.js @@ -1,4 +1,4 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'vmg'; const ENDPOINT = 'https://predict.vmg.nyc'; diff --git a/modules/vrtcalBidAdapter.js b/modules/vrtcalBidAdapter.js index 139f985ed67..ff24803f688 100644 --- a/modules/vrtcalBidAdapter.js +++ b/modules/vrtcalBidAdapter.js @@ -1,6 +1,6 @@ -import {registerBidder} from '../src/adapters/bidderFactory'; -import { BANNER } from '../src/mediaTypes'; -import {ajax} from '../src/ajax'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import {ajax} from '../src/ajax.js'; export const spec = { code: 'vrtcal', diff --git a/modules/vubleBidAdapter.js b/modules/vubleBidAdapter.js index 288390f01c9..d14f24e9993 100644 --- a/modules/vubleBidAdapter.js +++ b/modules/vubleBidAdapter.js @@ -1,8 +1,8 @@ // Vuble Adapter -import * as utils from '../src/utils'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { Renderer } from '../src/Renderer'; +import * as utils from '../src/utils.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; const BIDDER_CODE = 'vuble'; @@ -108,6 +108,13 @@ export const spec = { adUnitCode: bidRequest.adUnitCode }; + if (bidderRequest && bidderRequest.gdprConsent) { + data.gdpr_consent = { + consent_string: bidderRequest.gdprConsent.consentString, + gdpr_applies: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : true + } + } + return { method: 'POST', url: url, diff --git a/modules/waardexBidAdapter.js b/modules/waardexBidAdapter.js new file mode 100644 index 00000000000..255bf24098b --- /dev/null +++ b/modules/waardexBidAdapter.js @@ -0,0 +1,218 @@ +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, + placementId: params.placementId, + 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.placementId && +bid.params.pubId), + + /** + * @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 pubId = ''; + if (validBidRequests[0] && validBidRequests[0].params && +validBidRequests[0].params.pubId) { + pubId = +validBidRequests[0].params.pubId; + } + + const url = `${ENDPOINT}?pubId=${pubId}`; + + 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..3913cfde6a0 --- /dev/null +++ b/modules/welectBidAdapter.js @@ -0,0 +1,87 @@ +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'], + 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: + { + gdpr_applies: bidRequest.gdprConsent.gdprApplies, + gdpr_consent: 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/widespaceBidAdapter.js b/modules/widespaceBidAdapter.js index a93c8fba0a0..3cea5ca57a1 100644 --- a/modules/widespaceBidAdapter.js +++ b/modules/widespaceBidAdapter.js @@ -1,17 +1,17 @@ -import {config} from '../src/config'; -import {registerBidder} from '../src/adapters/bidderFactory'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; import { - cookiesAreEnabled, parseQueryStringParameters, parseSizesInput -} from '../src/utils'; -import includes from 'core-js/library/fn/array/includes'; -import find from 'core-js/library/fn/array/find'; +} from '../src/utils.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import find from 'core-js-pure/features/array/find.js'; +import { getStorageManager } from '../src/storageManager.js'; + +export const storage = getStorageManager(); const BIDDER_CODE = 'widespace'; const WS_ADAPTER_VERSION = '2.0.1'; -const LOCAL_STORAGE_AVAILABLE = window.localStorage; -const COOKIE_ENABLED = cookiesAreEnabled(); const LS_KEYS = { PERF_DATA: 'wsPerfData', LC_UID: 'wsLcuid', @@ -175,37 +175,37 @@ export const spec = { function storeData(data, name, stringify = true) { const value = stringify ? JSON.stringify(data) : data; - if (LOCAL_STORAGE_AVAILABLE) { - localStorage.setItem(name, value); + if (storage.hasLocalStorage()) { + storage.setDataInLocalStorage(name, value); return true; - } else if (COOKIE_ENABLED) { + } else if (storage.cookiesAreEnabled()) { const theDate = new Date(); const expDate = new Date(theDate.setMonth(theDate.getMonth() + 12)).toGMTString(); - window.document.cookie = `${name}=${value};path=/;expires=${expDate}`; + storage.setCookie(name, value, expDate); return true; } } function getData(name, remove = true) { let data = []; - if (LOCAL_STORAGE_AVAILABLE) { + if (storage.hasLocalStorage()) { Object.keys(localStorage).filter((key) => { if (key.indexOf(name) > -1) { - data.push(localStorage.getItem(key)); + data.push(storage.getDataFromLocalStorage(key)); if (remove) { - localStorage.removeItem(key); + storage.removeDataFromLocalStorage(key); } } }); } - if (COOKIE_ENABLED) { + if (storage.cookiesAreEnabled()) { document.cookie.split(';').forEach((item) => { let value = item.split('='); if (value[0].indexOf(name) > -1) { data.push(value[1]); if (remove) { - document.cookie = `${value[0]}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`; + storage.setCookie(value[0], '', 'Thu, 01 Jan 1970 00:00:01 GMT'); } } }); diff --git a/modules/windtalkerBidAdapter.js b/modules/windtalkerBidAdapter.js new file mode 100644 index 00000000000..512cc7f839b --- /dev/null +++ b/modules/windtalkerBidAdapter.js @@ -0,0 +1,307 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import includes from 'core-js-pure/features/array/includes.js'; + +const NATIVE_DEFAULTS = { + TITLE_LEN: 100, + DESCR_LEN: 200, + SPONSORED_BY_LEN: 50, + IMG_MIN: 150, + ICON_MIN: 50, +}; +const DEFAULT_MIMES = ['video/mp4', 'video/webm', 'application/x-shockwave-flash', 'application/javascript']; +const VIDEO_TARGETING = ['mimes', 'skippable', 'playback_method', 'protocols', 'api']; +const DEFAULT_PROTOCOLS = [2, 3, 5, 6]; +const DEFAULT_APIS = [1, 2]; + +export const spec = { + + code: 'windtalker', + supportedMediaTypes: ['banner', 'native', 'video'], + + isBidRequestValid: bid => ( + !!(bid && bid.params && bid.params.pubId && bid.params.placementId) + ), + buildRequests: (bidRequests, bidderRequest) => { + const request = { + id: bidRequests[0].bidderRequestId, + at: 2, + imp: bidRequests.map(slot => impression(slot)), + site: site(bidRequests), + app: app(bidRequests), + device: device(bidRequests), + }; + applyGdpr(bidderRequest, request); + return { + method: 'POST', + url: 'https://windtalkerdisplay.hb.adp3.net/', + data: JSON.stringify(request), + }; + }, + interpretResponse: (response, request) => ( + bidResponseAvailable(request, response.body) + ), +}; + +function bidResponseAvailable(bidRequest, bidResponse) { + const idToImpMap = {}; + const idToBidMap = {}; + const ortbRequest = parse(bidRequest.data); + ortbRequest.imp.forEach(imp => { + idToImpMap[imp.id] = imp; + }); + if (bidResponse) { + bidResponse.seatbid.forEach(seatBid => seatBid.bid.forEach(bid => { + idToBidMap[bid.impid] = bid; + })); + } + const bids = []; + Object.keys(idToImpMap).forEach(id => { + if (idToBidMap[id]) { + const bid = {}; + bid.requestId = id; + bid.adId = id; + bid.creativeId = id; + bid.cpm = idToBidMap[id].price; + bid.currency = bidResponse.cur; + bid.ttl = 360; + bid.netRevenue = true; + if (idToImpMap[id]['native']) { + bid['native'] = nativeResponse(idToImpMap[id], idToBidMap[id]); + let nurl = idToBidMap[id].nurl; + nurl = nurl.replace(/\$(%7B|\{)AUCTION_IMP_ID(%7D|\})/gi, idToBidMap[id].impid); + nurl = nurl.replace(/\$(%7B|\{)AUCTION_PRICE(%7D|\})/gi, idToBidMap[id].price); + nurl = nurl.replace(/\$(%7B|\{)AUCTION_CURRENCY(%7D|\})/gi, bidResponse.cur); + nurl = nurl.replace(/\$(%7B|\{)AUCTION_BID_ID(%7D|\})/gi, bidResponse.bidid); + bid['native']['impressionTrackers'] = [nurl]; + bid.mediaType = 'native'; + } else if (idToImpMap[id]['video']) { + bid.vastUrl = idToBidMap[id].adm; + bid.vastUrl = bid.vastUrl.replace(/\$(%7B|\{)AUCTION_PRICE(%7D|\})/gi, idToBidMap[id].price); + bid.crid = idToBidMap[id].crid; + bid.width = idToImpMap[id].video.w; + bid.height = idToImpMap[id].video.h; + bid.mediaType = 'video'; + } else if (idToImpMap[id]['banner']) { + bid.ad = idToBidMap[id].adm; + bid.ad = bid.ad.replace(/\$(%7B|\{)AUCTION_IMP_ID(%7D|\})/gi, idToBidMap[id].impid); + bid.ad = bid.ad.replace(/\$(%7B|\{)AUCTION_AD_ID(%7D|\})/gi, idToBidMap[id].adid); + bid.ad = bid.ad.replace(/\$(%7B|\{)AUCTION_PRICE(%7D|\})/gi, idToBidMap[id].price); + bid.ad = bid.ad.replace(/\$(%7B|\{)AUCTION_CURRENCY(%7D|\})/gi, bidResponse.cur); + bid.ad = bid.ad.replace(/\$(%7B|\{)AUCTION_BID_ID(%7D|\})/gi, bidResponse.bidid); + bid.width = idToBidMap[id].w; + bid.height = idToBidMap[id].h; + bid.mediaType = 'banner'; + } + bids.push(bid); + } + }); + return bids; +} +function impression(slot) { + return { + id: slot.bidId, + secure: window.location.protocol === 'https:' ? 1 : 0, + 'banner': banner(slot), + 'native': nativeImpression(slot), + 'video': videoImpression(slot), + bidfloor: slot.params.bidFloor || '0.000001', + tagid: slot.params.placementId.toString(), + }; +} + +function banner(slot) { + if (slot.mediaType === 'banner' || utils.deepAccess(slot, 'mediaTypes.banner')) { + const sizes = utils.deepAccess(slot, 'mediaTypes.banner.sizes'); + if (sizes.length > 1) { + let format = []; + for (let f = 0; f < sizes.length; f++) { + format.push({'w': sizes[f][0], 'h': sizes[f][1]}); + } + return {'format': format}; + } else { + return { + w: sizes[0][0], + h: sizes[0][1] + } + } + } + return null; +} + +function videoImpression(slot) { + if (slot.mediaType === 'video' || utils.deepAccess(slot, 'mediaTypes.video')) { + const sizes = utils.deepAccess(slot, 'mediaTypes.video.playerSize'); + const video = { + w: sizes[0][0], + h: sizes[0][1], + mimes: DEFAULT_MIMES, + protocols: DEFAULT_PROTOCOLS, + api: DEFAULT_APIS, + }; + if (slot.params.video) { + Object.keys(slot.params.video).filter(param => includes(VIDEO_TARGETING, param)).forEach(param => video[param] = slot.params.video[param]); + } + return video; + } + return null; +} + +function nativeImpression(slot) { + if (slot.mediaType === 'native' || utils.deepAccess(slot, 'mediaTypes.native')) { + const assets = []; + addAsset(assets, titleAsset(1, slot.nativeParams.title, NATIVE_DEFAULTS.TITLE_LEN)); + addAsset(assets, dataAsset(2, slot.nativeParams.body, 2, NATIVE_DEFAULTS.DESCR_LEN)); + addAsset(assets, dataAsset(3, slot.nativeParams.sponsoredBy, 1, NATIVE_DEFAULTS.SPONSORED_BY_LEN)); + addAsset(assets, imageAsset(4, slot.nativeParams.icon, 1, NATIVE_DEFAULTS.ICON_MIN, NATIVE_DEFAULTS.ICON_MIN)); + addAsset(assets, imageAsset(5, slot.nativeParams.image, 3, NATIVE_DEFAULTS.IMG_MIN, NATIVE_DEFAULTS.IMG_MIN)); + return { + request: JSON.stringify({ assets }), + ver: '1.1', + }; + } + return null; +} + +function addAsset(assets, asset) { + if (asset) { + assets.push(asset); + } +} + +function titleAsset(id, params, defaultLen) { + if (params) { + return { + id, + required: params.required ? 1 : 0, + title: { + len: params.len || defaultLen, + }, + }; + } + return null; +} + +function imageAsset(id, params, type, defaultMinWidth, defaultMinHeight) { + return params ? { + id, + required: params.required ? 1 : 0, + img: { + type, + wmin: params.wmin || defaultMinWidth, + hmin: params.hmin || defaultMinHeight, + } + } : null; +} + +function dataAsset(id, params, type, defaultLen) { + return params ? { + id, + required: params.required ? 1 : 0, + data: { + type, + len: params.len || defaultLen, + } + } : null; +} + +function site(bidderRequest) { + const pubId = bidderRequest && bidderRequest.length > 0 ? bidderRequest[0].params.pubId : '0'; + const siteId = bidderRequest && bidderRequest.length > 0 ? bidderRequest[0].params.siteId : '0'; + const appParams = bidderRequest[0].params.app; + if (!appParams) { + return { + publisher: { + id: pubId.toString(), + domain: window.location.hostname, + }, + id: siteId.toString(), + ref: window.top.document.referrer, + page: window.location.href, + } + } + return null; +} + +function app(bidderRequest) { + const pubId = bidderRequest && bidderRequest.length > 0 ? bidderRequest[0].params.pubId : '0'; + const appParams = bidderRequest[0].params.app; + if (appParams) { + return { + publisher: { + id: pubId.toString(), + }, + id: appParams.id, + name: appParams.name, + bundle: appParams.bundle, + storeurl: appParams.storeUrl, + domain: appParams.domain, + } + } + return null; +} + +function device(bidderRequest) { + const lat = bidderRequest && bidderRequest.length > 0 ? bidderRequest[0].params.latitude : ''; + const lon = bidderRequest && bidderRequest.length > 0 ? bidderRequest[0].params.longitude : ''; + const ifa = bidderRequest && bidderRequest.length > 0 ? bidderRequest[0].params.ifa : ''; + return { + dnt: utils.getDNT() ? 1 : 0, + ua: navigator.userAgent, + language: (navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage), + w: (window.screen.width || window.innerWidth), + h: (window.screen.height || window.innerHeigh), + geo: { + lat: lat, + lon: lon, + }, + ifa: ifa, + }; +} + +function parse(rawResponse) { + try { + if (rawResponse) { + return JSON.parse(rawResponse); + } + } catch (ex) { + utils.logError('windtalker.parse', 'ERROR', ex); + } + return null; +} + +function applyGdpr(bidderRequest, ortbRequest) { + if (bidderRequest && bidderRequest.gdprConsent) { + ortbRequest.regs = { ext: { gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0 } }; + ortbRequest.user = { ext: { consent: bidderRequest.gdprConsent.consentString } }; + } +} + +function nativeResponse(imp, bid) { + if (imp['native']) { + const nativeAd = parse(bid.adm); + const keys = {}; + keys.image = {}; + keys.icon = {}; + if (nativeAd && nativeAd['native'] && nativeAd['native'].assets) { + nativeAd['native'].assets.forEach(asset => { + keys.title = asset.title ? asset.title.text : keys.title; + keys.body = asset.data && asset.id === 2 ? asset.data.value : keys.body; + keys.sponsoredBy = asset.data && asset.id === 3 ? asset.data.value : keys.sponsoredBy; + keys.icon.url = asset.img && asset.id === 4 ? asset.img.url : keys.icon.url; + keys.icon.width = asset.img && asset.id === 4 ? asset.img.w : keys.icon.width; + keys.icon.height = asset.img && asset.id === 4 ? asset.img.h : keys.icon.height; + keys.image.url = asset.img && asset.id === 5 ? asset.img.url : keys.image.url; + keys.image.width = asset.img && asset.id === 5 ? asset.img.w : keys.image.width; + keys.image.height = asset.img && asset.id === 5 ? asset.img.h : keys.image.height; + }); + if (nativeAd['native'].link) { + keys.clickUrl = encodeURIComponent(nativeAd['native'].link.url); + } + return keys; + } + } + return null; +} + +registerBidder(spec); diff --git a/modules/windtalkerBidAdapter.md b/modules/windtalkerBidAdapter.md new file mode 100644 index 00000000000..f7441effc47 --- /dev/null +++ b/modules/windtalkerBidAdapter.md @@ -0,0 +1,86 @@ +# Overview + +**Module Name**: Windtalker Bidder Adapter +**Module Type**: Bidder Adapter +**Maintainer**: corbin@windtalker.io + +# Description + +Connects to Windtalker demand source to fetch bids. +Banner, Native, Video formats are supported. +Please use ```windtalker``` as the bidder code. + +# Test Parameters +``` + var adUnits = [{ + code: 'dfp-native-div', + mediaTypes: { + native: { + title: { + required: true, + len: 75 + }, + image: { + required: true + }, + body: { + len: 200 + }, + icon: { + required: false + } + } + }, + bids: [{ + bidder: 'windtalker', + params: { + pubId: '584971', + siteId: '584971', + placementId: '123', + bidFloor: '0.001', // optional + ifa: 'XXX-XXX', // optional + latitude: '40.712775', // optional + longitude: '-74.005973', // optional + } + }] + }, + { + code: 'dfp-banner-div', + mediaTypes: { + banner: { + sizes: [ + [300, 250],[300,600] + ], + } + }, + bids: [{ + bidder: 'windtalker', + params: { + pubId: '584971', + siteId: '584971', + placementId: '123', + } + }] + }, + { + code: 'dfp-video-div', + mediaTypes: { + video: { + playerSize: [[640, 480]], + context: "instream" + } + }, + bids: [{ + bidder: 'windtalker', + params: { + pubId: '584971', + siteId: '584971', + placementId: '123', + video: { + skipppable: true, + } + } + }] + } + ]; +``` diff --git a/modules/wipesBidAdapter.js b/modules/wipesBidAdapter.js new file mode 100644 index 00000000000..f381bcb68a0 --- /dev/null +++ b/modules/wipesBidAdapter.js @@ -0,0 +1,71 @@ +import * as utils from '../src/utils.js'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {BANNER} from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'wipes'; +const ALIAS_BIDDER_CODE = ['wi']; +const SUPPORTED_MEDIA_TYPES = [BANNER] +const ENDPOINT_URL = 'https://adn-srv.reckoner-api.com/v1/prebid'; + +function isBidRequestValid(bid) { + switch (true) { + case !!(bid.params.asid): + break; + default: + utils.logWarn(`isBidRequestValid Error. ${bid.params}, please check your implementation.`); + return false; + } + return true; +} + +function buildRequests(validBidRequests, bidderRequest) { + return validBidRequests.map(bidRequest => { + const bidId = bidRequest.bidId + const params = bidRequest.params; + const asid = params.asid; + return { + method: 'GET', + url: ENDPOINT_URL, + data: { + asid: asid, + bid_id: bidId, + } + } + }); +} + +function interpretResponse(serverResponse, bidRequest) { + const bidResponses = []; + const response = serverResponse.body; + const cpm = response.cpm || 0; + if (cpm !== 0) { + const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue; + const bidResponse = { + requestId: response.bid_id, + cpm: cpm, + width: response.width, + height: response.height, + creativeId: response.video_creative_id || 0, + dealId: response.deal_id, + currency: 'JPY', + netRevenue: netRevenue, + ttl: config.getConfig('_bidderTimeout'), + referrer: bidRequest.data.r || '', + mediaType: BANNER, + ad: response.ad_tag, + }; + bidResponses.push(bidResponse); + } + return bidResponses; +} + +export const spec = { + code: BIDDER_CODE, + aliases: ALIAS_BIDDER_CODE, + isBidRequestValid, + buildRequests, + interpretResponse, + supportedMediaTypes: SUPPORTED_MEDIA_TYPES +} +registerBidder(spec); diff --git a/modules/wipesBidAdapter.md b/modules/wipesBidAdapter.md new file mode 100644 index 00000000000..712bf0b15d8 --- /dev/null +++ b/modules/wipesBidAdapter.md @@ -0,0 +1,33 @@ +# Overview + +``` +Module Name: WIPES Bidder Adapter +Module Type: Bidder Adapter +Maintainer: contact@3-shake.com +``` + +# Description + +Connect to WIPES for bids. +Publishers needs to be set up and approved by WIPES team to enable this adapter. +Please contact support@wipestream.com for further information. + +# Test Parameters +```javascript +var adUnits = [ + // adUnit + { + code: 'video-div', + mediaTypes: { + banner: { + sizes: [[160, 300]], + } + }, + bids: [{ + bidder: 'wipes', + params: { + asid: 'dWyPondh2EGB_bNlrVjzIXRZO9F0k1dpo0I8ZvQ' + } + }] + }] +``` diff --git a/modules/xhbBidAdapter.js b/modules/xhbBidAdapter.js index 8660889786e..9363eb97ddc 100644 --- a/modules/xhbBidAdapter.js +++ b/modules/xhbBidAdapter.js @@ -1,9 +1,9 @@ -import { Renderer } from '../src/Renderer'; -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; -import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes'; -import find from 'core-js/library/fn/array/find'; -import includes from 'core-js/library/fn/array/includes'; +import { Renderer } from '../src/Renderer.js'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } 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 BIDDER_CODE = 'xhb'; const URL = 'https://ib.adnxs.com/ut/v3/prebid'; @@ -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 9af3de24cb1..9c2b6abf475 100644 --- a/modules/yieldlabBidAdapter.js +++ b/modules/yieldlabBidAdapter.js @@ -1,8 +1,8 @@ -import * as utils from '../src/utils' -import { registerBidder } from '../src/adapters/bidderFactory' -import find from 'core-js/library/fn/array/find' -import { VIDEO, BANNER } from '../src/mediaTypes' -import { Renderer } from '../src/Renderer' +import * as utils from '../src/utils.js' +import { registerBidder } from '../src/adapters/bidderFactory.js' +import find from 'core-js-pure/features/array/find.js' +import { VIDEO, BANNER } from '../src/mediaTypes.js' +import { Renderer } from '../src/Renderer.js' const ENDPOINT = 'https://ad.yieldlab.net' const BIDDER_CODE = 'yieldlab' @@ -39,6 +39,14 @@ export const spec = { if (bid.params.targeting) { query.t = createQueryString(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 (bidderRequest && bidderRequest.gdprConsent) { @@ -80,6 +88,8 @@ export const spec = { const primarysize = bidRequest.sizes.length === 2 && !utils.isArray(bidRequest.sizes[0]) ? bidRequest.sizes : bidRequest.sizes[0] 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 bidResponse = { requestId: bidRequest.bidId, cpm: matchedBid.price / 100, @@ -94,7 +104,7 @@ export const spec = { ad: `` } - if (isVideo(bidRequest)) { + if (isVideo(bidRequest, adType)) { const playersize = getPlayerSize(bidRequest) if (playersize) { bidResponse.width = playersize[0] @@ -124,10 +134,11 @@ export const spec = { /** * Is this a video format? * @param {Object} format + * @param {String} adtype * @returns {Boolean} */ -function isVideo (format) { - return utils.deepAccess(format, 'mediaTypes.video') +function isVideo (format, adtype) { + return utils.deepAccess(format, 'mediaTypes.video') && adtype.toLowerCase() === 'video' } /** @@ -159,6 +170,19 @@ function parseSize (size) { return size.split('x').map(Number) } +/** + * Creates a string out of an array of eids with source and uid + * @param {Array} eids + * @returns {String} + */ +function createUserIdString (eids) { + let str = [] + for (let i = 0; i < eids.length; i++) { + str.push(eids[i].source + ':' + eids[i].uids[0].id) + } + return str.join(',') +} + /** * Creates a querystring out of an object with key-values * @param {Object} obj diff --git a/modules/yieldliftBidAdapter.js b/modules/yieldliftBidAdapter.js new file mode 100644 index 00000000000..87a598bd335 --- /dev/null +++ b/modules/yieldliftBidAdapter.js @@ -0,0 +1,144 @@ +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import * as utils from '../src/utils.js'; +import {BANNER} from '../src/mediaTypes.js'; + +const ENDPOINT_URL = 'https://x.yieldlift.com/auction'; + +const DEFAULT_BID_TTL = 30; +const DEFAULT_CURRENCY = 'USD'; +const DEFAULT_NET_REVENUE = true; + +export const spec = { + code: 'yieldlift', + aliases: ['yl'], + supportedMediaTypes: [BANNER], + + isBidRequestValid: function (bid) { + return (!!bid.params.unitId && typeof bid.params.unitId === 'string') || + (!!bid.params.networkId && typeof bid.params.networkId === 'string') || + (!!bid.params.publisherId && typeof bid.params.publisherId === 'string'); + }, + + buildRequests: function (validBidRequests, bidderRequest) { + if (!validBidRequests || !bidderRequest) { + return; + } + const publisherId = validBidRequests[0].params.publisherId; + const networkId = validBidRequests[0].params.networkId; + const impressions = validBidRequests.map(bidRequest => ({ + id: bidRequest.bidId, + banner: { + format: bidRequest.mediaTypes.banner.sizes.map(sizeArr => ({ + w: sizeArr[0], + h: sizeArr[1] + })) + }, + ext: { + exchange: { + unitId: bidRequest.params.unitId + } + } + })); + + const openrtbRequest = { + id: bidderRequest.auctionId, + imp: impressions, + site: { + domain: window.location.hostname, + page: window.location.href, + ref: bidderRequest.refererInfo ? bidderRequest.refererInfo.referer || null : null + }, + ext: { + exchange: { + publisherId: publisherId, + networkId: networkId, + } + } + }; + + // adding schain object + if (validBidRequests[0].schain) { + utils.deepSetValue(openrtbRequest, 'source.ext.schain', validBidRequests[0].schain); + } + + // Attaching GDPR Consent Params + if (bidderRequest.gdprConsent) { + utils.deepSetValue(openrtbRequest, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + utils.deepSetValue(openrtbRequest, 'regs.ext.gdpr', (bidderRequest.gdprConsent.gdprApplies ? 1 : 0)); + } + + // CCPA + if (bidderRequest.uspConsent) { + utils.deepSetValue(openrtbRequest, 'regs.ext.us_privacy', bidderRequest.uspConsent); + } + + const payloadString = JSON.stringify(openrtbRequest); + return { + method: 'POST', + url: ENDPOINT_URL, + data: payloadString, + }; + }, + + interpretResponse: function (serverResponse) { + const bidResponses = []; + const response = (serverResponse || {}).body; + // response is always one seat (exchange) with (optional) bids for each impression + 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, + width: bid.w, + height: bid.h, + ad: bid.adm, + ttl: DEFAULT_BID_TTL, + creativeId: bid.crid, + netRevenue: DEFAULT_NET_REVENUE, + currency: DEFAULT_CURRENCY, + }) + }) + } else { + utils.logInfo('yieldlift.interpretResponse :: no valid responses to interpret'); + } + return bidResponses; + }, + getUserSyncs: function (syncOptions, serverResponses) { + utils.logInfo('yieldlift.getUserSyncs', 'syncOptions', syncOptions, 'serverResponses', serverResponses); + let syncs = []; + + if (!syncOptions.iframeEnabled && !syncOptions.pixelEnabled) { + return syncs; + } + + serverResponses.forEach(resp => { + const userSync = utils.deepAccess(resp, 'body.ext.usersync'); + if (userSync) { + let syncDetails = []; + Object.keys(userSync).forEach(key => { + const value = userSync[key]; + if (value.syncs && value.syncs.length) { + syncDetails = syncDetails.concat(value.syncs); + } + }); + syncDetails.forEach(syncDetails => { + syncs.push({ + type: syncDetails.type === 'iframe' ? 'iframe' : 'image', + url: syncDetails.url + }); + }); + + if (!syncOptions.iframeEnabled) { + syncs = syncs.filter(s => s.type !== 'iframe') + } + if (!syncOptions.pixelEnabled) { + syncs = syncs.filter(s => s.type !== 'image') + } + } + }); + utils.logInfo('yieldlift.getUserSyncs result=%o', syncs); + return syncs; + }, + +}; +registerBidder(spec); diff --git a/modules/yieldliftBidAdapter.md b/modules/yieldliftBidAdapter.md new file mode 100644 index 00000000000..96b5de1b618 --- /dev/null +++ b/modules/yieldliftBidAdapter.md @@ -0,0 +1,31 @@ +# Overview + +``` +Module Name: YieldLift Bid Adapter +Module Type: Bidder Adapter +Maintainer: info@yieldlift.com +``` + +# Description + +Module that connects to YieldLift's demand sources + +# Test Parameters +``` +var adUnits = [ + { + code: 'banner-ad-div', + mediaTypes: { + banner: { + sizes: [[300, 250], [300,600]] + } + }, + bids: [{ + bidder: 'yieldlift', + params: { + unitId: 'test' + } + }] + } +]; +``` diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js index ccf565df5da..55495979ea4 100644 --- a/modules/yieldmoBidAdapter.js +++ b/modules/yieldmoBidAdapter.js @@ -1,11 +1,10 @@ -import * as utils from '../src/utils'; -import { registerBidder } from '../src/adapters/bidderFactory'; +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'yieldmo'; const CURRENCY = 'USD'; const TIME_TO_LIVE = 300; const NET_REVENUE = true; -const SYNC_ENDPOINT = 'https://static.yieldmo.com/blank.min.html?orig='; const SERVER_ENDPOINT = 'https://ads.yieldmo.com/exchange/prebid'; const localWindow = utils.getWindowTop(); @@ -13,10 +12,10 @@ export const spec = { code: BIDDER_CODE, supportedMediaTypes: ['banner'], /** - * Determines whether or not the given bid request is valid. - * @param {object} bid, bid to validate - * @return boolean, true if valid, otherwise false - */ + * Determines whether or not the given bid request is valid. + * @param {object} bid, bid to validate + * @return boolean, true if valid, otherwise false + */ isBidRequestValid: function(bid) { return !!(bid && bid.adUnitCode && bid.bidId); }, @@ -39,15 +38,25 @@ export const spec = { title: localWindow.document.title || '', w: localWindow.innerWidth, h: localWindow.innerHeight, - userConsent: JSON.stringify({ - // case of undefined, stringify will remove param - gdprApplies: bidderRequest && bidderRequest.gdprConsent ? bidderRequest.gdprConsent.gdprApplies : undefined, - cmp: bidderRequest && bidderRequest.gdprConsent ? bidderRequest.gdprConsent.consentString : undefined - }), - us_privacy: bidderRequest && bidderRequest.us_privacy, + userConsent: + 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 + ? bidderRequest.uspConsent + : '', }; - bidRequests.forEach((request) => { + bidRequests.forEach(request => { serverRequest.p.push(addPlacement(request)); const pubcid = getId(request, 'pubcid'); if (pubcid) { @@ -61,8 +70,13 @@ export const spec = { if (tdid) { serverRequest.tdid = tdid; } + const criteoId = getId(request, 'criteoId'); + if (criteoId) { + serverRequest.cri_prebid = criteoId; + } if (request.schain) { - serverRequest.schain = JSON.stringify(request.schain); + serverRequest.schain = + JSON.stringify(request.schain); } }); serverRequest.p = '[' + serverRequest.p.toString() + ']'; @@ -70,7 +84,7 @@ export const spec = { method: 'GET', url: SERVER_ENDPOINT, data: serverRequest - } + }; }, /** * Makes Yieldmo Ad Server response compatible to Prebid specs @@ -81,7 +95,7 @@ export const spec = { let bids = []; let data = serverResponse.body; if (data.length > 0) { - data.forEach((response) => { + data.forEach(response => { if (response.cpm && response.cpm > 0) { bids.push(createNewBid(response)); } @@ -89,17 +103,10 @@ export const spec = { } return bids; }, - getUserSync: function(syncOptions) { - if (trackingEnabled(syncOptions)) { - return [{ - type: 'iframe', - url: SYNC_ENDPOINT + utils.getOrigin() - }]; - } else { - return []; - } + getUserSyncs: function() { + return []; } -} +}; registerBidder(spec); /*************************************** @@ -115,7 +122,7 @@ function addPlacement(request) { placement_id: request.adUnitCode, callback_id: request.bidId, sizes: request.mediaTypes.banner.sizes - } + }; if (request.params) { if (request.params.placementId) { placementInfo.ym_placement_id = request.params.placementId; @@ -128,9 +135,9 @@ function addPlacement(request) { } /** - * creates a new bid with response information - * @param response server response - */ + * creates a new bid with response information + * @param response server response + */ function createNewBid(response) { return { requestId: response['callback_id'], @@ -141,32 +148,18 @@ function createNewBid(response) { currency: CURRENCY, netRevenue: NET_REVENUE, ttl: TIME_TO_LIVE, - ad: response.ad + ad: response.ad, }; } /** - * Detects if tracking is allowed - * @returns false if dnt or if not iframe/pixel enabled + * Detects whether dnt is true + * @returns true if user enabled dnt */ -function trackingEnabled(options) { - return (isIOS() && !getDNT() && options.iframeEnabled); -} - -/** - * Detects whether we're in iOS - * @returns true if in iOS - */ -function isIOS() { - return /iPhone|iPad|iPod/i.test(window.navigator.userAgent); -} - -/** - * Detects whether dnt is true - * @returns true if user enabled dnt - */ function getDNT() { - return window.doNotTrack === '1' || window.navigator.doNotTrack === '1' || false; + return ( + window.doNotTrack === '1' || window.navigator.doNotTrack === '1' || false + ); } /** @@ -174,7 +167,9 @@ function getDNT() { */ function getPageDescription() { if (document.querySelector('meta[name="description"]')) { - return document.querySelector('meta[name="description"]').getAttribute('content'); // Value of the description metadata from the publisher's page. + return document + .querySelector('meta[name="description"]') + .getAttribute('content'); // Value of the description metadata from the publisher's page. } else { return ''; } @@ -200,9 +195,9 @@ function getPageDescription() { */ /** - * Detects what environment we're in - * @returns Environment kind - */ + * Detects what environment we're in + * @returns Environment kind + */ function getEnvironment() { if (isSuperSandboxedIframe()) { return 89; @@ -228,28 +223,31 @@ function getEnvironment() { } /** - * @returns true if we are running on the top window at dispatch time - */ + * @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 - */ + * @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 - */ + * @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 ( + frameElement.id.indexOf('google_ads_iframe') > -1 && + parentElement.id.indexOf('google_ads_iframe') > -1 + ); } return false; } catch (e) { @@ -258,8 +256,8 @@ function isDfp() { } /** -* @returns true if there is an AMP context object -*/ + * @returns true if there is an AMP context object + */ function isAmp() { try { const ampContext = window.context || window.parent.context; @@ -285,7 +283,11 @@ function isSafeFrame() { function isDFPSafeFrame() { if (window.location && window.location.href) { const href = window.location.href; - return isSafeFrame() && href.indexOf('google') !== -1 && href.indexOf('safeframe') !== -1; + return ( + isSafeFrame() && + href.indexOf('google') !== -1 && + href.indexOf('safeframe') !== -1 + ); } return false; } @@ -318,7 +320,7 @@ function isSuperSandboxedIframe() { * @returns true if the window has the attribute identifying MRAID */ function isMraid() { - return !!(window.mraid); + return !!window.mraid; } /** @@ -329,7 +331,12 @@ function isMraid() { */ function getId(request, idType) { let id; - if (request && request.userId && request.userId[idType] && typeof request.userId === 'object') { + if ( + request && + request.userId && + request.userId[idType] && + typeof request.userId === 'object' + ) { id = request.userId[idType]; } return id; diff --git a/modules/yieldmoBidAdapter.md b/modules/yieldmoBidAdapter.md index ef5f07a4eb9..0f86d2507d1 100644 --- a/modules/yieldmoBidAdapter.md +++ b/modules/yieldmoBidAdapter.md @@ -4,6 +4,7 @@ Module Name: Yieldmo Bid Adapter Module Type: Bidder Adapter Maintainer: opensource@yieldmo.com +Note: Our ads will only render in mobile ``` # Description diff --git a/modules/yieldoneAnalyticsAdapter.js b/modules/yieldoneAnalyticsAdapter.js index 07aca207b4c..dd40e205b07 100644 --- a/modules/yieldoneAnalyticsAdapter.js +++ b/modules/yieldoneAnalyticsAdapter.js @@ -1,10 +1,10 @@ -import {ajax} from '../src/ajax'; -import adapter from '../src/AnalyticsAdapter'; +import {ajax} from '../src/ajax.js'; +import adapter from '../src/AnalyticsAdapter.js'; import CONSTANTS from '../src/constants.json'; -import adapterManager from '../src/adapterManager'; -import { targeting } from '../src/targeting'; -import { auctionManager } from '../src/auctionManager'; -import * as utils from '../src/utils'; +import adapterManager from '../src/adapterManager.js'; +import { targeting } from '../src/targeting.js'; +import { auctionManager } from '../src/auctionManager.js'; +import * as utils from '../src/utils.js'; const ANALYTICS_CODE = 'yieldone'; const analyticsType = 'endpoint'; @@ -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 @@ -121,12 +127,12 @@ const yieldoneAnalytics = Object.assign(adapter({analyticsType}), { 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); } diff --git a/modules/yieldoneBidAdapter.js b/modules/yieldoneBidAdapter.js index 27e8a381a46..59240878426 100644 --- a/modules/yieldoneBidAdapter.js +++ b/modules/yieldoneBidAdapter.js @@ -1,8 +1,8 @@ -import * as utils from '../src/utils'; -import {config} from '../src/config'; -import {registerBidder} from '../src/adapters/bidderFactory'; -import { Renderer } from '../src/Renderer'; -import { BANNER, VIDEO } from '../src/mediaTypes'; +import * as utils from '../src/utils.js'; +import {config} from '../src/config.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import { Renderer } from '../src/Renderer.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; const BIDDER_CODE = 'yieldone'; const ENDPOINT_URL = 'https://y.one.impact-ad.jp/h_bid'; @@ -22,8 +22,9 @@ export const spec = { const params = bidRequest.params; const placementId = params.placementId; const cb = Math.floor(Math.random() * 99999999999); - const referrer = encodeURIComponent(bidderRequest.refererInfo.referer); + const referrer = bidderRequest.refererInfo.referer; const bidId = bidRequest.bidId; + const transactionId = bidRequest.transactionId; const unitCode = bidRequest.adUnitCode; const timeout = config.getConfig('bidderTimeout'); const payload = { @@ -32,6 +33,7 @@ export const spec = { cb: cb, r: referrer, uid: bidId, + tid: transactionId, uc: unitCode, tmax: timeout, t: 'i' diff --git a/modules/yuktamediaAnalyticsAdapter.js b/modules/yuktamediaAnalyticsAdapter.js index e961933d018..b346a26c843 100644 --- a/modules/yuktamediaAnalyticsAdapter.js +++ b/modules/yuktamediaAnalyticsAdapter.js @@ -1,9 +1,8 @@ -import { ajax } from '../src/ajax'; -import adapter from '../src/AnalyticsAdapter'; -import adapterManager from '../src/adapterManager'; +import { ajax } from '../src/ajax.js'; +import adapter from '../src/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; import CONSTANTS from '../src/constants.json'; -import * as url from '../src/url'; -import * as utils from '../src/utils'; +import * as utils from '../src/utils.js'; const emptyUrl = ''; const analyticsType = 'endpoint'; @@ -115,7 +114,7 @@ function send(data, status) { } data.initOptions = initOptions; - let yuktamediaAnalyticsRequestUrl = url.format({ + let yuktamediaAnalyticsRequestUrl = utils.buildUrl({ protocol: 'https', hostname: 'analytics-prebid.yuktamedia.com', pathname: status == 'auctionEnd' ? '/api/bids' : '/api/bid/won', 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/package-lock.json b/package-lock.json old mode 100755 new mode 100644 index d0400d54ff7..2fc53a75352 --- a/package-lock.json +++ b/package-lock.json @@ -1,17277 +1,23892 @@ { - "name": "prebid.js", - "version": "3.1.0-pre", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.5.tgz", - "integrity": "sha512-M42+ScN4+1S9iB6f+TL7QBpoQETxbclx+KNoKJABghnKYE+fMzSGqst0BZJc8CpI625bwPwYgUyRvxZ+0mZzpw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.7.4", - "@babel/helpers": "^7.7.4", - "@babel/parser": "^7.7.5", - "@babel/template": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.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": { - "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 - } - } - }, - "@babel/generator": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.4.tgz", - "integrity": "sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg==", - "dev": true, - "requires": { - "@babel/types": "^7.7.4", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz", - "integrity": "sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og==", - "dev": true, - "requires": { - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz", - "integrity": "sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.7.4", - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-call-delegate": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz", - "integrity": "sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz", - "integrity": "sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A==", - "dev": true, - "requires": { - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.6.0" - } - }, - "@babel/helper-define-map": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz", - "integrity": "sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.7.4", - "@babel/types": "^7.7.4", - "lodash": "^4.17.13" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz", - "integrity": "sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg==", - "dev": true, - "requires": { - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-function-name": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz", - "integrity": "sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.7.4", - "@babel/template": "^7.7.4", - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz", - "integrity": "sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA==", - "dev": true, - "requires": { - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz", - "integrity": "sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ==", - "dev": true, - "requires": { - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz", - "integrity": "sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw==", - "dev": true, - "requires": { - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-module-imports": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz", - "integrity": "sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ==", - "dev": true, - "requires": { - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz", - "integrity": "sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.7.4", - "@babel/helper-simple-access": "^7.7.4", - "@babel/helper-split-export-declaration": "^7.7.4", - "@babel/template": "^7.7.4", - "@babel/types": "^7.7.4", - "lodash": "^4.17.13" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz", - "integrity": "sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg==", - "dev": true, - "requires": { - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==" - }, - "@babel/helper-regex": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", - "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", - "dev": true, - "requires": { - "lodash": "^4.17.13" - } - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz", - "integrity": "sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.7.4", - "@babel/helper-wrap-function": "^7.7.4", - "@babel/template": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-replace-supers": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz", - "integrity": "sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.7.4", - "@babel/helper-optimise-call-expression": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-simple-access": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz", - "integrity": "sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A==", - "dev": true, - "requires": { - "@babel/template": "^7.7.4", - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", - "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", - "dev": true, - "requires": { - "@babel/types": "^7.7.4" - } - }, - "@babel/helper-wrap-function": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz", - "integrity": "sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.7.4", - "@babel/template": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" - } - }, - "@babel/helpers": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.7.4.tgz", - "integrity": "sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg==", - "dev": true, - "requires": { - "@babel/template": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@babel/types": "^7.7.4" - } - }, - "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", - "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==", - "dev": true - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz", - "integrity": "sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.7.4", - "@babel/plugin-syntax-async-generators": "^7.7.4" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz", - "integrity": "sha512-StH+nGAdO6qDB1l8sZ5UBV8AC3F2VW2I8Vfld73TMKyptMU9DY5YsJAS8U81+vEtxcH3Y/La0wG0btDrhpnhjQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.7.4" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz", - "integrity": "sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.7.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.4.tgz", - "integrity": "sha512-rnpnZR3/iWKmiQyJ3LKJpSwLDcX/nSXhdLk4Aq/tXOApIvyu7qoabrige0ylsAJffaUC51WiBu209Q0U+86OWQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.7.4" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz", - "integrity": "sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.7.4" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz", - "integrity": "sha512-cHgqHgYvffluZk85dJ02vloErm3Y6xtH+2noOBOJ2kXOJH3aVCDnj5eR/lVNlTnYu4hndAPJD3rTFjW3qee0PA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz", - "integrity": "sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz", - "integrity": "sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz", - "integrity": "sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz", - "integrity": "sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz", - "integrity": "sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.4.tgz", - "integrity": "sha512-wdsOw0MvkL1UIgiQ/IFr3ETcfv1xb8RMM0H9wbiDyLaJFyiDg5oZvDLCXosIXmFeIlweML5iOBXAkqddkYNizg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz", - "integrity": "sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz", - "integrity": "sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.7.4" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz", - "integrity": "sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz", - "integrity": "sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.13" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz", - "integrity": "sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.7.4", - "@babel/helper-define-map": "^7.7.4", - "@babel/helper-function-name": "^7.7.4", - "@babel/helper-optimise-call-expression": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.7.4", - "@babel/helper-split-export-declaration": "^7.7.4", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz", - "integrity": "sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz", - "integrity": "sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.4.tgz", - "integrity": "sha512-mk0cH1zyMa/XHeb6LOTXTbG7uIJ8Rrjlzu91pUx/KS3JpcgaTDwMS8kM+ar8SLOvlL2Lofi4CGBAjCo3a2x+lw==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz", - "integrity": "sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz", - "integrity": "sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz", - "integrity": "sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz", - "integrity": "sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz", - "integrity": "sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz", - "integrity": "sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.5.tgz", - "integrity": "sha512-CT57FG4A2ZUNU1v+HdvDSDrjNWBrtCmSH6YbbgN3Lrf0Di/q/lWRxZrE72p3+HCCz9UjfZOEBdphgC0nzOS6DQ==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.7.5", - "@babel/helper-plugin-utils": "^7.0.0", - "babel-plugin-dynamic-import-node": "^2.3.0" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz", - "integrity": "sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.7.5", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.7.4", - "babel-plugin-dynamic-import-node": "^2.3.0" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz", - "integrity": "sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0", - "babel-plugin-dynamic-import-node": "^2.3.0" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz", - "integrity": "sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz", - "integrity": "sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.7.4" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz", - "integrity": "sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz", - "integrity": "sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.7.4" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz", - "integrity": "sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw==", - "dev": true, - "requires": { - "@babel/helper-call-delegate": "^7.7.4", - "@babel/helper-get-function-arity": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz", - "integrity": "sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.7.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.5.tgz", - "integrity": "sha512-/8I8tPvX2FkuEyWbjRCt4qTAgZK0DVy8QRguhA524UH48RfGJy94On2ri+dCuwOpcerPRl9O4ebQkRcVzIaGBw==", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.0" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.7.4.tgz", - "integrity": "sha512-OrPiUB5s5XvkCO1lS7D8ZtHcswIC57j62acAnJZKqGGnHP+TIc/ljQSrgdX/QyOTdEK5COAhuc820Hi1q2UgLQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz", - "integrity": "sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz", - "integrity": "sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz", - "integrity": "sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz", - "integrity": "sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz", - "integrity": "sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz", - "integrity": "sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/preset-env": { - "version": "7.7.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.6.tgz", - "integrity": "sha512-k5hO17iF/Q7tR9Jv8PdNBZWYW6RofxhnxKjBMc0nG4JTaWvOTiPoO/RLFwAKcA4FpmuBFm6jkoqaRJLGi0zdaQ==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.7.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.7.4", - "@babel/plugin-proposal-dynamic-import": "^7.7.4", - "@babel/plugin-proposal-json-strings": "^7.7.4", - "@babel/plugin-proposal-object-rest-spread": "^7.7.4", - "@babel/plugin-proposal-optional-catch-binding": "^7.7.4", - "@babel/plugin-proposal-unicode-property-regex": "^7.7.4", - "@babel/plugin-syntax-async-generators": "^7.7.4", - "@babel/plugin-syntax-dynamic-import": "^7.7.4", - "@babel/plugin-syntax-json-strings": "^7.7.4", - "@babel/plugin-syntax-object-rest-spread": "^7.7.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.7.4", - "@babel/plugin-syntax-top-level-await": "^7.7.4", - "@babel/plugin-transform-arrow-functions": "^7.7.4", - "@babel/plugin-transform-async-to-generator": "^7.7.4", - "@babel/plugin-transform-block-scoped-functions": "^7.7.4", - "@babel/plugin-transform-block-scoping": "^7.7.4", - "@babel/plugin-transform-classes": "^7.7.4", - "@babel/plugin-transform-computed-properties": "^7.7.4", - "@babel/plugin-transform-destructuring": "^7.7.4", - "@babel/plugin-transform-dotall-regex": "^7.7.4", - "@babel/plugin-transform-duplicate-keys": "^7.7.4", - "@babel/plugin-transform-exponentiation-operator": "^7.7.4", - "@babel/plugin-transform-for-of": "^7.7.4", - "@babel/plugin-transform-function-name": "^7.7.4", - "@babel/plugin-transform-literals": "^7.7.4", - "@babel/plugin-transform-member-expression-literals": "^7.7.4", - "@babel/plugin-transform-modules-amd": "^7.7.5", - "@babel/plugin-transform-modules-commonjs": "^7.7.5", - "@babel/plugin-transform-modules-systemjs": "^7.7.4", - "@babel/plugin-transform-modules-umd": "^7.7.4", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.7.4", - "@babel/plugin-transform-new-target": "^7.7.4", - "@babel/plugin-transform-object-super": "^7.7.4", - "@babel/plugin-transform-parameters": "^7.7.4", - "@babel/plugin-transform-property-literals": "^7.7.4", - "@babel/plugin-transform-regenerator": "^7.7.5", - "@babel/plugin-transform-reserved-words": "^7.7.4", - "@babel/plugin-transform-shorthand-properties": "^7.7.4", - "@babel/plugin-transform-spread": "^7.7.4", - "@babel/plugin-transform-sticky-regex": "^7.7.4", - "@babel/plugin-transform-template-literals": "^7.7.4", - "@babel/plugin-transform-typeof-symbol": "^7.7.4", - "@babel/plugin-transform-unicode-regex": "^7.7.4", - "@babel/types": "^7.7.4", - "browserslist": "^4.6.0", - "core-js-compat": "^3.4.7", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.5.0" - } - }, - "@babel/template": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", - "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.4", - "@babel/types": "^7.7.4" - } - }, - "@babel/traverse": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.7.4.tgz", - "integrity": "sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.7.4", - "@babel/helper-function-name": "^7.7.4", - "@babel/helper-split-export-declaration": "^7.7.4", - "@babel/parser": "^7.7.4", - "@babel/types": "^7.7.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - }, - "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 - } - } - }, - "@babel/types": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", - "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "@cnakazawa/watch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", - "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, - "@gulp-sourcemaps/identity-map": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", - "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", - "dev": true, - "requires": { - "acorn": "^5.0.3", - "css": "^2.2.1", - "normalize-path": "^2.1.1", - "source-map": "^0.6.0", - "through2": "^2.0.3" - }, - "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" - } - }, - "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-sourcemaps/map-sources": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", - "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", - "dev": true, - "requires": { - "normalize-path": "^2.0.1", - "through2": "^2.0.3" - }, - "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" - } - } - } - }, - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^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/core": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", - "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", - "requires": { - "@jest/console": "^24.7.1", - "@jest/reporters": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-changed-files": "^24.9.0", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-resolve-dependencies": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "jest-watcher": "^24.9.0", - "micromatch": "^3.1.10", - "p-each-series": "^1.0.0", - "realpath-native": "^1.1.0", - "rimraf": "^2.5.4", - "slash": "^2.0.0", - "strip-ansi": "^5.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==" - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "@jest/environment": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", - "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", - "requires": { - "@jest/fake-timers": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "requires": { - "@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==", - "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==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.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/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, - "@jest/test-sequencer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", - "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", - "requires": { - "@jest/test-result": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0" - } - }, - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", - "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^24.9.0", - "babel-plugin-istanbul": "^5.1.0", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.9.0", - "jest-regex-util": "^24.9.0", - "jest-util": "^24.9.0", - "micromatch": "^3.1.10", - "pirates": "^4.0.1", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "2.4.1" - }, - "dependencies": { - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "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==", - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@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 - }, - "@sinonjs/commons": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", - "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/formatio": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", - "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", - "dev": true, - "requires": { - "samsam": "1.3.0" - } - }, - "@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" - } - }, - "@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", - "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz", - "integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.8.tgz", - "integrity": "sha512-yGeB2dHEdvxjP0y4UbRtQaSkXJ9649fYCmIdRoul5kfAoGCwxuCbMhag0k3RPfnuh9kPGm8x89btcfDEXdVWGw==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/crypto-js": { - "version": "3.1.43", - "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-3.1.43.tgz", - "integrity": "sha512-EHe/YKctU3IYNBsDmSOPX/7jLHPRlx8WaiDKSY9JCTnJ8XJeM4c0ZJvx+9Gxmr2s2ihI92R+3U/gNL1sq5oRuQ==" - }, - "@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==" - }, - "@types/istanbul-lib-report": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", - "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@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==", - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "24.0.23", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.23.tgz", - "integrity": "sha512-L7MBvwfNpe7yVPTXLn32df/EK+AMBFAFvZrRuArGs7npEWnlziUXK+5GMIUTI4NIuwok3XibsjXCs5HxviYXjg==", - "requires": { - "jest-diff": "^24.3.0" - } - }, - "@types/node": { - "version": "12.12.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.14.tgz", - "integrity": "sha512-u/SJDyXwuihpwjXy7hOOghagLEV1KdAST6syfnOk6QZAMzZuWZqXy5aYYZbh8Jdpd4escVFP0MvftHNDb9pruA==" - }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==" - }, - "@types/yargs": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", - "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", - "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==" - }, - "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": { - "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==", - "dev": true - }, - "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" - } - }, - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" - }, - "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": { - "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 - } - } - }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", - "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==", - "dev": true - } - } - }, - "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": { - "acorn": "^3.0.4" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } - } - }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==" - }, - "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==", - "dev": true, - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "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" - } - }, - "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=", - "dev": true, - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.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" - } - } - } - }, - "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==", - "requires": { - "ansi-wrap": "^0.1.0" - } - }, - "ansi-cyan": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", - "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", - "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==" - }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "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-red": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", - "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", - "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=" - }, - "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==", - "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=" - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "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=", - "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=", - "requires": { - "buffer-equal": "^1.0.0" - } - }, - "append-transform": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", - "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", - "dev": true, - "requires": { - "default-require-extensions": "^1.0.0" - } - }, - "archiver": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-2.1.1.tgz", - "integrity": "sha1-/2YrSnggFJSj7lRNOjP+dJZQnrw=", - "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" - } - } - } - }, - "archiver-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", - "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", - "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" - }, - "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" - } - } - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.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=" - }, - "arr-filter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", - "requires": { - "make-iterator": "^1.0.0" - } - }, - "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==" - }, - "arr-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", - "requires": { - "make-iterator": "^1.0.0" - } - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, - "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=" - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" - }, - "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.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" - } - }, - "array-initial": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", - "requires": { - "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==" - } - } - }, - "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==", - "requires": { - "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==" - } - } - }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" - }, - "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==", - "requires": { - "default-compare": "^1.0.0", - "get-value": "^2.0.6", - "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==" - } - } - }, - "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=" - }, - "array.prototype.flat": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.2.tgz", - "integrity": "sha512-VXjh7lAL4KXKF2hY4FnEW9eRW6IhdvFW1sN/JwLbmECbCgACCnBHNyP3lFiYuttr0jxRN9Bsc5+G27dMseSWqQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.15.0", - "function-bind": "^1.1.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==", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "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" - } - }, - "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": { - "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" - } - } - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "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 - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" - }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "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==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^2.0.0", - "stream-exhaust": "^1.0.1" - } - }, - "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==" - }, - "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==" - }, - "async-settle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", - "requires": { - "async-done": "^1.2.2" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, - "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=" - }, - "aws4": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", - "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", - "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=", - "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 - } - } - }, - "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-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 - } - } - }, - "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-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" - }, - "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true - } - } - }, - "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" - } - }, - "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=", - "dev": true, - "requires": { - "babel-helper-explode-assignable-expression": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "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" - } - }, - "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=", - "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-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" - } - }, - "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=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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=", - "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" - } - }, - "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=", - "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-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", - "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", - "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" - }, - "dependencies": { - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - } - } - }, - "babel-loader": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", - "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", - "dev": true, - "requires": { - "find-cache-dir": "^2.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1", - "pify": "^4.0.1" - } - }, - "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-runtime": "^6.22.0" - } - }, - "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=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.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==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "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==", - "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==", - "requires": { - "@types/babel__traverse": "^7.0.6" - } - }, - "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=", - "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=", - "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=", - "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": { - "babel-plugin-syntax-dynamic-import": "^6.18.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" - } - }, - "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" - } - }, - "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-syntax-class-constructor-call": "^6.18.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "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-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-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=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" - } - }, - "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-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": { - "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.22.0", - "babel-template": "^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=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "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": { - "babel-runtime": "^6.22.0", - "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=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "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": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "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=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "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" - } - }, - "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" - } - }, - "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": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "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" - } - }, - "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" - } - }, - "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, - "requires": { - "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" - } - }, - "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": { - "babel-runtime": "^6.22.0", - "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": { - "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" - } - }, - "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-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": { - "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": { - "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=", - "dev": true, - "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" - } - }, - "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" - } - } - } - }, - "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=", - "dev": true, - "requires": { - "babel-plugin-syntax-export-extensions": "^6.8.0", - "babel-runtime": "^6.22.0" - } - }, - "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": { - "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=", - "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" - } - }, - "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": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" - } - }, - "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": { - "babel-runtime": "^6.22.0" - } - }, - "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-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-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-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": { - "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-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": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "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": { - "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-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": { - "babel-plugin-transform-flow-strip-types": "^6.22.0" - } - }, - "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==", - "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" - } - }, - "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": { - "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": { - "babel-plugin-transform-do-expressions": "^6.22.0", - "babel-plugin-transform-function-bind": "^6.22.0", - "babel-preset-stage-1": "^6.24.1" - } - }, - "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" - } - }, - "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" - } - }, - "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": { - "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-register": { - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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": { - "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": { - "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-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": { - "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 - } - } - }, - "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=", - "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" - } - }, - "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.4", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.4.tgz", - "integrity": "sha512-S8vuDB4w6YpRhICUDET3guPlQpaJl7od94tpZ0Fvnyp+MKW/HyDTcRDck+29C9g+d/qQHnddRH3+94kZdrW0Ww==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "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=", - "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==", - "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==", - "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==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "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=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "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=", - "dev": true, - "requires": { - "callsite": "1.0.0" - } - }, - "bfj": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", - "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "check-types": "^8.0.3", - "hoopy": "^0.1.4", - "tryer": "^1.0.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 - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" - }, - "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 - }, - "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", - "dev": true, - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.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 - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "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 - }, - "body": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", - "dev": true, - "requires": { - "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 - } - } - }, - "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": { - "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" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "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=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browser-process-hrtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", - "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==" - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "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=" - } - } - }, - "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, - "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" - } - }, - "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": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.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==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "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": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "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" - } - }, - "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": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz", - "integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001015", - "electron-to-chromium": "^1.3.322", - "node-releases": "^1.1.42" - } - }, - "browserstack": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz", - "integrity": "sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==", - "dev": true, - "requires": { - "https-proxy-agent": "^2.2.1" - } - }, - "browserstack-local": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.4.2.tgz", - "integrity": "sha512-fRaynjF0MvtyyfPRy2NFnVwxLyNtD28K/v9xRsIjUVf7xLc80NIm7Nfr3KXlFmWizhG91PL/UAOXlHkoxQjaNw==", - "dev": true, - "requires": { - "https-proxy-agent": "^2.2.1", - "is-running": "^2.0.0", - "ps-tree": "=1.1.1", - "temp-fs": "^0.9.9" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", - "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", - "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==", - "dev": true, - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "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=" - }, - "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==" - }, - "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 - }, - "build": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/build/-/build-0.1.4.tgz", - "integrity": "sha1-cH/gJv/O3crL/c3zVur9pk8VEEY=", - "requires": { - "cssmin": "0.3.x", - "jsmin": "1.x", - "jxLoader": "*", - "moo-server": "*", - "promised-io": "*", - "timespan": "2.x", - "uglify-js": "1.x", - "walker": "1.x", - "winston": "*", - "wrench": "1.3.x" - }, - "dependencies": { - "uglify-js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.3.5.tgz", - "integrity": "sha1-S1v/+Rhu/7qoiOTJ6UvZ/EyUkp0=" - } - } - }, - "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==" - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "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" - } - }, - "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 - }, - "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=", - "dev": true - }, - "query-string": { - "version": "5.1.1", - "resolved": "http://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=", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - } - } - }, - "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": { - "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 - } - } - }, - "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==" - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "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": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - } - } - }, - "caniuse-lite": { - "version": "1.0.30001015", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz", - "integrity": "sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ==", - "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==", - "requires": { - "rsvp": "^4.8.4" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "ccount": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.4.tgz", - "integrity": "sha512-fpZ81yYfzentuieinmGnphk0pLkOTMm6MZdVqwd77ROvhko6iujLNGrHH5E7utq3ygWklwfmwuG+A7P+NpqT6w==", - "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" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "character-entities": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.3.tgz", - "integrity": "sha512-yB4oYSAa9yLcGyTbB4ItFwHw43QHdH129IJ5R+WvxOkWlyFnR5FAaBNnUq4mcxsTVZGh28bHoeTHMKXH1wZf3w==", - "dev": true - }, - "character-entities-html4": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.3.tgz", - "integrity": "sha512-SwnyZ7jQBCRHELk9zf2CN5AnGEc2nA+uKMZLHvcqhpPprjkYhiLn0DywMHgN5ttFZuITMATbh68M6VIVKwJbcg==", - "dev": true - }, - "character-entities-legacy": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.3.tgz", - "integrity": "sha512-YAxUpPoPwxYFsslbdKkhrGnXAtXoHNgYjlBM3WMXkWGTl5RsY3QmOyhwAgL8Nxm9l5LBThXGawxKPn68y6/fww==", - "dev": true - }, - "character-reference-invalid": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.3.tgz", - "integrity": "sha512-VOq6PRzQBam/8Jm6XBGk2fNEnHXAdGd6go0rtd4weAGECBamHDwwCQSOT12TACIYUZegUXnV6xBXqUssijtxIg==", - "dev": true - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "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": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "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" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - }, - "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": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "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==", - "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=", - "requires": { - "is-descriptor": "^0.1.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=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "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==" - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" - }, - "clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=" - }, - "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": { - "mimic-response": "^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=" - }, - "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==", - "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "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=" - }, - "collapse-white-space": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.5.tgz", - "integrity": "sha512-703bOOmytCYAX9cXYqoikYIx6twmFCXsnzRQheBcTG3nzKYBR4P/+wkYeH+Mvj7qUz8zZDtdyzbxfnEi/kYzRQ==", - "dev": true - }, - "collection-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", - "requires": { - "arr-map": "^2.0.2", - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" - } - }, - "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==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "color-string": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", - "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "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==" - }, - "colornames": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", - "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" - }, - "colorspace": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", - "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", - "requires": { - "color": "3.0.x", - "text-hex": "1.0.x" - } - }, - "combine-lists": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", - "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", - "dev": true, - "requires": { - "lodash": "^4.5.0" - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "comma-separated-tokens": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.7.tgz", - "integrity": "sha512-Jrx3xsP4pPv4AwJUDWY9wOXGtwPXARej6Xd99h4TUGotmf8APuquKMpK+dnD3UgyxK7OEWaisjZz+3b5jtL6xQ==", - "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==" - }, - "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==" - }, - "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": "1.2.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz", - "integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=", - "dev": true, - "requires": { - "buffer-crc32": "^0.2.1", - "crc32-stream": "^2.0.0", - "normalize-path": "^2.0.0", - "readable-stream": "^2.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=", - "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=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "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==", - "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==" - } - } - }, - "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==", - "dev": true - }, - "console-browserify": { - "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==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "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==", - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "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=" - }, - "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==", - "requires": { - "each-props": "^1.3.0", - "is-plain-object": "^2.0.1" - } - }, - "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==" - }, - "core-js-compat": { - "version": "3.4.8", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.4.8.tgz", - "integrity": "sha512-l3WTmnXHV2Sfu5VuD7EHE2w7y+K68+kULKt5RJg8ZJk3YhHF1qLD4O8v8AmNq+8vbOwnPFFDvds25/AoEvMqlQ==", - "dev": true, - "requires": { - "browserslist": "^4.8.2", - "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==", - "dev": true - } - } - }, - "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=" - }, - "coveralls": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.9.tgz", - "integrity": "sha512-nNBg3B1+4iDox5A5zqHKzUTiwl2ey4k2o0NEcVZYvl+GOSJdKBj4AJGKLv6h3SvWch7tABHePAQOSZWM9E2hMg==", - "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" - } - }, - "crc": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "dev": true, - "requires": { - "buffer": "^5.1.0" - } - }, - "crc32-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", - "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", - "dev": true, - "requires": { - "crc": "^3.4.4", - "readable-stream": "^2.0.0" - } - }, - "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": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "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": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "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": { - "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" - } - }, - "criteo-direct-rsa-validate": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/criteo-direct-rsa-validate/-/criteo-direct-rsa-validate-1.0.0.tgz", - "integrity": "sha512-BMstd/uhDJVd1zugn34VXlEcGl/ftN3cLS3ljudp/fWr3lq+ym6fUfXm3ru5c0G+rbio+7YFv7fkWjcK9A8z2w==", - "requires": { - "@types/crypto-js": "^3.1.43", - "@types/jest": "^24.0.23", - "@types/node": "^12.12.14", - "build": "^0.1.4", - "crypto-js": "^3.1.9-1", - "gulp": "^4.0.2", - "gulp-clean": "^0.4.0", - "gulp-concat": "^2.6.1", - "gulp-rename": "^1.4.0", - "gulp-typescript": "^6.0.0-alpha.1", - "gulp-uglify": "^3.0.2", - "jest": "^24.9.0", - "through2": "3.0.1", - "ts-jest": "^24.1.0", - "typescript": "^3.7.2" - }, - "dependencies": { - "arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", - "requires": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - } - }, - "arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=" - }, - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=" - }, - "extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", - "requires": { - "kind-of": "^1.1.0" - } - }, - "gulp-clean": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/gulp-clean/-/gulp-clean-0.4.0.tgz", - "integrity": "sha512-DARK8rNMo4lHOFLGTiHEJdf19GuoBDHqGUaypz+fOhrvOs3iFO7ntdYtdpNxv+AzSJBx/JfypF0yEj9ks1IStQ==", - "requires": { - "fancy-log": "^1.3.2", - "plugin-error": "^0.1.2", - "rimraf": "^2.6.2", - "through2": "^2.0.3", - "vinyl": "^2.1.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=" - }, - "plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", - "requires": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - } - }, - "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", - "requires": { - "readable-stream": "2 || 3" - } - } - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "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": { - "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" - } - }, - "crypto-js": { - "version": "3.1.9-1", - "resolved": "http://build-nexus.crto.in/repository/npm/crypto-js/-/crypto-js-3.1.9-1.tgz", - "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" - }, - "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": { - "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 - } - } - }, - "css-parse": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", - "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", - "dev": true, - "requires": { - "css": "^2.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 - }, - "cssmin": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/cssmin/-/cssmin-0.3.2.tgz", - "integrity": "sha1-3c5MVHtRCuDVlKjx+/iq+OLFwA0=" - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" - }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", - "requires": { - "cssom": "0.3.x" - } - }, - "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": { - "array-find-index": "^1.0.1" - } - }, - "custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", - "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==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "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==", - "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.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==", - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "date-format": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", - "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=", - "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": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" - } - }, - "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": { - "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 - } - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "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=" - }, - "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" - } - }, - "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": { - "type-detect": "^4.0.0" - } - }, - "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==", - "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" - } - }, - "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=" - }, - "deepmerge": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.0.1.tgz", - "integrity": "sha512-VIPwiMJqJ13ZQfaCsIFnp5Me9tnjURiaIFxfz7EH0Ci0dTSQpZtSLrqOicXqEd/z2r+z+Klk9GzmnRsgpgbOsQ==", - "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==", - "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==" - } - } - }, - "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" - }, - "dependencies": { - "strip-bom": { - "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" - } - } - } - }, - "default-resolution": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=" - }, - "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==", - "requires": { - "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==", - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.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==", - "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==", - "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==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "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=" - }, - "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": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "detab": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.2.tgz", - "integrity": "sha512-Q57yPrxScy816TTE1P/uLRXLDKjXhvYTbfxS/e6lPD+YrqghbsMlGB9nQzj/zVtSPaF0DFPSdO916EWO4sQUyQ==", - "dev": true, - "requires": { - "repeat-string": "^1.5.4" - } - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" - }, - "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": { - "repeating": "^2.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=" - }, - "detective": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", - "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", - "dev": true, - "requires": { - "acorn": "^5.2.1", - "defined": "^1.0.0" - } - }, - "di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", - "dev": true - }, - "diagnostics": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", - "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", - "requires": { - "colorspace": "1.1.x", - "enabled": "1.0.x", - "kuler": "1.0.x" - } - }, - "diff": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", - "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", - "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==" - }, - "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": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "disparity": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/disparity/-/disparity-2.0.0.tgz", - "integrity": "sha1-V92stHMkrl9Y0swNqIbbTOnutxg=", - "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 - } - } - }, - "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=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "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": { - "esutils": "^2.0.2", - "isarray": "^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==", - "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" - }, - "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==", - "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" - }, - "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" - } + "name": "prebid.js", + "version": "3.24.0-pre", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.1" + } + }, + "@babel/compat-data": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.10.1.tgz", + "integrity": "sha512-CHvCj7So7iCkGKPRFUfryXIkU2gSBw7VSZFYLsqVhrS47269VK2Hfi9S/YcublPMW8k1u2bQBlbDruoQEm4fgw==", + "dev": true, + "requires": { + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "semver": "^5.5.0" + } + }, + "@babel/core": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.2.tgz", + "integrity": "sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.1", + "@babel/generator": "^7.10.2", + "@babel/helper-module-transforms": "^7.10.1", + "@babel/helpers": "^7.10.1", + "@babel/parser": "^7.10.2", + "@babel/template": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.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": { + "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 } - }, - "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": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, - "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 - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "requires": { - "webidl-conversions": "^4.0.2" - } - }, - "dset": { - "version": "2.0.1", - "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 - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "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==", - "requires": { - "is-plain-object": "^2.0.1", - "object.defaults": "^1.1.0" + } + }, + "@babel/generator": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.2.tgz", + "integrity": "sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.2", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.1.tgz", + "integrity": "sha512-ewp3rvJEwLaHgyWGe4wQssC2vjks3E80WiUe2BpMb0KhreTjMROCbxXcEovTrbeGVdQct5VjQfrv9EgC+xMzCw==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.1.tgz", + "integrity": "sha512-cQpVq48EkYxUU0xozpGCLla3wlkdRRqLWu1ksFMXA9CM5KQmyyRpSEsYXbao7JUkOw/tAaYKCaYyZq6HOFYtyw==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.2.tgz", + "integrity": "sha512-hYgOhF4To2UTB4LTaZepN/4Pl9LD4gfbJx8A34mqoluT8TLbof1mhUlYuNWTEebONa8+UlCC4X0TEXu7AOUyGA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.10.1", + "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.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.2.tgz", + "integrity": "sha512-5C/QhkGFh1vqcziq1vAL6SI9ymzUp8BCYjFpvYVhWP4DlATIb3u5q3iUd35mvlyGs8fO7hckkW7i0tmH+5+bvQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.1", + "@babel/helper-member-expression-to-functions": "^7.10.1", + "@babel/helper-optimise-call-expression": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/helper-replace-supers": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.1.tgz", + "integrity": "sha512-Rx4rHS0pVuJn5pJOqaqcZR4XSgeF9G/pO/79t+4r7380tXFJdzImFnxMU19f83wjSrmKHq6myrM10pFHTGzkUA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.1", + "@babel/helper-regex": "^7.10.1", + "regexpu-core": "^4.7.0" + } + }, + "@babel/helper-define-map": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.1.tgz", + "integrity": "sha512-+5odWpX+OnvkD0Zmq7panrMuAGQBu6aPUgvMzuMGo4R+jUOvealEj2hiqI6WhxgKrTpFoFj0+VdsuA8KDxHBDg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.1", + "@babel/types": "^7.10.1", + "lodash": "^4.17.13" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.1.tgz", + "integrity": "sha512-vcUJ3cDjLjvkKzt6rHrl767FeE7pMEYfPanq5L16GRtrXIoznc0HykNW2aEYkcnP76P0isoqJ34dDMFZwzEpJg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-function-name": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz", + "integrity": "sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz", + "integrity": "sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.1.tgz", + "integrity": "sha512-vLm5srkU8rI6X3+aQ1rQJyfjvCBLXP8cAGeuw04zeAM2ItKb1e7pmVmLyHb4sDaAYnLL13RHOZPLEtcGZ5xvjg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.1.tgz", + "integrity": "sha512-u7XLXeM2n50gb6PWJ9hoO5oO7JFPaZtrh35t8RqKLT1jFKj9IWeD1zrcrYp1q1qiZTdEarfDWfTIP8nGsu0h5g==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-module-imports": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz", + "integrity": "sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-module-transforms": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz", + "integrity": "sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.1", + "@babel/helper-replace-supers": "^7.10.1", + "@babel/helper-simple-access": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1", + "lodash": "^4.17.13" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.1.tgz", + "integrity": "sha512-a0DjNS1prnBsoKx83dP2falChcs7p3i8VMzdrSbfLhuQra/2ENC4sbri34dz/rWmDADsmF1q5GbfaXydh0Jbjg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz", + "integrity": "sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.1.tgz", + "integrity": "sha512-7isHr19RsIJWWLLFn21ubFt223PjQyg1HY7CZEMRr820HttHPpVvrsIN3bUOo44DEfFV4kBXO7Abbn9KTUZV7g==", + "dev": true, + "requires": { + "lodash": "^4.17.13" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.1.tgz", + "integrity": "sha512-RfX1P8HqsfgmJ6CwaXGKMAqbYdlleqglvVtht0HGPMSsy2V6MqLlOJVF/0Qyb/m2ZCi2z3q3+s6Pv7R/dQuZ6A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.1", + "@babel/helper-wrap-function": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-replace-supers": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz", + "integrity": "sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.10.1", + "@babel/helper-optimise-call-expression": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-simple-access": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz", + "integrity": "sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw==", + "dev": true, + "requires": { + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz", + "integrity": "sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==", + "dev": true, + "requires": { + "@babel/types": "^7.10.1" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.1.tgz", + "integrity": "sha512-C0MzRGteVDn+H32/ZgbAv5r56f2o1fZSA/rj/TYo8JEJNHg+9BdSmKBUND0shxWRztWhjlT2cvHYuynpPsVJwQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/helpers": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.1.tgz", + "integrity": "sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw==", + "dev": true, + "requires": { + "@babel/template": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", + "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.1.tgz", + "integrity": "sha512-vzZE12ZTdB336POZjmpblWfNNRpMSua45EYnRigE2XsZxcXcIyly2ixnTJasJE4Zq3U7t2d8rRF7XRUuzHxbOw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/helper-remap-async-to-generator": "^7.10.1", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.1.tgz", + "integrity": "sha512-sqdGWgoXlnOdgMXU+9MbhzwFRgxVLeiGBqTrnuS7LC2IBU31wSsESbTUreT2O418obpfPdGUR2GbEufZF1bpqw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.1.tgz", + "integrity": "sha512-Cpc2yUVHTEGPlmiQzXj026kqwjEQAD9I4ZC16uzdbgWgitg/UHKHLffKNCQZ5+y8jpIZPJcKcwsr2HwPh+w3XA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.1.tgz", + "integrity": "sha512-m8r5BmV+ZLpWPtMY2mOKN7wre6HIO4gfIiV+eOmsnZABNenrt/kzYBwrh+KOfgumSWpnlGs5F70J8afYMSJMBg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.1.tgz", + "integrity": "sha512-56cI/uHYgL2C8HVuHOuvVowihhX0sxb3nnfVRzUeVHTWmRHTZrKuAh/OBIMggGU/S1g/1D2CRCXqP+3u7vX7iA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.1.tgz", + "integrity": "sha512-jjfym4N9HtCiNfyyLAVD8WqPYeHUrw4ihxuAynWj6zzp2gf9Ey2f7ImhFm6ikB3CLf5Z/zmcJDri6B4+9j9RsA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/plugin-syntax-numeric-separator": "^7.10.1" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.1.tgz", + "integrity": "sha512-Z+Qri55KiQkHh7Fc4BW6o+QBuTagbOp9txE+4U1i79u9oWlf2npkiDx+Rf3iK3lbcHBuNy9UOkwuR5wOMH3LIQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.10.1" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.1.tgz", + "integrity": "sha512-VqExgeE62YBqI3ogkGoOJp1R6u12DFZjqwJhqtKc2o5m1YTUuUWnos7bZQFBhwkxIFpWYJ7uB75U7VAPPiKETA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.1.tgz", + "integrity": "sha512-dqQj475q8+/avvok72CF3AOSV/SGEcH29zT5hhohqqvvZ2+boQoOr7iGldBG5YXTO2qgCgc2B3WvVLUdbeMlGA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.1.tgz", + "integrity": "sha512-RZecFFJjDiQ2z6maFprLgrdnm0OzoC23Mx89xf1CcEsxmHuzuXOdniEuI+S3v7vjQG4F5sa6YtUp+19sZuSxHg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.1.tgz", + "integrity": "sha512-JjfngYRvwmPwmnbRZyNiPFI8zxCZb8euzbCG/LxyKdeTb59tVciKo9GK9bi6JYKInk1H11Dq9j/zRqIH4KigfQ==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.1.tgz", + "integrity": "sha512-Gf2Yx/iRs1JREDtVZ56OrjjgFHCaldpTnuy9BHla10qyVT3YkIIGEtoDWhyop0ksu1GvNjHIoYRBqm3zoR1jyQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@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", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.1.tgz", + "integrity": "sha512-uTd0OsHrpe3tH5gRPTxG8Voh99/WCU78vIm5NMRYPAqC8lR4vajt6KkCAknCHrx24vkPdd/05yfdGSB4EIY2mg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@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", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.1.tgz", + "integrity": "sha512-hgA5RYkmZm8FTFT3yu2N9Bx7yVVOKYT6yEdXXo6j2JTm0wNxgqaGeQVaSHRjhfnQbX91DtjFB6McRFSlcJH3xQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.1.tgz", + "integrity": "sha512-6AZHgFJKP3DJX0eCNJj01RpytUa3SOGawIxweHkNX2L6PYikOZmoh5B0d7hIHaIgveMjX990IAa/xK7jRTN8OA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.1.tgz", + "integrity": "sha512-XCgYjJ8TY2slj6SReBUyamJn3k2JLUIiiR5b6t1mNCMSvv7yx+jJpaewakikp0uWFQSF7ChPPoe3dHmXLpISkg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/helper-remap-async-to-generator": "^7.10.1" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.1.tgz", + "integrity": "sha512-B7K15Xp8lv0sOJrdVAoukKlxP9N59HS48V1J3U/JGj+Ad+MHq+am6xJVs85AgXrQn4LV8vaYFOB+pr/yIuzW8Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.1.tgz", + "integrity": "sha512-8bpWG6TtF5akdhIm/uWTyjHqENpy13Fx8chg7pFH875aNLwX8JxIxqm08gmAT+Whe6AOmaTeLPe7dpLbXt+xUw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "lodash": "^4.17.13" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.1.tgz", + "integrity": "sha512-P9V0YIh+ln/B3RStPoXpEQ/CoAxQIhRSUn7aXqQ+FZJ2u8+oCtjIXR3+X0vsSD8zv+mb56K7wZW1XiDTDGiDRQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.1", + "@babel/helper-define-map": "^7.10.1", + "@babel/helper-function-name": "^7.10.1", + "@babel/helper-optimise-call-expression": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/helper-replace-supers": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.1.tgz", + "integrity": "sha512-mqSrGjp3IefMsXIenBfGcPXxJxweQe2hEIwMQvjtiDQ9b1IBvDUjkAtV/HMXX47/vXf14qDNedXsIiNd1FmkaQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.1.tgz", + "integrity": "sha512-V/nUc4yGWG71OhaTH705pU8ZSdM6c1KmmLP8ys59oOYbT7RpMYAR3MsVOt6OHL0WzG7BlTU076va9fjJyYzJMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.1.tgz", + "integrity": "sha512-19VIMsD1dp02RvduFUmfzj8uknaO3uiHHF0s3E1OHnVsNj8oge8EQ5RzHRbJjGSetRnkEuBYO7TG1M5kKjGLOA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.1.tgz", + "integrity": "sha512-wIEpkX4QvX8Mo9W6XF3EdGttrIPZWozHfEaDTU0WJD/TDnXMvdDh30mzUl/9qWhnf7naicYartcEfUghTCSNpA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.1.tgz", + "integrity": "sha512-lr/przdAbpEA2BUzRvjXdEDLrArGRRPwbaF9rvayuHRvdQ7lUTTkZnhZrJ4LE2jvgMRFF4f0YuPQ20vhiPYxtA==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.1.tgz", + "integrity": "sha512-US8KCuxfQcn0LwSCMWMma8M2R5mAjJGsmoCBVwlMygvmDUMkTCykc84IqN1M7t+agSfOmLYTInLCHJM+RUoz+w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.1.tgz", + "integrity": "sha512-//bsKsKFBJfGd65qSNNh1exBy5Y9gD9ZN+DvrJ8f7HXr4avE5POW6zB7Rj6VnqHV33+0vXWUwJT0wSHubiAQkw==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.1.tgz", + "integrity": "sha512-qi0+5qgevz1NHLZroObRm5A+8JJtibb7vdcPQF1KQE12+Y/xxl8coJ+TpPW9iRq+Mhw/NKLjm+5SHtAHCC7lAw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.1.tgz", + "integrity": "sha512-UmaWhDokOFT2GcgU6MkHC11i0NQcL63iqeufXWfRy6pUOGYeCGEKhvfFO6Vz70UfYJYHwveg62GS83Rvpxn+NA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.1.tgz", + "integrity": "sha512-31+hnWSFRI4/ACFr1qkboBbrTxoBIzj7qA69qlq8HY8p7+YCzkCT6/TvQ1a4B0z27VeWtAeJd6pr5G04dc1iHw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.1.tgz", + "integrity": "sha512-AQG4fc3KOah0vdITwt7Gi6hD9BtQP/8bhem7OjbaMoRNCH5Djx42O2vYMfau7QnAzQCa+RJnhJBmFFMGpQEzrg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/helper-simple-access": "^7.10.1", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.1.tgz", + "integrity": "sha512-ewNKcj1TQZDL3YnO85qh9zo1YF1CHgmSTlRQgHqe63oTrMI85cthKtZjAiZSsSNjPQ5NCaYo5QkbYqEw1ZBgZA==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.10.1", + "@babel/helper-module-transforms": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.1.tgz", + "integrity": "sha512-EIuiRNMd6GB6ulcYlETnYYfgv4AxqrswghmBRQbWLHZxN4s7mupxzglnHqk9ZiUpDI4eRWewedJJNj67PWOXKA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.1.tgz", + "integrity": "sha512-MBlzPc1nJvbmO9rPr1fQwXOM2iGut+JC92ku6PbiJMMK7SnQc1rytgpopveE3Evn47gzvGYeCdgfCDbZo0ecUw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.1.tgz", + "integrity": "sha512-WnnStUDN5GL+wGQrJylrnnVlFhFmeArINIR9gjhSeYyvroGhBrSAXYg/RHsnfzmsa+onJrTJrEClPzgNmmQ4Gw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/helper-replace-supers": "^7.10.1" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.1.tgz", + "integrity": "sha512-tJ1T0n6g4dXMsL45YsSzzSDZCxiHXAQp/qHrucOq5gEHncTA3xDxnd5+sZcoQp+N1ZbieAaB8r/VUCG0gqseOg==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.1.tgz", + "integrity": "sha512-Kr6+mgag8auNrgEpbfIWzdXYOvqDHZOF0+Bx2xh4H2EDNwcbRb9lY6nkZg8oSjsX+DH9Ebxm9hOqtKW+gRDeNA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.1.tgz", + "integrity": "sha512-B3+Y2prScgJ2Bh/2l9LJxKbb8C8kRfsG4AdPT+n7ixBHIxJaIG8bi8tgjxUMege1+WqSJ+7gu1YeoMVO3gPWzw==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.1.tgz", + "integrity": "sha512-qN1OMoE2nuqSPmpTqEM7OvJ1FkMEV+BjVeZZm9V9mq/x1JLKQ4pcv8riZJMNN3u2AUGl0ouOMjRr2siecvHqUQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.1.tgz", + "integrity": "sha512-AR0E/lZMfLstScFwztApGeyTHJ5u3JUKMjneqRItWeEqDdHWZwAOKycvQNCasCK/3r5YXsuNG25funcJDu7Y2g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.1.tgz", + "integrity": "sha512-8wTPym6edIrClW8FI2IoaePB91ETOtg36dOkj3bYcNe7aDMN2FXEoUa+WrmPc4xa1u2PQK46fUX2aCb+zo9rfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.1.tgz", + "integrity": "sha512-j17ojftKjrL7ufX8ajKvwRilwqTok4q+BjkknmQw9VNHnItTyMP5anPFzxFJdCQs7clLcWpCV3ma+6qZWLnGMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/helper-regex": "^7.10.1" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.1.tgz", + "integrity": "sha512-t7B/3MQf5M1T9hPCRG28DNGZUuxAuDqLYS03rJrIk2prj/UV7Z6FOneijhQhnv/Xa039vidXeVbvjK2SK5f7Gg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.1.tgz", + "integrity": "sha512-qX8KZcmbvA23zDi+lk9s6hC1FM7jgLHYIjuLgULgc8QtYnmB3tAVIYkNoKRQ75qWBeyzcoMoK8ZQmogGtC/w0g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.1.tgz", + "integrity": "sha512-zZ0Poh/yy1d4jeDWpx/mNwbKJVwUYJX73q+gyh4bwtG0/iUlzdEu0sLMda8yuDFS6LBQlT/ST1SJAR6zYwXWgw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.1.tgz", + "integrity": "sha512-Y/2a2W299k0VIUdbqYm9X2qS6fE0CUBhhiPpimK6byy7OJ/kORLlIX+J6UrjgNu5awvs62k+6RSslxhcvVw2Tw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1" + } + }, + "@babel/preset-env": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.10.2.tgz", + "integrity": "sha512-MjqhX0RZaEgK/KueRzh+3yPSk30oqDKJ5HP5tqTSB1e2gzGS3PLy7K0BIpnp78+0anFuSwOeuCf1zZO7RzRvEA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.10.1", + "@babel/helper-compilation-targets": "^7.10.2", + "@babel/helper-module-imports": "^7.10.1", + "@babel/helper-plugin-utils": "^7.10.1", + "@babel/plugin-proposal-async-generator-functions": "^7.10.1", + "@babel/plugin-proposal-class-properties": "^7.10.1", + "@babel/plugin-proposal-dynamic-import": "^7.10.1", + "@babel/plugin-proposal-json-strings": "^7.10.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.1", + "@babel/plugin-proposal-numeric-separator": "^7.10.1", + "@babel/plugin-proposal-object-rest-spread": "^7.10.1", + "@babel/plugin-proposal-optional-catch-binding": "^7.10.1", + "@babel/plugin-proposal-optional-chaining": "^7.10.1", + "@babel/plugin-proposal-private-methods": "^7.10.1", + "@babel/plugin-proposal-unicode-property-regex": "^7.10.1", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.10.1", + "@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.1", + "@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.10.1", + "@babel/plugin-transform-arrow-functions": "^7.10.1", + "@babel/plugin-transform-async-to-generator": "^7.10.1", + "@babel/plugin-transform-block-scoped-functions": "^7.10.1", + "@babel/plugin-transform-block-scoping": "^7.10.1", + "@babel/plugin-transform-classes": "^7.10.1", + "@babel/plugin-transform-computed-properties": "^7.10.1", + "@babel/plugin-transform-destructuring": "^7.10.1", + "@babel/plugin-transform-dotall-regex": "^7.10.1", + "@babel/plugin-transform-duplicate-keys": "^7.10.1", + "@babel/plugin-transform-exponentiation-operator": "^7.10.1", + "@babel/plugin-transform-for-of": "^7.10.1", + "@babel/plugin-transform-function-name": "^7.10.1", + "@babel/plugin-transform-literals": "^7.10.1", + "@babel/plugin-transform-member-expression-literals": "^7.10.1", + "@babel/plugin-transform-modules-amd": "^7.10.1", + "@babel/plugin-transform-modules-commonjs": "^7.10.1", + "@babel/plugin-transform-modules-systemjs": "^7.10.1", + "@babel/plugin-transform-modules-umd": "^7.10.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.10.1", + "@babel/plugin-transform-object-super": "^7.10.1", + "@babel/plugin-transform-parameters": "^7.10.1", + "@babel/plugin-transform-property-literals": "^7.10.1", + "@babel/plugin-transform-regenerator": "^7.10.1", + "@babel/plugin-transform-reserved-words": "^7.10.1", + "@babel/plugin-transform-shorthand-properties": "^7.10.1", + "@babel/plugin-transform-spread": "^7.10.1", + "@babel/plugin-transform-sticky-regex": "^7.10.1", + "@babel/plugin-transform-template-literals": "^7.10.1", + "@babel/plugin-transform-typeof-symbol": "^7.10.1", + "@babel/plugin-transform-unicode-escapes": "^7.10.1", + "@babel/plugin-transform-unicode-regex": "^7.10.1", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.10.2", + "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.10.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.2.tgz", + "integrity": "sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg==", + "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==", + "dev": true } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + } + }, + "@babel/template": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", + "integrity": "sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.1", + "@babel/parser": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "@babel/traverse": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.1.tgz", + "integrity": "sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.1", + "@babel/generator": "^7.10.1", + "@babel/helper-function-name": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1", + "@babel/parser": "^7.10.1", + "@babel/types": "^7.10.1", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "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 } - }, - "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 - }, - "electron-to-chromium": { - "version": "1.3.322", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", - "integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==", - "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==", - "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" + } + }, + "@babel/types": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.2.tgz", + "integrity": "sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.1", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@gulp-sourcemaps/identity-map": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", + "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", + "dev": true, + "requires": { + "acorn": "^5.0.3", + "css": "^2.2.1", + "normalize-path": "^2.1.1", + "source-map": "^0.6.0", + "through2": "^2.0.3" + }, + "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" + } + }, + "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 } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "enabled": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", - "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", - "requires": { - "env-variable": "0.0.x" + } + }, + "@gulp-sourcemaps/map-sources": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", + "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", + "dev": true, + "requires": { + "normalize-path": "^2.0.1", + "through2": "^2.0.3" + }, + "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" + } } - }, - "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==", - "requires": { - "once": "^1.4.0" + } + }, + "@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", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "dev": true, + "requires": { + "@jest/source-map": "^24.9.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true } - }, - "engine.io": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", - "integrity": "sha1-tgKBw1SEpw7gNR6g6/+D7IyVIqI=", - "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": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "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" - } + } + }, + "@jest/core": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "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" } - } - }, - "engine.io-client": { - "version": "3.2.1", - "resolved": "http://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", - "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", - "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" - }, - "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": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "dev": true, - "requires": { - "ms": "2.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" + } } - }, - "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" + } + }, + "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" + } } } - } - }, - "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": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.5", - "has-binary2": "~1.0.2" - } - }, - "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": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "object-assign": "^4.0.1", - "tapable": "^0.2.7" - } - }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", - "dev": true - }, - "env-variable": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", - "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" - }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, - "requires": { - "prr": "~1.0.1" - } - }, - "error": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", - "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", - "dev": true, - "requires": { - "string-template": "~0.2.1" - } - }, - "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==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.3.tgz", - "integrity": "sha512-WtY7Fx5LiOnSYgF5eg/1T+GONaGmpvpPdCpSnYij+U2gDTL0UPfWrhDw7b2IYb+9NQJsYpCA0wOQvZfsd6YwRw==", - "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.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.1.0", - "string.prototype.trimright": "^2.1.0" - } - }, - "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==", - "dev": true, - "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": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es5-shim": { - "version": "4.5.13", - "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.13.tgz", - "integrity": "sha512-xi6hh6gsvDE0MaW4Vp1lgNEBpVcCXRWfPXj5egDvtgLz4L9MEvNwYEMdJH+JJinWkwa8c3c3o5HduV7dB/e1Hw==", - "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=", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "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 - }, - "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, - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - }, - "dependencies": { - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" + }, + "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" + } } } - } - }, - "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==", - "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==", - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "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=" - }, - "escodegen": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", - "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", - "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true + }, + "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 + }, + "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" + } + }, + "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" } } - }, - "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" + } + }, + "@jest/environment": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "dev": true, + "requires": { + "@jest/fake-timers": "^24.9.0", + "@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": "*" + } } - }, - "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-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": 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, - "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" + } + }, + "@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-message-util": "^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": "*" + } + }, + "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" + } } - }, - "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" + } + }, + "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" + } } - }, - "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 - }, - "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" + } + }, + "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 + }, + "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" + } } - }, - "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.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.5.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": { + "@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==", + "dev": true } - }, - "eslint-module-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.0.tgz", - "integrity": "sha512-kCo8pZaNz2dsAW7nCUjuVoI11EBXXpIzfNxmaoLhXoRDOnqXLC4iSGVRdZPhOitfbdEfMEfKOiENaK6wDPZEGw==", - "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, - "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==", - "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 - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } + } + }, + "@jest/source-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.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 + } + } + }, + "@jest/test-result": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "dev": true, + "requires": { + "@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": "*" } } - }, - "eslint-plugin-import": { - "version": "2.19.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.19.1.tgz", - "integrity": "sha512-x68131aKoCZlCae7rDXKSAQmbT5DQuManyXo2sK6fJJ0aK5CWAkv6A6HJZGgqC8IhjQxYPgo6/IY4Oz8AFsbBw==", - "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" + } + }, + "@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + } + }, + "@jest/transform": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.9.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", + "micromatch": "^3.1.10", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "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" + } } - }, - "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" + } + }, + "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" + } } - }, - "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" + } + }, + "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" + } } } - } - }, - "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": { - "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 + }, + "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 + }, + "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 + }, + "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" } } - }, - "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==", - "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==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "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==", - "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==", - "dev": true - }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", - "dev": true, - "requires": { - "estraverse": "^4.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==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "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": { - "d": "1", - "es5-ext": "~0.10.14" + } + }, + "@jest/types": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz", + "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.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": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "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" + } } - }, - "event-stream": { - "version": "3.3.4", - "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", - "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" - }, - "dependencies": { - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", - "dev": true + } + }, + "@jsdevtools/coverage-istanbul-loader": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/coverage-istanbul-loader/-/coverage-istanbul-loader-3.0.3.tgz", + "integrity": "sha512-TAdNkeGB5Fe4Og+ZkAr1Kvn9by2sfL44IAHFtxlh1BA1XJ5cLpO9iSNki5opWESv3l3vSHsZ9BNKuqFKbEbFaA==", + "dev": true, + "requires": { + "convert-source-map": "^1.7.0", + "istanbul-lib-instrument": "^4.0.1", + "loader-utils": "^1.4.0", + "merge-source-map": "^1.1.0", + "schema-utils": "^2.6.4" + } + }, + "@kiosked/ulid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@kiosked/ulid/-/ulid-3.0.0.tgz", + "integrity": "sha512-ZKt2KIgGHDaGfKt6FjYvCpDvBXZRRoE8b+wDOlAV76aXKpq6ITiSUnPYevR4y55NKDnwCvwOrjWe+aVOCAK8kQ==" + }, + "@sindresorhus/is": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", + "integrity": "sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz", + "integrity": "sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "dev": true, + "requires": { + "samsam": "1.3.0" + } + }, + "@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "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.8", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.8.tgz", + "integrity": "sha512-KXBiQG2OXvaPWFPDS1rD8yV9vO0OuWIqAEqLsbfX0oU2REN5KuoMnZ1gClWcBhO5I3n6oTVAmrMufOvRqdmFTQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz", + "integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.12.tgz", + "integrity": "sha512-t4CoEokHTfcyfb4hUaF9oOHu9RmmNWnm1CP0YmMqOOfClKascOmvlEM736vlqeScuGvBDsHkf8R2INd4DWreQA==", + "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.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.2.tgz", + "integrity": "sha512-rsZg7eL+Xcxsxk2XlBt9KcG8nOp9iYdKCOikY9x2RFJCyOdNj4MKPQty0e8oZr29vVAzKXr1BmR+kZauti3o1w==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "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.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==", + "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.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.9.tgz", + "integrity": "sha512-0sCTiXKXELOBxvZLN4krQ0FPOAA7ij+6WwvD0k/PHd9/KAkr4dXel5J9fh6F4x1FwAQILqAWkmpeuS6mjf1iKA==", + "dev": true + }, + "@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", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/yargs": { + "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": "*" + } + }, + "@types/yargs-parser": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", + "dev": true + }, + "@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": { + "@types/node": "*" + } + }, + "@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": { + "@wdio/logger": "6.0.16", + "browserstack-local": "^1.4.5", + "got": "^11.0.2" + } + }, + "@wdio/cli": { + "version": "6.1.16", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-6.1.16.tgz", + "integrity": "sha512-q7JaEiLU2mdOibeKAQFqdWTS2evdkwgWSft1rmWDN7idiV39uncTTUcwlXBKE2a9yDk/8qn6EEXdBLthOCfyOA==", + "dev": true, + "requires": { + "@wdio/config": "6.1.14", + "@wdio/logger": "6.0.16", + "@wdio/utils": "6.1.8", + "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", + "log-update": "^4.0.0", + "webdriverio": "6.1.16", + "yargs": "^15.0.1", + "yarn-install": "^1.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.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "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 + }, + "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" + } + }, + "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 + }, + "locate-path": { + "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": "^4.1.0" + } + }, + "p-limit": { + "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" } - } - }, - "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.0.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", - "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", - "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": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "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==", - "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==", - "requires": { - "pump": "^3.0.0" - } + }, + "p-locate": { + "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.2.0" } - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" - }, - "expand-braces": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", - "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", - "dev": true, - "requires": { - "array-slice": "^0.2.3", - "array-unique": "^0.2.1", - "braces": "^0.1.2" - }, - "dependencies": { - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "braces": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", - "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", - "dev": true, - "requires": { - "expand-range": "^0.1.0" - } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "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 + }, + "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" } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "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=", - "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=", - "requires": { - "is-extendable": "^0.1.0" - } + }, + "yargs": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "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.1" } } - }, - "expand-range": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", - "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", - "dev": true, - "requires": { - "is-number": "^0.1.1", - "repeat-string": "^0.2.2" - }, - "dependencies": { - "is-number": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", - "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", - "dev": true - }, - "repeat-string": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", - "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", - "dev": true + } + }, + "@wdio/concise-reporter": { + "version": "6.1.14", + "resolved": "https://registry.npmjs.org/@wdio/concise-reporter/-/concise-reporter-6.1.14.tgz", + "integrity": "sha512-QKGiIPE2sYJpQcQ5zogUogu+Yldkx/FUM4LC01lc3v0Nww7n0p0fJA3U4cKFAqyW0gXCwW7m6/9c5fDgaSv8+g==", + "dev": true, + "requires": { + "@wdio/reporter": "6.1.14", + "chalk": "^4.0.0", + "pretty-ms": "^7.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" } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "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==", - "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==" + }, + "chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "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==", - "requires": { - "is-plain-object": "^2.0.4" - } + }, + "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" } - } - }, - "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==", - "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=", - "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=", - "requires": { - "is-extendable": "^0.1.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==", - "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==", - "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==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } + }, + "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" } } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "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==", - "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.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, - "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" - } - }, - "fecha": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", - "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" - }, - "fibers": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-3.1.1.tgz", - "integrity": "sha512-dl3Ukt08rHVQfY8xGD0ODwyjwrRALtaghuqGH2jByYX1wpY+nAnRQjJ6Dbqq0DnVgNVQ9yibObzbF4IlPyiwPw==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3" - } - }, - "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" - } - }, - "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" - } - }, - "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": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "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=", - "requires": { - "is-extendable": "^0.1.0" - } + } + }, + "@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": { + "@wdio/logger": "6.0.16", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + } + }, + "@wdio/local-runner": { + "version": "6.1.16", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-6.1.16.tgz", + "integrity": "sha512-3+pT2fcMXFAnELA6jYjVm6Nt8Il7tGL66A90UbRiT0sL2faTcD3uGAPbmzxMclsmWLh7C04ucCnFwQoTMW1emg==", + "dev": true, + "requires": { + "@wdio/logger": "6.0.16", + "@wdio/repl": "6.1.8", + "@wdio/runner": "6.1.16", + "async-exit-hook": "^2.0.1", + "stream-buffers": "^3.0.2" + } + }, + "@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": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.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" } - } - }, - "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" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.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==", - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "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==", - "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==" - }, - "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": { - "glob": "^7.1.3" - } + }, + "chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } - } - }, - "flatted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", - "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==", - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "follow-redirects": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", - "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", - "dev": true, - "requires": { - "debug": "^3.0.0" - }, - "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 + }, + "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" } - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "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=" - }, - "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==", - "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=", - "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" - } - }, - "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": "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" - }, - "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=", - "dev": true + }, + "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" } } - }, - "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=", - "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": { - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", - "dev": true + } + }, + "@wdio/mocha-framework": { + "version": "6.1.14", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-6.1.14.tgz", + "integrity": "sha512-2AmUH/v3kZoIDAMdW73AhI4tDJU3ie/2dO/DtpXJ3XFnuJ1CtklZGyCTtYHGMZ8DBj18/8Lrs/O0CjS5bAu2tw==", + "dev": true, + "requires": { + "@wdio/logger": "6.0.16", + "@wdio/utils": "6.1.8", + "expect-webdriverio": "^1.1.5", + "mocha": "^7.0.1" + }, + "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 + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" } - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": 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" - } - }, - "glob": { - "version": "7.1.3", - "bundled": 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" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": 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" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": 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" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": 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, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": 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" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "optional": 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" + } + }, + "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 + }, + "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" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "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" + } + }, + "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": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "p-limit": { + "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==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "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": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.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" + } + }, + "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" } } - }, - "fun-hooks": { - "version": "0.9.7", - "resolved": "https://registry.npmjs.org/fun-hooks/-/fun-hooks-0.9.7.tgz", - "integrity": "sha512-2G0S9op/u+Ye/IJVPS++bs8oDuC/x7MpTKPkJ85U0PBfocJYd+f8WQRN1gqaCa2egKwjOOtXYVFcu0ksns+lWQ==", - "requires": { - "typescript-tuple": "^2.2.1" + } + }, + "@wdio/protocols": { + "version": "6.1.14", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-6.1.14.tgz", + "integrity": "sha512-UtRLQ55i23cLQRGtFiEJty1F6AbAfiSpfIxDAiXKHbw6Rp1StwxlqHFrhNe5F48Zu4hnie46t9N/tr/cZOe0kA==", + "dev": true + }, + "@wdio/repl": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-6.1.8.tgz", + "integrity": "sha512-C647KvDIcOHYN24eFbiM2xE+etPEACvRYkEp7BPLyopEABDr0I3Qdb5MLhopC5eMAVHp70/WT27H1CE2v9iILQ==", + "dev": true, + "requires": { + "@wdio/utils": "6.1.8" + } + }, + "@wdio/reporter": { + "version": "6.1.14", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-6.1.14.tgz", + "integrity": "sha512-Pt6P0JU0COHTpggsOoJKUJyAyQsi7xlHebBNU/DWdHHpmzYd4e9vDutjyTqXu/1zn+t+Zq+uL1IC0E4Xjv6f7w==", + "dev": true, + "requires": { + "fs-extra": "^9.0.0" + } + }, + "@wdio/runner": { + "version": "6.1.16", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-6.1.16.tgz", + "integrity": "sha512-pGRT51BGnxp4zFD1pSp6qZD/4dnbSnDyV4g/MbbFiA4PFKF41mFhaxRwIGMHcp4EYlv9gaT31UA52JaFIYyuNA==", + "dev": true, + "requires": { + "@wdio/config": "6.1.14", + "@wdio/logger": "6.0.16", + "@wdio/utils": "6.1.8", + "deepmerge": "^4.0.0", + "gaze": "^1.1.2", + "webdriver": "6.1.14", + "webdriverio": "6.1.16" + } + }, + "@wdio/spec-reporter": { + "version": "6.1.14", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-6.1.14.tgz", + "integrity": "sha512-QaSBgnzllzLp9LR7/5DTkmrI8BqcznUma8ZxwUNmhvskv/oKzrmNyeCsGoiExFmCk81A9FgZiZPXey7CuaTkdw==", + "dev": true, + "requires": { + "@wdio/reporter": "6.1.14", + "chalk": "^4.0.0", + "easy-table": "^1.1.1", + "pretty-ms": "^7.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.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "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" + } } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "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" + } + }, + "@wdio/sync": { + "version": "6.1.14", + "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-6.1.14.tgz", + "integrity": "sha512-94K0kQdrOU0aMlJ2Xsd4tWr4tPpmCFp612Ml5+ecQh4C4XD07ocfsvGs+mwI7cfF1sO6g/Hoc+XTY2D+/8En3w==", + "dev": true, + "requires": { + "@wdio/logger": "6.0.16", + "fibers": "^4.0.1" + } + }, + "@wdio/utils": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-6.1.8.tgz", + "integrity": "sha512-qzvD8qCPpIpDrZ0HNOx1hTlfKY26p8WByUXgr52ll6DXxtAYXZLIJ8GAYFJUi87NVfwtv6+O7owQGSM/jtr8AQ==", + "dev": true, + "requires": { + "@wdio/logger": "6.0.16" + } + }, + "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": { + "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" + } + }, + "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": { + "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 } - }, - "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==" - }, - "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": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", - "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": "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=" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" + } + }, + "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": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "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==", - "dev": true, - "requires": { - "is-ssh": "^1.3.0", - "parse-url": "^3.0.2" + } + }, + "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": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true } - }, - "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" + } + }, + "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": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "dev": true + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "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" + }, + "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 } - }, - "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 + } + }, + "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 + }, + "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": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.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" } } - }, - "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" - } + } + }, + "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": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "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" + } + }, + "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": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "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": "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" + } + }, + "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": { + "buffer-equal": "^1.0.0" + } + }, + "append-transform": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "dev": true, + "requires": { + "default-require-extensions": "^1.0.0" + } + }, + "archiver": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-4.0.1.tgz", + "integrity": "sha512-/YV1pU4Nhpf/rJArM23W6GTUjT0l++VbjykrCRua1TSXrn+yM8Qs7XvtwSiRse0iCe49EPNf7ktXnPsWuSb91Q==", + "dev": true, + "requires": { + "archiver-utils": "^2.1.0", + "async": "^2.6.3", + "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": { + "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" } } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "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=", - "requires": { - "is-extglob": "^2.1.0" - } + } + }, + "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": { + "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": { + "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-stream": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", - "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" - } - }, - "glob-watcher": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", - "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", - "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" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.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==", + "dev": true, + "requires": { + "sprintf-js": "~1.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 + }, + "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": { + "make-iterator": "^1.0.0" + } + }, + "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=", + "dev": true, + "requires": { + "make-iterator": "^1.0.0" + } + }, + "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 + }, + "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, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "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": { + "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 } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + } + }, + "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": { + "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 } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "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.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", - "dev": true, - "requires": { - "glob": "~7.1.1", - "lodash": "~4.17.10", - "minimatch": "~3.0.2" + } + }, + "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": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "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 } - }, - "glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", - "requires": { - "sparkles": "^1.0.0" + } + }, + "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": { + "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==", + "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": { + "safer-buffer": "~2.1.0" + } + }, + "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" + }, + "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 } - }, - "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" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + } + }, + "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": { + "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" } } - }, - "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==" - }, - "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=" - }, - "gulp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", - "requires": { - "glob-watcher": "^5.0.3", - "gulp-cli": "^2.2.0", - "undertaker": "^1.2.1", - "vinyl-fs": "^3.0.0" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "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=", - "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==" - }, - "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==", - "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-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=", - "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=", - "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=", - "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=", - "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=", - "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=", - "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=" - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "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=", - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^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=" - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "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=", - "requires": { - "is-utf8": "^0.2.0" - } - }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "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=" - }, - "yargs": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", - "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", - "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=", - "requires": { - "camelcase": "^3.0.0" - } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "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==", + "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 + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "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" + } + }, + "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 + }, + "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 + }, + "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 + }, + "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" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "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 + }, + "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.10.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", + "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", + "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=", + "dev": true, + "requires": { + "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" } - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.0.tgz", - "integrity": "sha1-Tf/lJdriuGTGbC4jxicdev3s784=", - "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 + }, + "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 } - }, - "gulp-concat": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", - "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", - "requires": { - "concat-with-sourcemaps": "^1.0.0", - "through2": "^2.0.0", - "vinyl": "^2.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==", + "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" + }, + "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 } - }, - "gulp-connect": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/gulp-connect/-/gulp-connect-5.7.0.tgz", - "integrity": "sha1-fpJfXkw06/7fnzGFdpZuj+iEDVo=", - "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": "sha1-XaN4Jf7z51872kf3YNZL/RDhXhA=", - "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 + } + }, + "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-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" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + } + } + }, + "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" + } + }, + "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=", + "dev": true, + "requires": { + "babel-helper-explode-assignable-expression": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "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" + } + }, + "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=", + "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-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" + } + }, + "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=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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=", + "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" + } + }, + "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=", + "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-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "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": { + "@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 } - }, - "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" + } + }, + "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": { + "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": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true } - }, - "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" - } + } + }, + "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-runtime": "^6.22.0" + } + }, + "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=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "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": { + "object.assign": "^4.1.0" + } + }, + "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/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-limit": { + "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==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "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-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" + } + }, + "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=", + "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=", + "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=", + "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": { + "babel-plugin-syntax-dynamic-import": "^6.18.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" + } + }, + "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" + } + }, + "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-syntax-class-constructor-call": "^6.18.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "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-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-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=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "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-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": { + "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.22.0", + "babel-template": "^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=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "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": { + "babel-runtime": "^6.22.0", + "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=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "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": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "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=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "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" + } + }, + "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" + } + }, + "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": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "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" + } + }, + "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" + } + }, + "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, + "requires": { + "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" + } + }, + "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": { + "babel-runtime": "^6.22.0", + "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": { + "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" + } + }, + "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-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": { + "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": { + "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=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" } - } - }, - "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" - } + }, + "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" } } - }, - "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" + } + }, + "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=", + "dev": true, + "requires": { + "babel-plugin-syntax-export-extensions": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "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": { + "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=", + "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" + } + }, + "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": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "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": { + "babel-runtime": "^6.22.0" + } + }, + "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-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-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-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": { + "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" + } } - }, - "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" - } + } + }, + "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": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "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": { + "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" } } - }, - "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" + } + }, + "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": { + "babel-plugin-transform-flow-strip-types": "^6.22.0" + } + }, + "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": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" + } + }, + "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": { + "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": { + "babel-plugin-transform-do-expressions": "^6.22.0", + "babel-plugin-transform-function-bind": "^6.22.0", + "babel-preset-stage-1": "^6.24.1" + } + }, + "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" + } + }, + "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" + } + }, + "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": { + "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-register": { + "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 } - }, - "gulp-rename": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.4.0.tgz", - "integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==" - }, - "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" + } + }, + "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==" } - }, - "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" + } + }, + "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" + } + }, + "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": { + "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": { + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "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 - } + } + }, + "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": { + "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 } - }, - "gulp-typescript": { - "version": "6.0.0-alpha.1", - "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-6.0.0-alpha.1.tgz", - "integrity": "sha512-KoT0TTfjfT7w3JItHkgFH1T/zK4oXWC+a8xxKfniRfVcA0Fa1bKrIhztYelYmb+95RB80OLMBreknYkdwzdi2Q==", - "requires": { - "ansi-colors": "^4.1.1", - "plugin-error": "^1.0.1", - "source-map": "^0.7.3", - "through2": "^3.0.1", - "vinyl": "^2.2.0", - "vinyl-fs": "^3.0.3" - }, - "dependencies": { - "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==" - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - }, - "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", - "requires": { - "readable-stream": "2 || 3" - } + } + }, + "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=", + "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" + } + }, + "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==", + "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" } - } - }, - "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==", - "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-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": { - "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 - }, - "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 - }, - "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" - } + }, + "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" } - } - }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "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.5.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", - "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", - "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==" + }, + "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" } - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "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==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "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=" - }, - "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==" + }, + "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" } } - }, - "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" + } + }, + "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 + }, + "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": { + "safe-buffer": "5.1.2" + } + }, + "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=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "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=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "bfj": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", + "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "check-types": "^8.0.3", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + } + }, + "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 + }, + "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": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, + "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 + }, + "binaryextensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", + "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", + "dev": true + }, + "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": { + "file-uri-to-path": "1.0.0" + } + }, + "bl": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", + "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", + "dev": true, + "requires": { + "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 } - }, - "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 + } + }, + "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 + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==", + "dev": true + }, + "body": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", + "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "dev": true, + "requires": { + "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 } - }, - "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=" - }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", - "requires": { - "sparkles": "^1.0.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==", + "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" + } + }, + "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": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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" + } + }, + "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==", + "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 } - }, - "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" + } + }, + "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, + "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" + } + }, + "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": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.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==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "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": { + "bn.js": "^4.1.0", + "randombytes": "^2.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 } - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + } + }, + "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 } - }, - "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=", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } + } + }, + "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": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.0.tgz", + "integrity": "sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001043", + "electron-to-chromium": "^1.3.413", + "node-releases": "^1.1.53", + "pkg-up": "^2.0.0" + } + }, + "browserstack": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz", + "integrity": "sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==", + "dev": true, + "requires": { + "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" } - } - }, - "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.3", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.0.3.tgz", - "integrity": "sha512-C62CVn7jbjp89yOhhy7vrkSaB7Vk906Gtcw/Ihd+Iufnq+2pwOZjdPmpzpKLWJXPJBMDX3wXg4FqmdOayPcewA==", - "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 + }, + "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" } - } - }, - "hast-util-whitespace": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.3.tgz", - "integrity": "sha512-AlkYiLTTwPOyxZ8axq2/bCwRUPjIPBfrHkXuCR92B38b3lSdU22R5F/Z4DL6a2kxWpekWq1w6Nj48tWat6GeRA==", - "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.17.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.17.0.tgz", - "integrity": "sha512-PyO7FK7z8ZC7FqBlmAxm4d+1DYaoS6+uaxt9KGkyP1AnmGRLnWmNod1yp9BFjUyHoDF00k+V57gF6X9ifY7f/A==", - "dev": true, - "requires": { - "handlebars": "^4.5.3" - } - }, - "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==", - "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.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", - "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==" - }, - "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==", - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "html-void-elements": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.4.tgz", - "integrity": "sha512-yMk3naGPLrfvUV9TdDbuYXngh/TpHbA6TrOw3HL9kS8yhwx7i309BReNg7CbAJXGE+UMJ6je5OqJ7lC63o6YuQ==", - "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=", - "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==", - "dev": true, - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "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 + }, + "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 } - }, - "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==", - "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==", - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "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" - } - }, - "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=", - "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==" - }, - "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" - }, - "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 - }, - "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" - } + } + }, + "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": { + "https-proxy-agent": "^4.0.0", + "is-running": "^2.1.0", + "ps-tree": "=1.2.0", + "temp-fs": "^0.9.9" + } + }, + "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": { + "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 } - }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" - }, - "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" + } + }, + "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": { + "node-int64": "^0.4.0" + } + }, + "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": { + "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==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "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 + }, + "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": { + "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": { + "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 } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" + } + }, + "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": { + "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" + } + }, + "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 + }, + "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": { + "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" + } + }, + "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": { + "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 } - }, - "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=" - }, - "ipaddr.js": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", - "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" - }, - "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==", - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" + } + }, + "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 + }, + "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": { + "camelcase": "^3.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true } - }, - "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=", - "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=", - "requires": { - "is-buffer": "^1.1.5" - } + } + }, + "caniuse-lite": { + "version": "1.0.30001077", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001077.tgz", + "integrity": "sha512-AEzsGvjBJL0lby/87W96PyEvwN0GsYvk5LHsglLg9tW37K4BqvAvoSCdWIE13OZQ8afupqZ73+oL/1LkedN8hA==", + "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==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "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": { + "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==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.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==", + "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==", + "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==", + "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.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz", + "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==", + "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.4.0" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.2.tgz", + "integrity": "sha512-zWD9RVVKd8Nx2xKGY4G08lb3nCD+2hmICxovvRE9QjBKQzHFvCYqGlsw15b4zUxLKq3wXEwVbR/yLtMbfk7JbQ==", + "dev": true, + "requires": { + "@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": { + "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" } } - }, - "is-alphabetical": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.3.tgz", - "integrity": "sha512-eEMa6MKpHFzw38eKm56iNNi6GJ7lf6aLLio7Kr23sJPAECscgRtZvOBYybejWDQ2bM949Y++61PY+udzj5QMLA==", - "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.3", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.3.tgz", - "integrity": "sha512-A1IGAPO5AW9vSh7omxIlOGwIqEvpW/TA+DksVOPM5ODuxKlZS09+TEM1E3275lJqO2oJ38vDpeAL3DCIiHE6eA==", - "dev": true, - "requires": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "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==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "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": { + "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" + } } - }, - "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=" - }, - "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=", - "requires": { - "binary-extensions": "^1.0.0" + } + }, + "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" + } + }, + "cli-spinners": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.3.0.tgz", + "integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w==", + "dev": 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 + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "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=", + "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=", + "dev": true, + "requires": { + "mimic-response": "^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==", + "dev": true, + "requires": { + "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" + } } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "requires": { - "ci-info": "^2.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "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=", + "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==", + "dev": true + }, + "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": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "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": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "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": { + "color-name": "1.1.3" + } + }, + "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": { + "delayed-stream": "~1.0.0" + } + }, + "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==", + "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": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^3.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^2.3.7" + }, + "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" + } } - }, - "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=", - "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=", - "requires": { - "is-buffer": "^1.1.5" - } + } + }, + "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": { + "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" } } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" - }, - "is-decimal": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.3.tgz", - "integrity": "sha512-bvLSwoDg2q6Gf+E2LEPiklHZxxiSi3XAh4Mav65mKqTfCO1HM3uBs24TjEH8iJX3bbDdLXKJXBTmGzuTUuAEjQ==", - "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==", - "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==" - } + } + }, + "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 } - }, - "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" + } + }, + "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==", + "dev": true + }, + "console-browserify": { + "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==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "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==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "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==", + "dev": true, + "requires": { + "each-props": "^1.3.0", + "is-plain-object": "^2.0.1" + } + }, + "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": { + "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 } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" + } + }, + "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 + }, + "coveralls": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.0.tgz", + "integrity": "sha512-sHxOu2ELzW8/NC1UP5XVLbZDzO4S3VxfFye3XYCznopHy02YjNkHcj5bKaVw2O7hVaBdBjEdQGpie4II1mWhuQ==", + "dev": true, + "requires": { + "js-yaml": "^3.13.1", + "lcov-parse": "^1.0.0", + "log-driver": "^1.2.7", + "minimist": "^1.2.5", + "request": "^2.88.2" + } + }, + "crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "requires": { + "buffer": "^5.1.0" + } + }, + "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": { + "crc": "^3.4.4", + "readable-stream": "^3.4.0" + } + }, + "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": { + "bn.js": "^4.1.0", + "elliptic": "^6.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 } - }, - "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=" - }, - "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==" - }, - "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==", - "requires": { - "is-extglob": "^2.1.1" + } + }, + "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": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "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": { + "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" + } + }, + "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": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "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": { + "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" + } + }, + "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": { + "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 } - }, - "is-hexadecimal": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.3.tgz", - "integrity": "sha512-zxQ9//Q3D/34poZf8fiy3m3XVpbQc7ren15iKqrTtLPwkPD/t3Scy9Imp63FujULGxuK0ZlCwoo5xNpktFgbOA==", - "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=" - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "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=", - "requires": { - "is-buffer": "^1.1.5" - } + } + }, + "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==", + "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==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, + "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": { + "array-find-index": "^1.0.1" + } + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "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" + } + }, + "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" + } + }, + "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": { + "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" } } - }, - "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==", - "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.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "requires": { - "has": "^1.0.1" + } + }, + "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": { + "get-stdin": "^4.0.1", + "meow": "^3.3.0" + } + }, + "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": { + "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 } - }, - "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==", - "requires": { - "is-unc-path": "^1.0.0" + } + }, + "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": "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": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "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 } - }, - "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==", - "dev": true, - "requires": { - "protocols": "^1.1.0" + } + }, + "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": { + "type-detect": "^4.0.0" + } + }, + "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==", + "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" + } + }, + "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/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "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": { - "has-symbols": "^1.0.1" + } + }, + "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 + }, + "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": { + "clone": "^1.0.2" + } + }, + "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==", + "requires": { + "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": { + "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" + } } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "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==", - "requires": { - "unc-path-regex": "^0.1.2" + } + }, + "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": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "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": { + "repeat-string": "^1.5.4" + } + }, + "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 + }, + "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": { + "repeating": "^2.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=", + "dev": true + }, + "detective": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", + "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "dev": true, + "requires": { + "acorn": "^5.2.1", + "defined": "^1.0.0" + } + }, + "devtools": { + "version": "6.1.16", + "resolved": "https://registry.npmjs.org/devtools/-/devtools-6.1.16.tgz", + "integrity": "sha512-Px/K/xYY+fTW8D5yt7p6ZZJfkfHHulKVr2Y+BJSCQyKNSY/hiZFT6KAjoUFrAastLCqqs1gW2Dy/OGb0qWm+Hg==", + "dev": true, + "requires": { + "@wdio/config": "6.1.14", + "@wdio/logger": "6.0.16", + "@wdio/protocols": "6.1.14", + "@wdio/utils": "6.1.8", + "chrome-launcher": "^0.13.1", + "puppeteer-core": "^3.0.0", + "ua-parser-js": "^0.7.21", + "uuid": "^8.0.0" + } + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diff-sequences": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", + "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==", + "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": { + "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 } - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" - }, - "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=" - }, - "is-whitespace-character": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.3.tgz", - "integrity": "sha512-SNPgMLz9JzPccD3nPctcj8sZlX9DAMJSKH8bP7Z6bohCwuNgX8xbWr1eTAYXX9Vpi/aSn8Y1akL9WgM3t43YNQ==", - "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==" - }, - "is-word-character": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.3.tgz", - "integrity": "sha512-0wfcrFgOOOBdgRNT9H33xe6Zi6yhX/uoc4U8NBZGeQQB0ctU1dnlNTyL9JM2646bHDTpsDm1Brb3VPoCIMrd/A==", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "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" + } + }, + "disparity": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/disparity/-/disparity-2.0.0.tgz", + "integrity": "sha1-V92stHMkrl9Y0swNqIbbTOnutxg=", + "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 + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "istanbul": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", - "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", - "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" - }, - "dependencies": { - "escodegen": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", - "dev": true, - "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.2.0" - } - }, - "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": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.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 - }, - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "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=", - "dev": true, - "optional": true, - "requires": { - "amdefine": ">=0.0.4" + } + }, + "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=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "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": { + "esutils": "^2.0.2", + "isarray": "^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==", + "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" + }, + "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 + }, + "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" + } } - }, - "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" + } + }, + "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" + } } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true } - } - }, - "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==", - "dev": true, - "requires": { - "lodash": "^4.17.14" + }, + "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" + } } - }, - "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" + } + }, + "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" + } } - }, - "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 - }, - "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 - }, - "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": { - "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" + } + }, + "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" + } + }, + "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 + }, + "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" + } } - }, - "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": { - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" + } + }, + "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-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" + } + }, + "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-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": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } } - }, - "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": { - "handlebars": "^4.0.3" + } + }, + "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 + }, + "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" + } } - }, - "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 - }, - "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" + } + }, + "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" + } } } - } - }, - "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==", - "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" - }, - "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==", - "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==", - "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" - } + }, + "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=", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "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 + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "dset": { + "version": "2.0.1", + "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 + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "requires": { + "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" + } + } + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.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" + } + } + } + }, + "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": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "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": { + "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 + } + } + }, + "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" + } + }, + "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": { + "jake": "^10.6.1" + } + }, + "electron-to-chromium": { + "version": "1.3.458", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.458.tgz", + "integrity": "sha512-OjRkb0igW0oKE2QbzS7vBYrm7xjW/KRTtIj0OGGx57jr/YhBiKb7oZvdbaojqjfCb/7LbnwsbMbdsYjthdJbAw==", + "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==", + "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" + }, + "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 + } + } + }, + "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 + }, + "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": { + "once": "^1.4.0" + } + }, + "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": { + "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" + } + } + } + }, + "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": { + "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": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "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": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "object-assign": "^4.0.1", + "tapable": "^0.2.7" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", + "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", + "dev": true, + "requires": { + "string-template": "~0.2.1" + } + }, + "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": { + "is-arrayish": "^0.2.1" + } + }, + "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==", + "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" + } + }, + "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" + } + }, + "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": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "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 + }, + "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, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + }, + "dependencies": { + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + } + } + }, + "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" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", + "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", + "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 + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": 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, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "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, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "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 + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "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, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } - } - }, - "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==" - }, - "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==", - "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" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "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" } } - }, - "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==", - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "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==", - "requires": { - "has-flag": "^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=", + "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==", + "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": { + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.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==", - "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" - }, - "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 - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + }, + "eslint-plugin-import": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz", + "integrity": "sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg==", + "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": { + "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" + } + }, + "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" + } + }, + "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" } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true } - }, - "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", - "requires": { - "handlebars": "^4.1.2" + } + }, + "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": { + "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 } - }, - "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" + } + }, + "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==", + "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==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "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==", + "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==", + "dev": true + }, + "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": { + "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 } - }, - "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" + } + }, + "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": { + "estraverse": "^4.1.0" + } + }, + "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": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "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": { + "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" + } + }, + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "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 + }, + "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": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "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": { + "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": { + "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" + } + }, + "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" + } } - }, - "jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", - "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", - "requires": { - "import-local": "^2.0.0", - "jest-cli": "^24.9.0" - }, - "dependencies": { - "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==", - "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" - } - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "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" - } + } + }, + "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": { + "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" } } - }, - "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==", - "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.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": { + "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" + } } - }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "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" + } + }, + "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": "25.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-25.5.0.tgz", + "integrity": "sha512-w7KAXo0+6qqZZhovCaBVPSIqQp7/UTcx4M9uKt2m6pd2VB1voyC8JizLRqeEqud3AAVP02g+hbErDu5gu64tlA==", + "dev": true, + "requires": { + "@jest/types": "^25.5.0", + "ansi-styles": "^4.0.0", + "jest-get-type": "^25.2.6", + "jest-matcher-utils": "^25.5.0", + "jest-message-util": "^25.5.0", + "jest-regex-util": "^25.2.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" + } + }, + "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 } - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + } + }, + "expect-webdriverio": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-1.1.5.tgz", + "integrity": "sha512-+RL4Lkne+/z+o1G5Y0S5QuEXeICxt4jExhBSM2Jn/mrDwb+PZVKPM2Yd1OzLsKeCdQLtw4Oft6514Gp5GLgdZA==", + "dev": true, + "requires": { + "expect": "^25.2.1", + "jest-matcher-utils": "^25.1.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 } - }, - "jest-docblock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", - "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", - "requires": { - "detect-newline": "^2.1.0" + } + }, + "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": { + "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": { + "is-plain-object": "^2.0.4" + } } - }, - "jest-each": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", - "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", - "requires": { - "@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" + } + }, + "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/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": "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" + } } - }, - "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==", - "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" + } + }, + "extract-zip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.0.tgz", + "integrity": "sha512-i42GQ498yibjdvIhivUsRslx608whtGoFIhF26Z7O4MYncBxp8CwalOs1lnHy21A9sIohWO2+uiE4SRtC9JXDg==", + "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": { + "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 } - }, - "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==", - "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" + } + }, + "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": "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 + }, + "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" + } + }, + "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" + } + }, + "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": { + "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" + } + }, + "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-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==" - }, - "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==", - "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" + } + }, + "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": { + "glob": "^7.1.3" + } } - }, - "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==", - "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" + } + }, + "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": { + "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" + } } - }, - "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==", - "requires": { - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" + } + }, + "follow-redirects": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", + "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", + "dev": true, + "requires": { + "debug": "^3.0.0" + }, + "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 } - }, - "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==", - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.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=", + "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==", + "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" + } } - }, - "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==", - "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" - }, - "dependencies": { - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", + "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "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 } - }, - "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==", - "requires": { - "@jest/types": "^24.9.0" + } + }, + "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" + } + }, + "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==" + }, + "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": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", + "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 } - }, - "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==" - }, - "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==" - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "requires": { - "@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" + } + }, + "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" + } } - }, - "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==", - "requires": { - "@jest/types": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.9.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" + } } - }, - "jest-runner": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", - "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", - "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", - "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" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "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==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + } + }, + "glob-watcher": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", + "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", + "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" + }, + "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" + } + }, + "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" + }, + "dependencies": { + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "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" + } + } + } + }, + "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" + } + }, + "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" + } + }, + "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" + } } - }, - "jest-runtime": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", - "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", - "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==" - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "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" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz", + "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.12", + "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.2.0", + "resolved": "https://registry.npmjs.org/got/-/got-11.2.0.tgz", + "integrity": "sha512-68pBow9XXXSdVRV5wSx0kWMCZsag4xE3Ru0URVe0PWsSYmU4SJrUmEO6EVYFlFHc9rq/6Yqn6o1GxIb9torQxg==", + "dev": true, + "requires": { + "@sindresorhus/is": "^2.1.1", + "@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", + "get-stream": "^5.1.0", + "http2-wrapper": "^1.0.0-beta.4.5", + "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.2.1", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.1.tgz", + "integrity": "sha512-yEMxrXqY8mJFlaauFQxNrCpzWJThu0sH1sqlToaTOT063Hub9s/Nt2C+GSLe6feQ/IMWrHvGOOsyES7CQc9O+A==", + "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-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" + } } } - } - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==" - }, - "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==", - "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==" + }, + "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" } - } - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "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" } - } - }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - } - }, - "jest-watcher": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", - "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", - "requires": { - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "jest-util": "^24.9.0", - "string-length": "^2.0.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "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==", - "requires": { - "has-flag": "^3.0.0" + }, + "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" + } } } - } - }, - "js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "requires": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", - "xml-name-validator": "^3.0.0" - } - }, - "jsencrypt": { - "version": "3.0.0-rc.1", - "resolved": "http://build-nexus.crto.in/repository/npm/jsencrypt/-/jsencrypt-3.0.0-rc.1.tgz", - "integrity": "sha512-gcvGaqerlUJy1Kq6tNgPYteVEoWNemu+9hBe2CdsCIz4rVcwjoTQ72iD1W76/PRMlnkzG0yVh7nwOOMOOUfKmg==" - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "jsmin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jsmin/-/jsmin-1.0.1.tgz", - "integrity": "sha1-570NzWSWw79IYyNb9GGj2YqjuYw=" - }, - "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 - }, - "json-loader": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", - "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "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 - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json5": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", - "requires": { - "minimist": "^1.2.0" - } - }, - "jsonfile": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz", - "integrity": "sha1-6l7+QLg2kLmGZ2FKc5L8YOhCwN0=", - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "just-clone": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", - "integrity": "sha1-v7P672WqEqMWBYcSlFwyb9jwFDQ=" - }, - "just-debounce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", - "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=" - }, - "just-extend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", - "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", - "dev": true - }, - "jxLoader": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jxLoader/-/jxLoader-0.1.1.tgz", - "integrity": "sha1-ATTqUUTlM7WU/B/yX/GU4jXFPs0=", - "requires": { - "js-yaml": "0.3.x", - "moo-server": "1.3.x", - "promised-io": "*", - "walker": "1.x" - }, - "dependencies": { - "js-yaml": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-0.3.7.tgz", - "integrity": "sha1-1znY7oZGHlSzVNan19HyrZoWf2I=" + }, + "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 } - }, - "karma": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/karma/-/karma-3.1.4.tgz", - "integrity": "sha512-31Vo8Qr5glN+dZEVIpnPCxEGleqE0EY6CtC2X9TagRV3rRQ3SNrvfhddICkJgUK3AgqpeKSZau03QumTGhGoSw==", - "dev": true, - "requires": { - "bluebird": "^3.3.0", - "body-parser": "^1.16.1", - "chokidar": "^2.0.3", - "colors": "^1.1.0", - "combine-lists": "^1.0.0", - "connect": "^3.6.0", - "core-js": "^2.2.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.0", - "expand-braces": "^0.1.1", - "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.5", - "log4js": "^3.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==", - "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 + } + }, + "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" } - } - }, - "karma-babel-preprocessor": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/karma-babel-preprocessor/-/karma-babel-preprocessor-6.0.1.tgz", - "integrity": "sha1-euHT5klQ2+EfQht0BAqwj7WmbCE=", - "dev": true, - "requires": { - "babel-core": "^6.0.0" - } - }, - "karma-browserstack-launcher": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/karma-browserstack-launcher/-/karma-browserstack-launcher-1.5.1.tgz", - "integrity": "sha512-zt9Ukow5A9WZHZXCFVO/h5kRsAdaZYeMNJK9Uan8v42amQXt3B/DZVxl24NCcAIxufKjW13UWd9iJ9knG9OCYw==", - "dev": true, - "requires": { - "browserstack": "~1.5.1", - "browserstack-local": "^1.3.7", - "q": "~1.5.0" - } - }, - "karma-chai": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", - "integrity": "sha1-vuWtQEAFF4Ea40u5RfdikJEIt5o=", - "dev": true - }, - "karma-chrome-launcher": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", - "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", - "dev": true, - "requires": { - "fs-access": "^1.0.0", - "which": "^1.2.1" - } - }, - "karma-coverage-istanbul-reporter": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.3.tgz", - "integrity": "sha1-O13/RmT6W41RlrmInj9hwforgNk=", - "dev": true, - "requires": { - "istanbul-api": "^1.3.1", - "minimatch": "^3.0.4" - } - }, - "karma-es5-shim": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/karma-es5-shim/-/karma-es5-shim-0.0.4.tgz", - "integrity": "sha1-zdADM8znfC5M4D46yT8vjs0fuVI=", - "dev": true, - "requires": { - "es5-shim": "^4.0.5" - } - }, - "karma-firefox-launcher": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-1.2.0.tgz", - "integrity": "sha512-j9Zp8M8+VLq1nI/5xZGfzeaEPtGQ/vk3G+Y8vpmFWLvKLNZ2TDjD6cu2dUu7lDbu1HXNgatsAX4jgCZTkR9qhQ==", - "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 + }, + "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 } - }, - "karma-ie-launcher": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/karma-ie-launcher/-/karma-ie-launcher-1.0.0.tgz", - "integrity": "sha1-SXmGhCxJAZA0bNifVJTKmDDG1Zw=", - "dev": true, - "requires": { - "lodash": "^4.6.1" - } - }, - "karma-mocha": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-1.3.0.tgz", - "integrity": "sha1-7qrH/8DiAetjxGdEDStpx883eL8=", - "dev": true, - "requires": { - "minimist": "1.2.0" - } - }, - "karma-mocha-reporter": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz", - "integrity": "sha1-FRIAlejtgZGG5HoLAS8810GJVWA=", - "dev": true, - "requires": { - "chalk": "^2.1.0", - "log-symbols": "^2.1.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 - }, - "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" - } + } + }, + "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" } - } - }, - "karma-opera-launcher": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/karma-opera-launcher/-/karma-opera-launcher-1.0.0.tgz", - "integrity": "sha1-+lFihTGh0L6EstjcDX7iCfyP+Ro=", - "dev": true - }, - "karma-safari-launcher": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/karma-safari-launcher/-/karma-safari-launcher-1.0.0.tgz", - "integrity": "sha1-lpgqLMR9BmquccVTursoMZEVos4=", - "dev": true - }, - "karma-script-launcher": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/karma-script-launcher/-/karma-script-launcher-1.0.0.tgz", - "integrity": "sha1-zQF8TeXvCeWp2nkydhdhCN1LVC0=", - "dev": true - }, - "karma-sinon": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/karma-sinon/-/karma-sinon-1.0.5.tgz", - "integrity": "sha1-TjRD8oMP3s/2JNN0cWPxIX2qKpo=", - "dev": true - }, - "karma-sourcemap-loader": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.7.tgz", - "integrity": "sha1-kTIsd/jxPUb+0GKwQuEAnUxFBdg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2" - } - }, - "karma-spec-reporter": { - "version": "0.0.31", - "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.31.tgz", - "integrity": "sha1-SDDccUihVcfXoYbmMjOaDYD63sM=", - "dev": true, - "requires": { - "colors": "^1.1.2" - } - }, - "karma-webpack": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/karma-webpack/-/karma-webpack-3.0.5.tgz", - "integrity": "sha512-nRudGJWstvVuA6Tbju9tyGUfXTtI1UXMXoRHVmM2/78D0q6s/Ye2IC157PKNDC15PWFGR0mVIRtWLAdcfsRJoA==", - "dev": true, - "requires": { - "async": "^2.0.0", - "babel-runtime": "^6.0.0", - "loader-utils": "^1.0.0", - "lodash": "^4.0.0", - "source-map": "^0.5.6", - "webpack-dev-middleware": "^2.0.6" - }, - "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" - } + }, + "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" } - } - }, - "kebab-case": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/kebab-case/-/kebab-case-1.0.0.tgz", - "integrity": "sha1-P55JkK3K0MaGwOcB92RYaPdfkes=", - "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" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" - }, - "kuler": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", - "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", - "requires": { - "colornames": "^1.1.1" - } - }, - "last-run": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", - "requires": { - "default-resolution": "^2.0.0", - "es6-weak-map": "^2.0.1" - } - }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true - }, - "lazystream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", - "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", - "requires": { - "readable-stream": "^2.0.5" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "requires": { - "invert-kv": "^1.0.0" - } - }, - "lcov-parse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", - "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", - "dev": true - }, - "lead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", - "requires": { - "flush-write-stream": "^1.0.2" - } - }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "requires": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - } - }, - "livereload-js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", - "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", - "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=", - "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=" + }, + "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" } - } - }, - "loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", - "dev": true - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.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" - } + }, + "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 } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "lodash._escapehtmlchar": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz", - "integrity": "sha1-32fDu2t+jh6DGrSL+geVuSr+iZ0=", - "dev": true, - "requires": { - "lodash._htmlescapes": "~2.4.1" - } - }, - "lodash._escapestringchar": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.4.1.tgz", - "integrity": "sha1-7P4iYYoq3lC/7qQ5N+Ud9m8O23I=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash._htmlescapes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz", - "integrity": "sha1-MtFL8IRLbeb4tioFG09nwii2JMs=", - "dev": true - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "lodash._isnative": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._isnative/-/lodash._isnative-2.4.1.tgz", - "integrity": "sha1-PqZAS3hKe+g2x7V1gOHN95sUgyw=", - "dev": true - }, - "lodash._objecttypes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", - "integrity": "sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=", - "dev": true - }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "lodash._reinterpolate": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz", - "integrity": "sha1-TxInqlqHEfxjL1sHofRgequLMiI=", - "dev": true - }, - "lodash._reunescapedhtml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz", - "integrity": "sha1-dHxPxAED6zu4oJduVx96JlnpO6c=", - "dev": true, - "requires": { - "lodash._htmlescapes": "~2.4.1", - "lodash.keys": "~2.4.1" - } - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, - "lodash._shimkeys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz", - "integrity": "sha1-bpzJZm/wgfC1psl4uD4kLmlJ0gM=", - "dev": true, - "requires": { - "lodash._objecttypes": "~2.4.1" - } - }, - "lodash.clone": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", - "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", - "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" - } - }, - "lodash.escape": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.4.1.tgz", - "integrity": "sha1-LOEsXghNsKV92l5dHu659dF1o7Q=", - "dev": true, - "requires": { - "lodash._escapehtmlchar": "~2.4.1", - "lodash._reunescapedhtml": "~2.4.1", - "lodash.keys": "~2.4.1" - } - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "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" - } - }, - "lodash.keys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", - "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", - "dev": true, - "requires": { - "lodash._isnative": "~2.4.1", - "lodash._shimkeys": "~2.4.1", - "lodash.isobject": "~2.4.1" - } - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" - }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true - }, - "lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" - }, - "lodash.template": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-2.4.1.tgz", - "integrity": "sha1-nmEQB+32KRKal0qzxIuBez4c8g0=", - "dev": true, - "requires": { - "lodash._escapestringchar": "~2.4.1", - "lodash._reinterpolate": "~2.4.1", - "lodash.defaults": "~2.4.1", - "lodash.escape": "~2.4.1", - "lodash.keys": "~2.4.1", - "lodash.templatesettings": "~2.4.1", - "lodash.values": "~2.4.1" - } - }, - "lodash.templatesettings": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz", - "integrity": "sha1-6nbHXRHrhtTb6JqDiTu4YZKaxpk=", - "dev": true, - "requires": { - "lodash._reinterpolate": "~2.4.1", - "lodash.escape": "~2.4.1" - } - }, - "lodash.values": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-2.4.1.tgz", - "integrity": "sha1-q/UUQ2s8twUAFieXjLzzCxKA7qQ=", - "dev": true, - "requires": { - "lodash.keys": "~2.4.1" - } - }, - "log-driver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", - "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", - "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" - } - }, - "log4js": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-3.0.6.tgz", - "integrity": "sha512-ezXZk6oPJCWL483zj64pNkMuY/NcRX5MPiB0zE6tjZM137aeusrOnW1ecxgF9cmwMWkBMhjteQxBPoZBh9FDxQ==", - "dev": true, - "requires": { - "circular-json": "^0.5.5", - "date-format": "^1.2.0", - "debug": "^3.1.0", - "rfdc": "^1.1.2", - "streamroller": "0.7.0" - }, - "dependencies": { - "circular-json": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", - "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==", - "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" - } - }, - "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 + } + }, + "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" } } - }, - "logform": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", - "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", - "requires": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", - "fecha": "^2.3.3", - "ms": "^2.1.1", - "triple-beam": "^1.3.0" - } - }, - "loglevelnext": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/loglevelnext/-/loglevelnext-1.0.5.tgz", - "integrity": "sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A==", - "dev": true, - "requires": { - "es6-symbol": "^3.1.1", - "object.assign": "^4.1.0" - } - }, - "lolex": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", - "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", - "dev": true - }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true - }, - "longest-streak": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.3.tgz", - "integrity": "sha512-9lz5IVdpwsKLMzQi0MQ+oD9EA0mIGcWYP7jXMTZVXP8D42PwuAk+M/HBFYQoxt1G5OR8m7aSIgb1UymfWGBWEw==", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^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" + } } - }, - "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 - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + } + }, + "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" + } } - }, - "lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", - "dev": true, - "requires": { - "es5-ext": "~0.10.2" + } + }, + "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 } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.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 } - }, - "make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==" - }, - "make-error-cause": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz", - "integrity": "sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0=", - "requires": { - "make-error": "^1.2.0" + } + }, + "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" + } } - }, - "make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "requires": { - "kind-of": "^6.0.2" + } + }, + "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 } - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "requires": { - "tmpl": "1.0.x" + } + }, + "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 } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "requires": { - "object-visit": "^1.0.0" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "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" + } } - }, - "markdown-escapes": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.3.tgz", - "integrity": "sha512-XUi5HJhhV5R74k8/0H2oCbCiYf/u4cO/rX8tnGkRvrqhsr5BRNU6Mg0yt/8UIx1iIS8220BNJsDb7XnILhLepw==", - "dev": true - }, - "markdown-table": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", - "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", - "dev": true - }, - "matchdep": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", - "requires": { - "findup-sync": "^2.0.0", - "micromatch": "^3.0.4", - "resolve": "^1.4.0", - "stack-trace": "0.0.10" - }, - "dependencies": { - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" + } + }, + "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" + }, + "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==" + }, + "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" + } } - }, - "math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", - "dev": true - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mdast-util-compact": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz", - "integrity": "sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg==", - "dev": true, - "requires": { - "unist-util-visit": "^1.1.0" + } + }, + "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 } - }, - "mdast-util-definitions": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-1.2.5.tgz", - "integrity": "sha512-CJXEdoLfiISCDc2JB6QLb79pYfI6+GcIH+W2ox9nMc7od0Pz+bovcHsiq29xAQY6ayqe/9CsK2VzkSJdg1pFYA==", - "dev": true, - "requires": { - "unist-util-visit": "^1.0.0" + } + }, + "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 } - }, - "mdast-util-inject": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-inject/-/mdast-util-inject-1.1.0.tgz", - "integrity": "sha1-2wa4tYW+lZotzS+H9HK6m3VvNnU=", - "dev": true, - "requires": { - "mdast-util-to-string": "^1.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.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.4.6", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.0-beta.4.6.tgz", + "integrity": "sha512-9oB4BiGDTI1FmIBlOF9OJ5hwJvcBEmPCqk/hy314Uhy2uq5TjekUZM8w8SPLLlUEM+mxNhXdPAXfrJN2Zbb/GQ==", + "dev": true, + "requires": { + "quick-lru": "^5.0.0", + "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 } - }, - "mdast-util-to-hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-3.0.4.tgz", - "integrity": "sha512-/eIbly2YmyVgpJNo+bFLLMCI1XgolO/Ffowhf+pHDq3X4/V6FntC9sGQCDLM147eTS+uSXv5dRzJyFn+o0tazA==", - "dev": true, - "requires": { - "collapse-white-space": "^1.0.0", - "detab": "^2.0.0", - "mdast-util-definitions": "^1.2.0", - "mdurl": "^1.0.1", - "trim": "0.0.1", - "trim-lines": "^1.0.0", - "unist-builder": "^1.0.1", - "unist-util-generated": "^1.1.0", - "unist-util-position": "^3.0.0", - "unist-util-visit": "^1.1.0", - "xtend": "^4.0.1" + } + }, + "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" + } + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", + "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "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" + } } - }, - "mdast-util-to-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.0.7.tgz", - "integrity": "sha512-P+gdtssCoHOX+eJUrrC30Sixqao86ZPlVjR5NEAoy0U79Pfxb1Y0Gntei0+GrnQD4T04X9xA8tcugp90cSmNow==", - "dev": true - }, - "mdast-util-toc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-toc/-/mdast-util-toc-3.1.0.tgz", - "integrity": "sha512-Za0hqL1PqWrvxGtA/3NH9D5nhGAUS9grMM4obEAz5+zsk1RIw/vWUchkaoDLNdrwk05A0CSC5eEXng36/1qE5w==", - "dev": true, - "requires": { - "github-slugger": "^1.2.1", - "mdast-util-to-string": "^1.0.5", - "unist-util-is": "^2.1.2", - "unist-util-visit": "^1.1.0" - }, - "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 - }, - "github-slugger": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.2.1.tgz", - "integrity": "sha512-SsZUjg/P03KPzQBt7OxJPasGw6NRO5uOgiZ5RGXVud5iSIZ0eNZeNp5rTwCxtavrRUa/A77j8mePVc5lEvk0KQ==", - "dev": true, - "requires": { - "emoji-regex": ">=6.0.0 <=6.1.1" - } - }, - "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 + } + }, + "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" } } - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.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": "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-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==" + }, + "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" + } } - }, - "memoizee": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.45", - "es6-weak-map": "^2.0.2", - "event-emitter": "^0.3.5", - "is-promise": "^2.1", - "lru-queue": "0.1", - "next-tick": "1", - "timers-ext": "^0.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==" + }, + "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 } - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + } + }, + "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-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-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==", + "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==", + "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" + } + }, + "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": { + "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": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + }, + "dependencies": { + "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 } - }, - "memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, - "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "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=", - "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=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } + } + }, + "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": { + "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": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + } + }, + "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": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.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 + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "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=", + "dev": true, + "optional": true, + "requires": { + "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" } } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "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==", - "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" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" + } + }, + "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==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "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" + } + }, + "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 + }, + "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 + }, + "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": { + "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" + } + }, + "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": { + "istanbul-lib-coverage": "^1.2.1", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" + } + }, + "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": { + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.2.1", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" + } + }, + "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": { + "handlebars": "^4.0.3" + } + }, + "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" + } + }, + "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" + } } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", - "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" - }, - "mime-types": { - "version": "2.1.25", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", - "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", - "requires": { - "mime-db": "1.42.0" + } + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "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": "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": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "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==", + "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 - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" + } + }, + "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": { + "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" + } } - }, - "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "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==", - "requires": { - "is-plain-object": "^2.0.4" - } + } + }, + "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": { + "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": "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 } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + }, + "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" + } + }, + "jake": { + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.1.tgz", + "integrity": "sha512-eSp5h9S7UFzKdQERTyF+KuPLjDZa1Tbw8gCVUn98n4PbIkLEDGe4zl7vF4Qge9kQj06HcymnksPk8jznPZeKsA==", + "dev": true, + "requires": { + "async": "0.9.x", + "chalk": "^2.4.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + } + }, + "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": { + "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/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 + }, + "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": { + "@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" + } + }, + "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-limit": { + "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==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "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" } } - }, - "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", - "dev": true, - "requires": { - "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.5", - "he": "1.1.1", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "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", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "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" - } - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } + } + }, + "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" + }, + "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": "*" } } - }, - "module-deps-sortable": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/module-deps-sortable/-/module-deps-sortable-4.0.6.tgz", - "integrity": "sha1-ElGkuixEqS32mJvQKdoSGk8hCbA=", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "browser-resolve": "^1.7.0", - "concat-stream": "~1.5.0", - "defined": "^1.0.0", - "detective": "^4.0.0", - "duplexer2": "^0.1.2", - "inherits": "^2.0.1", - "parents": "^1.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.3", - "stream-combiner2": "^1.1.1", - "subarg": "^1.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "concat-stream": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", - "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~2.0.0", - "typedarray": "~0.0.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } + } + }, + "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" + }, + "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" } } - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "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 } - } - }, - "moo-server": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/moo-server/-/moo-server-1.3.0.tgz", - "integrity": "sha1-XceVaVZaENbv7VQ5SR5p0jkuWPE=" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "dev": true, - "requires": { - "duplexer2": "0.0.2" - }, - "dependencies": { - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "requires": { - "readable-stream": "~1.1.9" + }, + "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" + } } - }, - "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.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + } + }, + "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" + } } - }, - "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 + } + }, + "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" } } - }, - "mute-stdout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" - }, - "ncp": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", - "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "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==" - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "nise": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.2.tgz", - "integrity": "sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==", - "dev": true, - "requires": { - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "lolex": "^4.1.0", - "path-to-regexp": "^1.7.0" - }, - "dependencies": { - "@sinonjs/formatio": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", - "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "lolex": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", - "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", - "dev": true - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "requires": { - "isarray": "0.0.1" - } + } + }, + "jest-diff": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz", + "integrity": "sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==", + "dev": true, + "requires": { + "chalk": "^3.0.0", + "diff-sequences": "^25.2.6", + "jest-get-type": "^25.2.6", + "pretty-format": "^25.5.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": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "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" } - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" - }, - "node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - }, - "dependencies": { - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + }, + "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" } } - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=" - }, - "node-notifier": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", - "requires": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - } - }, - "node-releases": { - "version": "1.1.42", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.42.tgz", - "integrity": "sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA==", - "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==", - "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-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": { + "@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" } } - }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "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" - } - }, - "now-and-later": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", - "requires": { - "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", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.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" + }, + "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": "*" + } } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" + } + }, + "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": "*" + } } - }, - "null-check": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", - "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", - "dev": true - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-component": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", - "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "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=", - "requires": { - "is-descriptor": "^0.1.0" + } + }, + "jest-get-type": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", + "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", + "dev": true + }, + "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": { + "@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": { + "@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": "*" + } + }, + "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" + } } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" + } + }, + "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" + } } } - } - }, - "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==", - "dev": true - }, - "object-is": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", - "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", - "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - }, - "dependencies": { - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "^1.0.1" + }, + "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 + }, + "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" + } } } - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" - } - }, - "object.reduce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "object.values": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", - "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.12.0", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "one-time": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", - "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "opener": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", - "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==", - "dev": true - }, - "opn": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", - "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "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" } } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "ordered-read-streams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", - "requires": { - "readable-stream": "^2.0.1" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - }, - "dependencies": { - "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, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + } + }, + "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, + "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" + } } - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.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" + } + }, + "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" + } } } - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "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==", - "dev": true - }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "requires": { - "p-reduce": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-is-promise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", - "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", - "dev": true - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "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==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=" - }, - "p-timeout": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", - "dev": true, - "requires": { - "p-finally": "^1.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pako": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", - "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", - "dev": true - }, - "parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", - "dev": true, - "requires": { - "path-platform": "~0.11.15" - } - }, - "parse-asn1": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", - "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", - "dev": true, - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-domain": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/parse-domain/-/parse-domain-2.3.4.tgz", - "integrity": "sha512-LlFJJVTry4DD3Xa76CsVNP6MIu3JZ8GXd5HEEp38KSDGBCVsnccagAJ5YLy7uEEabvwtauQEQPcvXWgUGkJbMA==", - "dev": true, - "requires": { - "got": "^8.3.2", - "jest": "^24.9.0", - "mkdirp": "^0.5.1", - "npm-run-all": "^4.1.5" - } - }, - "parse-entities": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", - "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==", - "dev": true, - "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - }, - "parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", - "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - } - }, - "parse-git-config": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-0.2.0.tgz", - "integrity": "sha1-Jygz/dFf6hRvt10zbSNrljtv9wY=", - "dev": true, - "requires": { - "ini": "^1.3.3" - } - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "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" + }, + "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" + } } } - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==" - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" - }, - "parse-path": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-3.0.4.tgz", - "integrity": "sha512-wP70vtwv2DyrM2YoA7ZHVv4zIXa4P7dGgHlj+VwyXNDduLLVJ7NMY1zsFxjUUJ3DAwJLupGb1H5gMDDiNlJaxw==", - "dev": true, - "requires": { - "is-ssh": "^1.3.0", - "protocols": "^1.4.0" - } - }, - "parse-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-3.0.2.tgz", - "integrity": "sha1-YCeHpwY6eV1yuGcxl1BecvYGEL4=", - "dev": true, - "requires": { - "is-ssh": "^1.3.0", - "normalize-url": "^1.9.1", - "parse-path": "^3.0.1", - "protocols": "^1.4.0" - } - }, - "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" - }, - "parseqs": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", - "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", - "dev": true, - "requires": { - "better-assert": "~1.0.0" - } - }, - "parseuri": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", - "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", - "dev": true, - "requires": { - "better-assert": "~1.0.0" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" - }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" - }, - "path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", - "dev": true - }, - "path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", - "requires": { - "path-root-regex": "^0.1.0" - } - }, - "path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "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==", - "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=" + }, + "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" } - } - }, - "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "dev": true - }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "requires": { - "through": "~2.3" - } - }, - "pbkdf2": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", - "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", - "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "pbkdf2-compat": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz", - "integrity": "sha1-tuDI+plJTZTgURV1gCpZpcFC8og=", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "pidtree": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", - "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "^2.0.0" - } - }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, - "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==", - "requires": { - "find-up": "^3.0.0" - } - }, - "plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", - "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - } - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "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==", - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - }, - "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==" + }, + "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" } - } - }, - "pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true - }, - "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==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "promised-io": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/promised-io/-/promised-io-0.3.5.tgz", - "integrity": "sha1-StIXuzZYvKrplGsXqGaOzYUeE1Y=" - }, - "prompts": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.0.tgz", - "integrity": "sha512-NfbbPPg/74fT7wk2XYQ7hAIp9zJyZp5Fu19iRbORqqy1BhtrkZ0fPafBU+7bmn8ie69DpT0R6QpJIN2oisYjJg==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.3" - } - }, - "property-information": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-3.2.0.tgz", - "integrity": "sha1-/RSDyPusYYCPX+NZ52k6H0ilgzE=", - "dev": true - }, - "protocols": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.7.tgz", - "integrity": "sha512-Fx65lf9/YDn3hUX08XUc0J8rSux36rEsyiv21ZGUC1mOyeM3lTRpZLcrm8aAolzS4itwVfm7TAPyxC2E5zd6xg==", - "dev": true - }, - "proxy-addr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", - "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.0" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true - }, - "ps-tree": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.1.tgz", - "integrity": "sha512-kef7fYYSKVqQffmzTMsVcUD1ObNJMp8sNSmHGlGKsZQyL/ht9MZKk86u0Rd1NhpTOAuhqwKCLLpktwkqz+MF8A==", - "dev": true, - "requires": { - "event-stream": "=3.3.4" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "psl": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", - "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==", - "dev": true - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } + }, + "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" + } + }, + "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" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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" } } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", - "dev": true - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "dev": true, - "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" + } + }, + "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" + }, + "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" + } } - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true - }, - "querystringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", - "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", - "dev": true - }, - "randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", - "dev": true, - "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.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==", - "dev": true + } + }, + "jest-matcher-utils": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-25.5.0.tgz", + "integrity": "sha512-VWI269+9JS5cpndnpCwm7dy7JtGQT30UHfrnM3mXl22gHGt/b7NkjBqXfbhZ8V4B7ANUsjK18PlSBmG0YH7gjw==", + "dev": true, + "requires": { + "chalk": "^3.0.0", + "jest-diff": "^25.5.0", + "jest-get-type": "^25.2.6", + "pretty-format": "^25.5.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": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "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" } } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" + } + }, + "jest-message-util": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-25.5.0.tgz", + "integrity": "sha512-ezddz3YCT/LT0SKAmylVyWWIGYoKHOFOFXx3/nA4m794lfVUskMcwhip6vTgdVrOtYdjeQeis2ypzes9mZb4EA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/types": "^25.5.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^3.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "slash": "^3.0.0", + "stack-utils": "^1.0.1" + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "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" + } } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.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" + }, + "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": "*" + } } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.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": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.2.6.tgz", + "integrity": "sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw==", + "dev": true + }, + "jest-resolve": { + "version": "24.9.0", + "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-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": "*" + } } - }, - "react-is": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", - "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", - "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=", - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.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" + }, + "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 } - }, - "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" - }, - "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" + } + }, + "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", + "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" + }, + "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" + } } - }, - "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" + } + }, + "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" + } } - }, - "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" + } + }, + "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" + } } - }, - "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.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "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==", - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "realpath-native": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", - "requires": { - "util.promisify": "^1.0.0" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "requires": { - "resolve": "^1.1.6" - } - }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - } - }, - "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", - "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", - "dev": true, - "requires": { - "regenerate": "^1.4.0" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "regenerator-transform": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", - "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", - "dev": true, - "requires": { - "private": "^0.1.6" - } - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexp.prototype.flags": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", - "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==", - "requires": { - "define-properties": "^1.1.2" - } - }, - "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", - "dev": true - }, - "regexpu-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", - "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.1.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - }, - "regjsgen": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", - "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", - "dev": true - }, - "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true + }, + "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" } - } - }, - "remark": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/remark/-/remark-9.0.0.tgz", - "integrity": "sha512-amw8rGdD5lHbMEakiEsllmkdBP+/KpjW/PRK6NSGPZKCQowh0BT4IWXDAkRMyG3SB9dKPXWMviFjNusXzXNn3A==", - "dev": true, - "requires": { - "remark-parse": "^5.0.0", - "remark-stringify": "^5.0.0", - "unified": "^6.0.0" - } - }, - "remark-html": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/remark-html/-/remark-html-7.0.0.tgz", - "integrity": "sha512-jqRzkZXCkM12gIY2ibMLTW41m7rfanliMTVQCFTezHJFsbH00YaTox/BX4gU+f/zCdzfhFJONtebFByvpMv37w==", - "dev": true, - "requires": { - "hast-util-sanitize": "^1.0.0", - "hast-util-to-html": "^3.0.0", - "mdast-util-to-hast": "^3.0.0", - "xtend": "^4.0.1" - } - }, - "remark-parse": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz", - "integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==", - "dev": true, - "requires": { - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^1.1.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^1.0.0", - "vfile-location": "^2.0.0", - "xtend": "^4.0.1" - } - }, - "remark-reference-links": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/remark-reference-links/-/remark-reference-links-4.0.4.tgz", - "integrity": "sha512-+2X8hwSQqxG4tvjYZNrTcEC+bXp8shQvwRGG6J/rnFTvBoU4G0BBviZoqKGZizLh/DG+0gSYhiDDWCqyxXW1iQ==", - "dev": true, - "requires": { - "unist-util-visit": "^1.0.0" - } - }, - "remark-slug": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/remark-slug/-/remark-slug-5.1.2.tgz", - "integrity": "sha512-DWX+Kd9iKycqyD+/B+gEFO3jjnt7Yg1O05lygYSNTe5i5PIxxxPjp5qPBDxPIzp5wreF7+1ROCwRgjEcqmzr3A==", - "dev": true, - "requires": { - "github-slugger": "^1.0.0", - "mdast-util-to-string": "^1.0.0", - "unist-util-visit": "^1.0.0" - } - }, - "remark-stringify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-5.0.0.tgz", - "integrity": "sha512-Ws5MdA69ftqQ/yhRF9XhVV29mhxbfGhbz0Rx5bQH+oJcNhhSM6nCu1EpLod+DjrFGrU0BMPs+czVmJZU7xiS7w==", - "dev": true, - "requires": { - "ccount": "^1.0.0", - "is-alphanumeric": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "longest-streak": "^2.0.1", - "markdown-escapes": "^1.0.0", - "markdown-table": "^1.1.0", - "mdast-util-compact": "^1.0.0", - "parse-entities": "^1.0.2", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "stringify-entities": "^1.0.1", - "unherit": "^1.0.4", - "xtend": "^4.0.1" - } - }, - "remark-toc": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/remark-toc/-/remark-toc-5.1.1.tgz", - "integrity": "sha512-vCPW4YOsm2CfyuScdktM9KDnJXVHJsd/ZeRtst+dnBU3B3KKvt8bc+bs5syJjyptAHfqo7H+5Uhz+2blWBfwow==", - "dev": true, - "requires": { - "mdast-util-toc": "^3.0.0", - "remark-slug": "^5.0.0" - } - }, - "remote-origin-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/remote-origin-url/-/remote-origin-url-0.4.0.tgz", - "integrity": "sha1-TT4pAvNOLTfRwmPYdxC3frQIajA=", - "dev": true, - "requires": { - "parse-git-config": "^0.2.0" - } - }, - "remove-bom-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", - "requires": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" - } - }, - "remove-bom-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", - "requires": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "replace-ext": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", - "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=" - }, - "replace-homedir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", - "requires": { - "homedir-polyfill": "^1.0.1", - "is-absolute": "^1.0.0", - "remove-trailing-separator": "^1.1.0" - } - }, - "replacestream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", - "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.3", - "object-assign": "^4.0.1", - "readable-stream": "^2.0.2" - } - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "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" } - } - }, - "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==", - "requires": { - "lodash": "^4.17.15" - } - }, - "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==", - "requires": { - "request-promise-core": "1.1.3", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "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==", + "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" } - } - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "resolve": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", - "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "requires": { - "resolve-from": "^3.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + }, + "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" } } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "resolve-options": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", - "requires": { - "value-or-function": "^3.0.0" - } - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" - }, - "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" - } - }, - "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, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" - }, - "rfdc": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", - "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", - "dev": true - }, - "rgb2hex": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.1.10.tgz", - "integrity": "sha512-vKz+kzolWbL3rke/xeTE2+6vHmZnNxGyDnaVW4OckntAIcc7DcZzWkQSfxMDwqHS8vhgySnIFyBUH7lIk6PxvQ==", - "dev": true - }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dev": true, - "requires": { - "align-text": "^0.1.1" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==" - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "dev": true, - "requires": { - "rx-lite": "*" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-json-parse": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", - "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" + } + }, + "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": { + "@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-limit": { + "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==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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" + } } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "samsam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", - "dev": true - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" + } + }, + "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": { + "@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" + } + }, + "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 + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "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" + } } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "schema-utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", - "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", - "dev": true, - "requires": { - "ajv": "^5.0.0" + } + }, + "jest-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "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": "*" + } + }, + "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 } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "semver-greatest-satisfied-range": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", - "requires": { - "sver-compat": "^1.5.0" + } + }, + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "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" + } } - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "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.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + }, + "jest-watcher": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "ansi-escapes": "^3.0.0", + "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 } - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "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" - } - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + } + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "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" } } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "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" + } } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^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=", - "requires": { - "is-extendable": "^0.1.0" - } + } + }, + "jsencrypt": { + "version": "3.0.0-rc.1", + "resolved": "https://registry.npmjs.org/jsencrypt/-/jsencrypt-3.0.0-rc.1.tgz", + "integrity": "sha512-gcvGaqerlUJy1Kq6tNgPYteVEoWNemu+9hBe2CdsCIz4rVcwjoTQ72iD1W76/PRMlnkzG0yVh7nwOOMOOUfKmg==" + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-buffer": { + "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": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", + "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "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 + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "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.5" + } + }, + "jsonfile": { + "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", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "just-clone": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-1.0.2.tgz", + "integrity": "sha1-v7P672WqEqMWBYcSlFwyb9jwFDQ=" + }, + "just-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", + "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=", + "dev": true + }, + "just-extend": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", + "dev": true + }, + "karma": { + "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": { + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "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 } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + } + }, + "karma-babel-preprocessor": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/karma-babel-preprocessor/-/karma-babel-preprocessor-6.0.1.tgz", + "integrity": "sha1-euHT5klQ2+EfQht0BAqwj7WmbCE=", + "dev": true, + "requires": { + "babel-core": "^6.0.0" + } + }, + "karma-browserstack-launcher": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-browserstack-launcher/-/karma-browserstack-launcher-1.4.0.tgz", + "integrity": "sha512-bUQK84U+euDfOUfEjcF4IareySMOBNRLrrl9q6cttIe8f011Ir6olLITTYMOJDcGY58wiFIdhPHSPd9Pi6+NfQ==", + "dev": true, + "requires": { + "browserstack": "~1.5.1", + "browserstacktunnel-wrapper": "~2.0.2", + "q": "~1.5.0" + } + }, + "karma-chai": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", + "integrity": "sha1-vuWtQEAFF4Ea40u5RfdikJEIt5o=", + "dev": true + }, + "karma-chrome-launcher": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", + "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "dev": true, + "requires": { + "fs-access": "^1.0.0", + "which": "^1.2.1" + } + }, + "karma-coverage": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.0.2.tgz", + "integrity": "sha512-zge5qiGEIKDdzWciQwP4p0LSac4k/L6VfrBsERMUn5mpDvxhv1sPVOrSlpzpi70T7NhuEy4bgnpAKIYuumIMCw==", + "dev": true, + "requires": { + "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" + } } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" + } + }, + "karma-coverage-istanbul-reporter": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.3.tgz", + "integrity": "sha1-O13/RmT6W41RlrmInj9hwforgNk=", + "dev": true, + "requires": { + "istanbul-api": "^1.3.1", + "minimatch": "^3.0.4" + } + }, + "karma-es5-shim": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/karma-es5-shim/-/karma-es5-shim-0.0.4.tgz", + "integrity": "sha1-zdADM8znfC5M4D46yT8vjs0fuVI=", + "dev": true, + "requires": { + "es5-shim": "^4.0.5" + } + }, + "karma-firefox-launcher": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-1.3.0.tgz", + "integrity": "sha512-Fi7xPhwrRgr+94BnHX0F5dCl1miIW4RHnzjIGxF8GaIEp7rNqX7LSi7ok63VXs3PS/5MQaQMhGxw+bvD+pibBQ==", + "dev": true, + "requires": { + "is-wsl": "^2.1.0" + } + }, + "karma-ie-launcher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/karma-ie-launcher/-/karma-ie-launcher-1.0.0.tgz", + "integrity": "sha1-SXmGhCxJAZA0bNifVJTKmDDG1Zw=", + "dev": true, + "requires": { + "lodash": "^4.6.1" + } + }, + "karma-mocha": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-1.3.0.tgz", + "integrity": "sha1-7qrH/8DiAetjxGdEDStpx883eL8=", + "dev": true, + "requires": { + "minimist": "1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "shell-quote": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", - "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", - "dev": true - }, - "shelljs": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", - "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" + } + }, + "karma-mocha-reporter": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz", + "integrity": "sha1-FRIAlejtgZGG5HoLAS8810GJVWA=", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "log-symbols": "^2.1.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 + }, + "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", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } } - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "requires": { - "is-arrayish": "^0.3.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + }, + "karma-opera-launcher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/karma-opera-launcher/-/karma-opera-launcher-1.0.0.tgz", + "integrity": "sha1-+lFihTGh0L6EstjcDX7iCfyP+Ro=", + "dev": true + }, + "karma-safari-launcher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/karma-safari-launcher/-/karma-safari-launcher-1.0.0.tgz", + "integrity": "sha1-lpgqLMR9BmquccVTursoMZEVos4=", + "dev": true + }, + "karma-script-launcher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/karma-script-launcher/-/karma-script-launcher-1.0.0.tgz", + "integrity": "sha1-zQF8TeXvCeWp2nkydhdhCN1LVC0=", + "dev": true + }, + "karma-sinon": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/karma-sinon/-/karma-sinon-1.0.5.tgz", + "integrity": "sha1-TjRD8oMP3s/2JNN0cWPxIX2qKpo=", + "dev": true + }, + "karma-sourcemap-loader": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.7.tgz", + "integrity": "sha1-kTIsd/jxPUb+0GKwQuEAnUxFBdg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "karma-spec-reporter": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.31.tgz", + "integrity": "sha1-SDDccUihVcfXoYbmMjOaDYD63sM=", + "dev": true, + "requires": { + "colors": "^1.1.2" + } + }, + "karma-webpack": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/karma-webpack/-/karma-webpack-3.0.5.tgz", + "integrity": "sha512-nRudGJWstvVuA6Tbju9tyGUfXTtI1UXMXoRHVmM2/78D0q6s/Ye2IC157PKNDC15PWFGR0mVIRtWLAdcfsRJoA==", + "dev": true, + "requires": { + "async": "^2.0.0", + "babel-runtime": "^6.0.0", + "loader-utils": "^1.0.0", + "lodash": "^4.0.0", + "source-map": "^0.5.6", + "webpack-dev-middleware": "^2.0.6" + }, + "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" } } - }, - "sinon": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz", - "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==", - "dev": true, - "requires": { - "@sinonjs/formatio": "^2.0.0", - "diff": "^3.1.0", - "lodash.get": "^4.4.2", - "lolex": "^2.2.0", - "nise": "^1.2.0", - "supports-color": "^5.1.0", - "type-detect": "^4.0.5" - }, - "dependencies": { - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true + } + }, + "kebab-case": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/kebab-case/-/kebab-case-1.0.0.tgz", + "integrity": "sha1-P55JkK3K0MaGwOcB92RYaPdfkes=", + "dev": true + }, + "keyv": { + "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.1" + } + }, + "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 + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "dev": true, + "requires": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "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" } } - }, - "sisteransi": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.4.tgz", - "integrity": "sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig==", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "lcov-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", + "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", + "dev": true + }, + "lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "dev": true, + "requires": { + "flush-write-stream": "^1.0.2" + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "requires": { + "leven": "^3.1.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dev": true, + "requires": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "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", + "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", + "dev": true + }, + "live-connect-js": { + "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.3", + "browser-cookies": "^1.2.0", + "tiny-hashes": "1.0.1" + } + }, + "livereload-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", + "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", + "dev": true + }, + "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" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "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" + }, + "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" + } } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "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=", - "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=", - "requires": { - "is-extendable": "^0.1.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" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basetostring": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", + "dev": true + }, + "lodash._basevalues": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", + "dev": true + }, + "lodash._escapehtmlchar": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz", + "integrity": "sha1-32fDu2t+jh6DGrSL+geVuSr+iZ0=", + "dev": true, + "requires": { + "lodash._htmlescapes": "~2.4.1" + } + }, + "lodash._escapestringchar": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.4.1.tgz", + "integrity": "sha1-7P4iYYoq3lC/7qQ5N+Ud9m8O23I=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._htmlescapes": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz", + "integrity": "sha1-MtFL8IRLbeb4tioFG09nwii2JMs=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash._isnative": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._isnative/-/lodash._isnative-2.4.1.tgz", + "integrity": "sha1-PqZAS3hKe+g2x7V1gOHN95sUgyw=", + "dev": true + }, + "lodash._objecttypes": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", + "integrity": "sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=", + "dev": true + }, + "lodash._reescape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", + "dev": true + }, + "lodash._reevaluate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", + "dev": true + }, + "lodash._reinterpolate": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz", + "integrity": "sha1-TxInqlqHEfxjL1sHofRgequLMiI=", + "dev": true + }, + "lodash._reunescapedhtml": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz", + "integrity": "sha1-dHxPxAED6zu4oJduVx96JlnpO6c=", + "dev": true, + "requires": { + "lodash._htmlescapes": "~2.4.1", + "lodash.keys": "~2.4.1" + } + }, + "lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "dev": true + }, + "lodash._shimkeys": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz", + "integrity": "sha1-bpzJZm/wgfC1psl4uD4kLmlJ0gM=", + "dev": true, + "requires": { + "lodash._objecttypes": "~2.4.1" + } + }, + "lodash.clone": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", + "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": "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", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.4.1.tgz", + "integrity": "sha1-LOEsXghNsKV92l5dHu659dF1o7Q=", + "dev": true, + "requires": { + "lodash._escapehtmlchar": "~2.4.1", + "lodash._reunescapedhtml": "~2.4.1", + "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", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.isobject": { + "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", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", + "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", + "dev": true, + "requires": { + "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" } } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^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=", - "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==", - "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==", - "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==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } + } + }, + "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", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "dev": true + }, + "lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "lodash.template": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-2.4.1.tgz", + "integrity": "sha1-nmEQB+32KRKal0qzxIuBez4c8g0=", + "dev": true, + "requires": { + "lodash._escapestringchar": "~2.4.1", + "lodash._reinterpolate": "~2.4.1", + "lodash.defaults": "~2.4.1", + "lodash.escape": "~2.4.1", + "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" } } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } + } + }, + "lodash.templatesettings": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz", + "integrity": "sha1-6nbHXRHrhtTb6JqDiTu4YZKaxpk=", + "dev": true, + "requires": { + "lodash._reinterpolate": "~2.4.1", + "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", + "integrity": "sha1-q/UUQ2s8twUAFieXjLzzCxKA7qQ=", + "dev": true, + "requires": { + "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", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", + "dev": true + }, + "log-symbols": { + "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.4.2" + } + }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "log4js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", + "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", + "dev": true, + "requires": { + "date-format": "^2.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.0", + "rfdc": "^1.1.4", + "streamroller": "^1.0.6" + }, + "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 } - }, - "socket.io": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", - "integrity": "sha1-oGnF/qvuPmshSnW0DOBlLhz7mYA=", - "dev": true, - "requires": { - "debug": "~3.1.0", - "engine.io": "~3.2.0", - "has-binary2": "~1.0.2", - "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.1.1", - "socket.io-parser": "~3.2.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "dev": true, - "requires": { - "ms": "2.0.0" + } + }, + "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", + "integrity": "sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A==", + "dev": true, + "requires": { + "es6-symbol": "^3.1.1", + "object.assign": "^4.1.0" + } + }, + "lolex": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", + "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "dev": true, + "requires": { + "es5-ext": "~0.10.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "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": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "make-error-cause": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz", + "integrity": "sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0=", + "dev": true, + "requires": { + "make-error": "^1.2.0" + } + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "markdown-escapes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", + "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", + "dev": true + }, + "markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "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", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "dev": true, + "requires": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "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" + } } } - } - }, - "socket.io-adapter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", - "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==", - "dev": true - }, - "socket.io-client": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", - "integrity": "sha1-3LOBA0NqtFeN2wJmOK4vIbYjZx8=", - "dev": true, - "requires": { - "backo2": "1.0.2", - "base64-arraybuffer": "0.1.5", - "component-bind": "1.0.0", - "component-emitter": "1.2.1", - "debug": "~3.1.0", - "engine.io-client": "~3.2.0", - "has-binary2": "~1.0.2", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "object-component": "0.0.3", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "socket.io-parser": "~3.2.0", - "to-array": "0.1.4" - }, - "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": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "dev": true, - "requires": { - "ms": "2.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" + } } } - } - }, - "socket.io-parser": { - "version": "3.2.0", - "resolved": "http://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", - "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", - "dev": true, - "requires": { - "component-emitter": "1.2.1", - "debug": "~3.1.0", - "isarray": "2.0.1" - }, - "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": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "dev": true, - "requires": { - "ms": "2.0.0" + }, + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "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", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "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" + } } - }, - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "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" + } + }, + "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" } } - }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" - }, - "space-separated-tokens": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.4.tgz", - "integrity": "sha512-UyhMSmeIqZrQn2UdjYpxEkwY9JUrn8pP+7L4f91zRzOQuI8MF1FGLfYU9DKCYeLdo7LXMxwrX5zKFy7eeeVHuA==", - "dev": true - }, - "sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==" - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==" - }, - "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==", - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" - }, - "split": { - "version": "0.3.3", - "resolved": "http://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", - "dev": true, - "requires": { - "through": "2" - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "requires": { - "extend-shallow": "^3.0.0" + } + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdast-util-compact": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz", + "integrity": "sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg==", + "dev": true, + "requires": { + "unist-util-visit": "^1.1.0" + } + }, + "mdast-util-definitions": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-1.2.5.tgz", + "integrity": "sha512-CJXEdoLfiISCDc2JB6QLb79pYfI6+GcIH+W2ox9nMc7od0Pz+bovcHsiq29xAQY6ayqe/9CsK2VzkSJdg1pFYA==", + "dev": true, + "requires": { + "unist-util-visit": "^1.0.0" + } + }, + "mdast-util-inject": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-inject/-/mdast-util-inject-1.1.0.tgz", + "integrity": "sha1-2wa4tYW+lZotzS+H9HK6m3VvNnU=", + "dev": true, + "requires": { + "mdast-util-to-string": "^1.0.0" + } + }, + "mdast-util-to-hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-3.0.4.tgz", + "integrity": "sha512-/eIbly2YmyVgpJNo+bFLLMCI1XgolO/Ffowhf+pHDq3X4/V6FntC9sGQCDLM147eTS+uSXv5dRzJyFn+o0tazA==", + "dev": true, + "requires": { + "collapse-white-space": "^1.0.0", + "detab": "^2.0.0", + "mdast-util-definitions": "^1.2.0", + "mdurl": "^1.0.1", + "trim": "0.0.1", + "trim-lines": "^1.0.0", + "unist-builder": "^1.0.1", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.0", + "xtend": "^4.0.1" + } + }, + "mdast-util-to-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz", + "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==", + "dev": true + }, + "mdast-util-toc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-toc/-/mdast-util-toc-3.1.0.tgz", + "integrity": "sha512-Za0hqL1PqWrvxGtA/3NH9D5nhGAUS9grMM4obEAz5+zsk1RIw/vWUchkaoDLNdrwk05A0CSC5eEXng36/1qE5w==", + "dev": true, + "requires": { + "github-slugger": "^1.2.1", + "mdast-util-to-string": "^1.0.5", + "unist-util-is": "^2.1.2", + "unist-util-visit": "^1.1.0" + }, + "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 + }, + "github-slugger": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.3.0.tgz", + "integrity": "sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q==", + "dev": true, + "requires": { + "emoji-regex": ">=6.0.0 <=6.1.1" + } + }, + "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 } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "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 } - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, - "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==" - }, - "state-toggle": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.2.tgz", - "integrity": "sha512-8LpelPGR0qQM4PnfLiplOQNJcIN1/r2Gy0xKB2zKnIW2YzPMt2sR4I/+gtPjhN7Svh9kw+zqEg2SFwpBO9iNiw==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "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=", - "requires": { - "is-descriptor": "^0.1.0" - } + } + }, + "memoizee": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", + "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.45", + "es6-weak-map": "^2.0.2", + "event-emitter": "^0.3.5", + "is-promise": "^2.1", + "lru-queue": "0.1", + "next-tick": "1", + "timers-ext": "^0.1.5" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "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" } } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" - }, - "stream-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/stream-array/-/stream-array-1.1.2.tgz", - "integrity": "sha1-nl9zRfITfDDuO0mLkRToC1K7frU=", - "dev": true, - "requires": { - "readable-stream": "~2.1.0" - }, - "dependencies": { - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "readable-stream": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", - "integrity": "sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA=", - "dev": true, - "requires": { - "buffer-shims": "^1.0.0", - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - }, - "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 + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "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": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" } } - }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "dev": true, - "requires": { - "duplexer": "~0.1.1" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "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 } - }, - "stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "dev": true, - "requires": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "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 } - }, - "stream-exhaust": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==" - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "dev": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "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.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-fn": { + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "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": { + "is-plain-object": "^2.0.4" + } } - }, - "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" - }, - "streamroller": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", - "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", - "dev": true, - "requires": { - "date-format": "^1.2.0", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "readable-stream": "^2.3.0" - }, - "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 + } + }, + "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" + } + }, + "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", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "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", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "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" + } + }, + "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", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" } } - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true - }, - "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", - "requires": { - "astral-regex": "^1.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=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" + } + }, + "module-deps-sortable": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/module-deps-sortable/-/module-deps-sortable-4.0.6.tgz", + "integrity": "sha1-ElGkuixEqS32mJvQKdoSGk8hCbA=", + "dev": true, + "requires": { + "JSONStream": "^1.0.3", + "browser-resolve": "^1.7.0", + "concat-stream": "~1.5.0", + "defined": "^1.0.0", + "detective": "^4.0.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.3", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", + "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~2.0.0", + "typedarray": "~0.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } } } - } - }, - "string-template": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", - "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==", - "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==" - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "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", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true } - }, - "string.prototype.padend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", - "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.4.3", - "function-bind": "^1.0.2" + } + }, + "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 } - }, - "string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multipipe": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "dev": true, + "requires": { + "duplexer2": "0.0.2" + }, + "dependencies": { + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "requires": { + "readable-stream": "~1.1.9" + } + }, + "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.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "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 } - }, - "string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + } + }, + "mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true + }, + "mute-stream": { + "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.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "ncp": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", + "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "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==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "nise": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", + "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", + "dev": true, + "requires": { + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^5.0.1", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "@sinonjs/formatio": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } } - }, - "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==", - "requires": { - "safe-buffer": "~5.1.0" + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "punycode": { + "version": "1.4.1", + "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" + } } - }, - "stringify-entities": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz", - "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==", - "dev": true, - "requires": { - "character-entities-html4": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-hexadecimal": "^1.0.0" + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.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 } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" + } + }, + "node-releases": { + "version": "1.1.58", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.58.tgz", + "integrity": "sha512-NxBudgVKiRh/2aPWMgPR7bPTX0VPmGx5QBwCtdHitnqFE5/O8DeBXuIMH1nwNnw/aMo6AjOrpsHzfY3UbUJ7yg==", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "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", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "requires": { + "once": "^1.3.2" + } + }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "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 } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - }, - "strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "null-check": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "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" + } + }, + "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" + } } - }, - "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 - }, - "subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", - "dev": true, - "requires": { - "minimist": "^1.1.0" + } + }, + "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==" + }, + "object-is": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", + "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "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==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "dev": true, + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "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", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "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": "^2.1.0" + } + }, + "opener": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", + "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==", + "dev": true + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "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 } - }, - "sver-compat": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", - "requires": { - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" - }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, - "requires": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.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 - }, - "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" - } + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "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" } } - }, - "tapable": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz", - "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==", - "dev": true - }, - "tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "dev": true, - "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - } - }, - "temp-fs": { - "version": "0.9.9", - "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz", - "integrity": "sha1-gHFzBDeHByDpQxUy/igUNk+IA9c=", - "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" - } + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + }, + "dependencies": { + "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, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } - } - }, - "ternary-stream": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-2.1.1.tgz", - "integrity": "sha512-j6ei9hxSoyGlqTmoMjOm+QNvUKDOIY6bNl4Uh1lhBvl6yjPW2iLqxDUYyfDPZknQ4KdRziFl+ec99iT4l7g0cw==", - "dev": true, - "requires": { - "duplexify": "^3.5.0", - "fork-stream": "^0.0.4", - "merge-stream": "^1.0.0", - "through2": "^2.0.1" - }, - "dependencies": { - "merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "dev": true, - "requires": { - "readable-stream": "^2.0.1" - } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.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" } + }, + "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 } - }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - }, - "dependencies": { - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-cancelable": { + "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": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "dev": 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, + "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-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "dev": true, + "requires": { + "p-finally": "^1.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 + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "dev": true, + "requires": { + "path-platform": "~0.11.15" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-domain": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/parse-domain/-/parse-domain-2.3.4.tgz", + "integrity": "sha512-LlFJJVTry4DD3Xa76CsVNP6MIu3JZ8GXd5HEEp38KSDGBCVsnccagAJ5YLy7uEEabvwtauQEQPcvXWgUGkJbMA==", + "dev": true, + "requires": { + "got": "^8.3.2", + "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 + }, + "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" + } } - }, - "text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "textextensions": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.6.0.tgz", - "integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==", - "dev": true - }, - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=" - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "through2-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", - "requires": { - "through2": "~2.0.0", - "xtend": "~4.0.0" + } + }, + "parse-entities": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", + "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==", + "dev": true, + "requires": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-git-config": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-0.2.0.tgz", + "integrity": "sha1-Jygz/dFf6hRvt10zbSNrljtv9wY=", + "dev": true, + "requires": { + "ini": "^1.3.3" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "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" + } } - }, - "time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" - }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true - }, - "timers-browserify": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", - "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" + } + }, + "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" + } + }, + "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", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parse-path": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-3.0.4.tgz", + "integrity": "sha512-wP70vtwv2DyrM2YoA7ZHVv4zIXa4P7dGgHlj+VwyXNDduLLVJ7NMY1zsFxjUUJ3DAwJLupGb1H5gMDDiNlJaxw==", + "dev": true, + "requires": { + "is-ssh": "^1.3.0", + "protocols": "^1.4.0" + } + }, + "parse-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-3.0.2.tgz", + "integrity": "sha1-YCeHpwY6eV1yuGcxl1BecvYGEL4=", + "dev": true, + "requires": { + "is-ssh": "^1.3.0", + "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" + } } - }, - "timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dev": true, - "requires": { - "es5-ext": "~0.10.46", - "next-tick": "1" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "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=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", + "dev": true + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "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" + } + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "dev": true, + "requires": { + "through": "~2.3" + } + }, + "pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-wHMFZ6HTLGlB9f/WsQBs5OwMQJoLXYuJUzbA+j+hRBf7+Y8KcXpatzIviIcTy1OAyhWQp08nyiPO8Dnv0z4Sww==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pbkdf2-compat": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz", + "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", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picomatch": { + "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.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "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" + }, + "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-limit": { + "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==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true } - }, - "timespan": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", - "integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=" - }, - "tiny-lr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", - "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", - "dev": true, - "requires": { - "body": "^5.1.0", - "debug": "^3.1.0", - "faye-websocket": "~0.10.0", - "livereload-js": "^2.3.0", - "object-assign": "^4.1.0", - "qs": "^6.4.0" - }, - "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 + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "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" } } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-format": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz", + "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==", + "dev": true, + "requires": { + "@jest/types": "^25.5.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.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 } - }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=" - }, - "to-absolute-glob": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", - "requires": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" + } + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "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", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "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 + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prompts": { + "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", + "sisteransi": "^1.0.4" + } + }, + "property-information": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-3.2.0.tgz", + "integrity": "sha1-/RSDyPusYYCPX+NZ52k6H0ilgzE=", + "dev": true + }, + "protocols": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.7.tgz", + "integrity": "sha512-Fx65lf9/YDn3hUX08XUc0J8rSux36rEsyiv21ZGUC1mOyeM3lTRpZLcrm8aAolzS4itwVfm7TAPyxC2E5zd6xg==", + "dev": true + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "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", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "ps-tree": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", + "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", + "dev": true, + "requires": { + "event-stream": "=3.3.4" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "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": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "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 } - }, - "to-array": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", - "dev": true - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "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", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "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=", - "requires": { - "is-buffer": "^1.1.5" - } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.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=", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "puppeteer-core": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-3.3.0.tgz", + "integrity": "sha512-hynQ3r0J/lkGrKeBCqu160jrj0WhthYLIzDQPkBxLzxPokjw4elk1sn6mXAian/kfD2NRzpdh9FSykxZyL56uA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "extract-zip": "^2.0.0", + "https-proxy-agent": "^4.0.0", + "mime": "^2.0.3", + "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" + } } - }, - "to-through": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", - "requires": { - "through2": "^2.0.3" + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "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", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dev": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.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==", + "dev": true } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "react-is": { + "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": "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" + }, + "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" + } + }, + "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" } } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "requires": { - "punycode": "^2.1.0" - } - }, - "trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", - "dev": true - }, - "trim-lines": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-1.1.2.tgz", - "integrity": "sha512-3GOuyNeTqk3FAqc3jOJtw7FTjYl94XBR5aD9QnDbK/T4CA9sW/J0l9RoaRPE9wyPP7NF331qnHnvJFBJ+IDkmQ==", - "dev": true - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, - "trim-trailing-lines": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.2.tgz", - "integrity": "sha512-MUjYItdrqqj2zpcHFTkMa9WAv4JHTI6gnRQGPFLrt5L9a6tRMiDnIqYl8JBvu2d2Tc3lWJKQwlGCp0K8AvCM+Q==", - "dev": true - }, - "triple-beam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", - "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" - }, - "trough": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.4.tgz", - "integrity": "sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==", - "dev": true - }, - "tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", - "dev": true - }, - "ts-jest": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.2.0.tgz", - "integrity": "sha512-Yc+HLyldlIC9iIK8xEN7tV960Or56N49MDP7hubCZUeI7EbIOTsas6rXCMB4kQjLACJ7eDOF4xWEO5qumpKsag==", - "requires": { - "bs-logger": "0.x", - "buffer-from": "1.x", - "fast-json-stable-stringify": "2.x", - "json5": "2.x", - "lodash.memoize": "4.x", - "make-error": "1.x", - "mkdirp": "0.x", - "resolve": "1.x", - "semver": "^5.5", - "yargs-parser": "10.x" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", - "requires": { - "camelcase": "^4.1.0" - } + } + }, + "readable-stream": { + "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": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "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": { + "picomatch": "^2.2.1" + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "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" } } - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regenerator-transform": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.4.tgz", + "integrity": "sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4", + "private": "^0.1.8" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp.prototype.flags": { + "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==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true + }, + "regexpu-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", + "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "~1.1.2" + } + }, + "remark": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark/-/remark-9.0.0.tgz", + "integrity": "sha512-amw8rGdD5lHbMEakiEsllmkdBP+/KpjW/PRK6NSGPZKCQowh0BT4IWXDAkRMyG3SB9dKPXWMviFjNusXzXNn3A==", + "dev": true, + "requires": { + "remark-parse": "^5.0.0", + "remark-stringify": "^5.0.0", + "unified": "^6.0.0" + } + }, + "remark-html": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/remark-html/-/remark-html-7.0.0.tgz", + "integrity": "sha512-jqRzkZXCkM12gIY2ibMLTW41m7rfanliMTVQCFTezHJFsbH00YaTox/BX4gU+f/zCdzfhFJONtebFByvpMv37w==", + "dev": true, + "requires": { + "hast-util-sanitize": "^1.0.0", + "hast-util-to-html": "^3.0.0", + "mdast-util-to-hast": "^3.0.0", + "xtend": "^4.0.1" + } + }, + "remark-parse": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz", + "integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==", + "dev": true, + "requires": { + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^1.1.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^1.0.0", + "vfile-location": "^2.0.0", + "xtend": "^4.0.1" + } + }, + "remark-reference-links": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/remark-reference-links/-/remark-reference-links-4.0.4.tgz", + "integrity": "sha512-+2X8hwSQqxG4tvjYZNrTcEC+bXp8shQvwRGG6J/rnFTvBoU4G0BBviZoqKGZizLh/DG+0gSYhiDDWCqyxXW1iQ==", + "dev": true, + "requires": { + "unist-util-visit": "^1.0.0" + } + }, + "remark-slug": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/remark-slug/-/remark-slug-5.1.2.tgz", + "integrity": "sha512-DWX+Kd9iKycqyD+/B+gEFO3jjnt7Yg1O05lygYSNTe5i5PIxxxPjp5qPBDxPIzp5wreF7+1ROCwRgjEcqmzr3A==", + "dev": true, + "requires": { + "github-slugger": "^1.0.0", + "mdast-util-to-string": "^1.0.0", + "unist-util-visit": "^1.0.0" + } + }, + "remark-stringify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-5.0.0.tgz", + "integrity": "sha512-Ws5MdA69ftqQ/yhRF9XhVV29mhxbfGhbz0Rx5bQH+oJcNhhSM6nCu1EpLod+DjrFGrU0BMPs+czVmJZU7xiS7w==", + "dev": true, + "requires": { + "ccount": "^1.0.0", + "is-alphanumeric": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "longest-streak": "^2.0.1", + "markdown-escapes": "^1.0.0", + "markdown-table": "^1.1.0", + "mdast-util-compact": "^1.0.0", + "parse-entities": "^1.0.2", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "stringify-entities": "^1.0.1", + "unherit": "^1.0.4", + "xtend": "^4.0.1" + } + }, + "remark-toc": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/remark-toc/-/remark-toc-5.1.1.tgz", + "integrity": "sha512-vCPW4YOsm2CfyuScdktM9KDnJXVHJsd/ZeRtst+dnBU3B3KKvt8bc+bs5syJjyptAHfqo7H+5Uhz+2blWBfwow==", + "dev": true, + "requires": { + "mdast-util-toc": "^3.0.0", + "remark-slug": "^5.0.0" + } + }, + "remote-origin-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/remote-origin-url/-/remote-origin-url-0.4.0.tgz", + "integrity": "sha1-TT4pAvNOLTfRwmPYdxC3frQIajA=", + "dev": true, + "requires": { + "parse-git-config": "^0.2.0" + } + }, + "remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "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": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "dev": true, + "requires": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, + "replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + } + }, + "replacestream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", + "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", + "dev": true, + "requires": { + "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" + } } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "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 } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "typescript": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz", - "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==" - }, - "typescript-compare": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", - "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==", - "requires": { - "typescript-logic": "^0.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "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==", + "dev": true, + "requires": { + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true } - }, - "typescript-logic": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz", - "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==" - }, - "typescript-tuple": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz", - "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==", - "requires": { - "typescript-compare": "^0.0.2" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "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", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true } - }, - "uglify-js": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.2.tgz", - "integrity": "sha512-uhRwZcANNWVLrxLfNFEdltoPNhECUR3lc+UdJoG9CBpMcSnKyWA94tc3eAujB1GcMY5Uwq8ZMp4qWpxWYDQmaA==", - "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==" - } + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "dev": true, + "requires": { + "value-or-function": "^3.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "responselike": { + "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": { + "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 } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true - }, - "uglifyjs-webpack-plugin": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", - "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", - "dev": true, - "requires": { - "source-map": "^0.5.6", - "uglify-js": "^2.8.29", - "webpack-sources": "^1.0.1" - }, - "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" + } + }, + "restore-cursor": { + "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": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rfdc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", + "dev": true + }, + "rgb2hex": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.0.tgz", + "integrity": "sha512-cHdNTwmTMPu/TpP1bJfdApd6MbD+Kzi4GNnM6h35mdFChhQPSi9cAI8J7DMn5kQDKX8NuBaQXAyo360Oa7tOEA==", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "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" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, + "run-async": { + "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", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "*" + } + }, + "rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "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", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-json-parse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", + "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "samsam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", + "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", + "dev": true + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "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" + } } - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "dev": true, - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.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" + } } - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "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" + } } - }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", - "dev": true - }, - "unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" - }, - "undertaker": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", - "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", - "requires": { - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "bach": "^1.0.0", - "collection-map": "^1.0.0", - "es6-weak-map": "^2.0.1", - "last-run": "^1.1.0", - "object.defaults": "^1.0.0", - "object.reduce": "^1.0.0", - "undertaker-registry": "^1.0.0" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "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": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "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" + } } - }, - "undertaker-registry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=" - }, - "unherit": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.2.tgz", - "integrity": "sha512-W3tMnpaMG7ZY6xe/moK04U9fBhi6wEiCYHUW5Mop/wQHf12+79EQGwxYejNdhEz2mkqkBlGwm7pxmgBKMVUj0w==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "xtend": "^4.0.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "dev": true, + "requires": { + "sver-compat": "^1.5.0" + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "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.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "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 } - }, - "unicode-match-property-value-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", - "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", - "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", - "dev": true - }, - "unified": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz", - "integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==", - "dev": true, - "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^1.1.0", - "trough": "^1.0.0", - "vfile": "^2.0.0", - "x-is-string": "^0.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "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" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true } - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^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" + } } - }, - "unique-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", - "requires": { - "json-stable-stringify-without-jsonify": "^1.0.1", - "through2-filter": "^3.0.0" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, + "shelljs": { + "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", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "sinon": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz", + "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==", + "dev": true, + "requires": { + "@sinonjs/formatio": "^2.0.0", + "diff": "^3.1.0", + "lodash.get": "^4.4.2", + "lolex": "^2.2.0", + "nise": "^1.2.0", + "supports-color": "^5.1.0", + "type-detect": "^4.0.5" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.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 } - }, - "unist-builder": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-1.0.4.tgz", - "integrity": "sha512-v6xbUPP7ILrT15fHGrNyHc1Xda8H3xVhP7/HAIotHOhVPjH5dCXA097C3Rry1Q2O+HbOLCao4hfPB+EYEjHgVg==", - "dev": true, - "requires": { - "object-assign": "^4.1.0" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "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" + } } - }, - "unist-util-generated": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.5.tgz", - "integrity": "sha512-1TC+NxQa4N9pNdayCYA1EGUOCAO0Le3fVp7Jzns6lnua/mYgwHo0tz5WUAfrdpNch1RZLHc61VZ1SDgrtNXLSw==", - "dev": true - }, - "unist-util-is": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", - "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==", - "dev": true - }, - "unist-util-position": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.0.4.tgz", - "integrity": "sha512-tWvIbV8goayTjobxDIr4zVTyG+Q7ragMSMeKC3xnPl9xzIc0+she8mxXLM3JVNDDsfARPbCd3XdzkyLdo7fF3g==", - "dev": true - }, - "unist-util-remove-position": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz", - "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==", - "dev": true, - "requires": { - "unist-util-visit": "^1.1.0" + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^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" + } + }, + "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" + } } - }, - "unist-util-stringify-position": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", - "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==", - "dev": true - }, - "unist-util-visit": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", - "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", - "dev": true, - "requires": { - "unist-util-visit-parents": "^2.0.0" + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } } - }, - "unist-util-visit-parents": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", - "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", - "dev": true, - "requires": { - "unist-util-is": "^3.0.0" + } + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "dev": true, + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "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" + } } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + }, + "socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==", + "dev": true + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "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" } } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "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" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "dev": true + }, + "sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true + }, + "spdx-correct": { + "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", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "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.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", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "dev": true, + "requires": { + "through": "2" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "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 + }, + "state-toggle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", + "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "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" } } - }, - "url-join": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", - "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", - "dev": true - }, - "url-parse": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", - "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "stream-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/stream-array/-/stream-array-1.1.2.tgz", + "integrity": "sha1-nl9zRfITfDDuO0mLkRToC1K7frU=", + "dev": true, + "requires": { + "readable-stream": "~2.1.0" + }, + "dependencies": { + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "readable-stream": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", + "integrity": "sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA=", + "dev": true, + "requires": { + "buffer-shims": "^1.0.0", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "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 } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - }, - "dependencies": { - "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 + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "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" } } - }, - "url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" - }, - "useragent": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", - "integrity": "sha1-IX+UOtVAyyEoZYqyP8lg9qiMmXI=", - "dev": true, - "requires": { - "lru-cache": "4.1.x", - "tmp": "0.0.x" + } + }, + "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", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "dev": true, + "requires": { + "duplexer": "~0.1.1" + } + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "dev": true, + "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" + } } - }, - "util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "dev": true, - "requires": { - "inherits": "2.0.3" + } + }, + "stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "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" + } } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "streamroller": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", + "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", + "dev": true, + "requires": { + "async": "^2.6.2", + "date-format": "^2.0.0", + "debug": "^3.2.6", + "fs-extra": "^7.0.1", + "lodash": "^4.17.14" + }, + "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" + } + }, + "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" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "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 + }, + "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 } - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" - }, - "v8flags": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", - "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", - "requires": { - "homedir-polyfill": "^1.0.1" + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.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 + }, + "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 + }, + "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" + } } - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + } + }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "dev": true + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.padend": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz", + "integrity": "sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "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==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "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==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "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" + } + }, + "stringify-entities": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz", + "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==", + "dev": true, + "requires": { + "character-entities-html4": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, + "strip-ansi": { + "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": "^5.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=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "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 + }, + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", + "dev": true, + "requires": { + "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", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "dev": true, + "requires": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "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 + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "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" + } } - }, - "value-or-function": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + } + }, + "tapable": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz", + "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": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz", + "integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==", + "dev": true, + "requires": { + "bl": "^4.0.1", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "temp-fs": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz", + "integrity": "sha1-gHFzBDeHByDpQxUy/igUNk+IA9c=", + "dev": true, + "requires": { + "rimraf": "~2.5.2" + } + }, + "ternary-stream": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-2.1.1.tgz", + "integrity": "sha512-j6ei9hxSoyGlqTmoMjOm+QNvUKDOIY6bNl4Uh1lhBvl6yjPW2iLqxDUYyfDPZknQ4KdRziFl+ec99iT4l7g0cw==", + "dev": true, + "requires": { + "duplexify": "^3.5.0", + "fork-stream": "^0.0.4", + "merge-stream": "^1.0.0", + "through2": "^2.0.1" + }, + "dependencies": { + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "dev": true, + "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" + } } - }, - "vfile": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz", - "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==", - "dev": true, - "requires": { - "is-buffer": "^1.1.4", - "replace-ext": "1.0.0", - "unist-util-stringify-position": "^1.0.0", - "vfile-message": "^1.0.0" + } + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "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-limit": { + "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==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "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": { + "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" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "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 } - }, - "vfile-location": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz", - "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==", - "dev": true - }, - "vfile-message": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz", - "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==", - "dev": true, - "requires": { - "unist-util-stringify-position": "^1.1.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "textextensions": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.6.0.tgz", + "integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==", + "dev": true + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "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" + } } - }, - "vfile-reporter": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/vfile-reporter/-/vfile-reporter-4.0.0.tgz", - "integrity": "sha1-6m8K4TQvSEFXOYXgX5QXNvJ96do=", - "dev": true, - "requires": { - "repeat-string": "^1.5.0", - "string-width": "^1.0.0", - "supports-color": "^4.1.0", - "unist-util-stringify-position": "^1.0.0", - "vfile-statistics": "^1.1.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 - }, - "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" - } - }, - "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" - } - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, - "requires": { - "has-flag": "^2.0.0" - } + } + }, + "through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, + "requires": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "tiny-hashes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tiny-hashes/-/tiny-hashes-1.0.1.tgz", + "integrity": "sha512-knIN5zj4fl7kW4EBU5sLP20DWUvi/rVouvJezV0UAym2DkQaqm365Nyc8F3QEiOvunNDMxR8UhcXd1d5g+Wg1g==" + }, + "tiny-lr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", + "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", + "dev": true, + "requires": { + "body": "^5.1.0", + "debug": "^3.1.0", + "faye-websocket": "~0.10.0", + "livereload-js": "^2.3.0", + "object-assign": "^4.1.0", + "qs": "^6.4.0" + }, + "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 + } + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "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" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "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" + } + }, + "to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "dev": true, + "requires": { + "through2": "^2.0.3" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "dev": true + }, + "trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", + "dev": true + }, + "trim-lines": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-1.1.3.tgz", + "integrity": "sha512-E0ZosSWYK2mkSu+KEtQ9/KqarVjA9HztOSX+9FDdNacRAq29RRV6ZQNgob3iuW8Htar9vAfEa6yyt5qBAHZDBA==", + "dev": true + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "trim-trailing-lines": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz", + "integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA==", + "dev": true + }, + "trough": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", + "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", + "dev": true + }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "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", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "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", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript-compare": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", + "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==", + "requires": { + "typescript-logic": "^0.0.0" + } + }, + "typescript-logic": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz", + "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==" + }, + "typescript-tuple": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz", + "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==", + "requires": { + "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.9.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", + "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", + "dev": true, + "requires": { + "commander": "~2.20.3" + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true + }, + "uglifyjs-webpack-plugin": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", + "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", + "dev": true, + "requires": { + "source-map": "^0.5.6", + "uglify-js": "^2.8.29", + "webpack-sources": "^1.0.1" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + } + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" } } - }, - "vfile-sort": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vfile-sort/-/vfile-sort-2.2.1.tgz", - "integrity": "sha512-5dt7xEhC44h0uRQKhbM2JAe0z/naHphIZlMOygtMBM9Nn0pZdaX5fshhwWit9wvsuP8t/wp43nTDRRErO1WK8g==", - "dev": true - }, - "vfile-statistics": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/vfile-statistics/-/vfile-statistics-1.1.3.tgz", - "integrity": "sha512-CstaK/ebTz1W3Qp41Bt9Lj/2DmumFsCwC2sKahDNSPh0mPh7/UyMLCoU8ZBX34CRU0d61B4W41yIFsV0NKMZeA==", - "dev": true - }, - "vinyl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", - "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - }, - "vinyl-fs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", - "requires": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", - "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" - } - }, - "vinyl-sourcemap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", - "requires": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.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=", - "requires": { - "remove-trailing-separator": "^1.0.1" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "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", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true + }, + "undertaker": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", + "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + } + }, + "undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "dev": true + }, + "unherit": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", + "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", + "dev": true, + "requires": { + "inherits": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true + }, + "unified": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz", + "integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==", + "dev": true, + "requires": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^1.1.0", + "trough": "^1.0.0", + "vfile": "^2.0.0", + "x-is-string": "^0.1.0" + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "requires": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "unist-builder": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-1.0.4.tgz", + "integrity": "sha512-v6xbUPP7ILrT15fHGrNyHc1Xda8H3xVhP7/HAIotHOhVPjH5dCXA097C3Rry1Q2O+HbOLCao4hfPB+EYEjHgVg==", + "dev": true, + "requires": { + "object-assign": "^4.1.0" + } + }, + "unist-util-generated": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.5.tgz", + "integrity": "sha512-1TC+NxQa4N9pNdayCYA1EGUOCAO0Le3fVp7Jzns6lnua/mYgwHo0tz5WUAfrdpNch1RZLHc61VZ1SDgrtNXLSw==", + "dev": true + }, + "unist-util-is": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", + "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==", + "dev": true + }, + "unist-util-position": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", + "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==", + "dev": true + }, + "unist-util-remove-position": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz", + "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==", + "dev": true, + "requires": { + "unist-util-visit": "^1.1.0" + } + }, + "unist-util-stringify-position": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", + "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==", + "dev": true + }, + "unist-util-visit": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", + "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", + "dev": true, + "requires": { + "unist-util-visit-parents": "^2.0.0" + } + }, + "unist-util-visit-parents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", + "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", + "dev": true, + "requires": { + "unist-util-is": "^3.0.0" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "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" + } } } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true } - }, - "vinyl-sourcemaps-apply": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", - "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", - "requires": { - "source-map": "^0.5.1" - } - }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "dev": true - }, - "void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", - "dev": true - }, - "w3c-hr-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", - "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", - "requires": { - "browser-process-hrtime": "^0.1.2" - } - }, - "walk": { - "version": "2.3.14", - "resolved": "https://registry.npmjs.org/walk/-/walk-2.3.14.tgz", - "integrity": "sha512-5skcWAUmySj6hkBdH6B6+3ddMjVQYH5Qy9QGbPmN8kVmLteXk+yVXg+yfk1nbX30EYakahLrr8iPcCxJQSCBeg==", - "dev": true, - "requires": { - "foreachasync": "^3.0.0" + } + }, + "unzipper": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.9.15.tgz", + "integrity": "sha512-2aaUvO4RAeHDvOCuEtth7jrHFaCKTSXPqUkXwADaLBzGbgZGzUDccoEdJ5lW+3RmfpOZYNx0Rw6F6PUzM6caIA==", + "dev": true, + "requires": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + }, + "dependencies": { + "bluebird": { + "version": "3.4.7", + "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" + } } - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "requires": { - "makeerror": "1.0.x" + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true } - }, - "watchpack": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", - "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", - "dev": true, - "requires": { - "chokidar": "^2.0.2", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" + } + }, + "url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + }, + "dependencies": { + "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 } - }, - "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" + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "useragent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", + "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", + "dev": true, + "requires": { + "lru-cache": "4.1.x", + "tmp": "0.0.x" + } + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz", + "integrity": "sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==", + "dev": true + }, + "v8flags": { + "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" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vfile": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz", + "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==", + "dev": true, + "requires": { + "is-buffer": "^1.1.4", + "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 } - }, - "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==", - "dev": true, - "requires": { - "babel-runtime": "^6.23.0", - "mocha": "^5.2.0", - "wdio-sync": "0.7.3" + } + }, + "vfile-location": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz", + "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==", + "dev": true + }, + "vfile-message": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz", + "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==", + "dev": true, + "requires": { + "unist-util-stringify-position": "^1.1.1" + } + }, + "vfile-reporter": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vfile-reporter/-/vfile-reporter-4.0.0.tgz", + "integrity": "sha1-6m8K4TQvSEFXOYXgX5QXNvJ96do=", + "dev": true, + "requires": { + "repeat-string": "^1.5.0", + "string-width": "^1.0.0", + "supports-color": "^4.1.0", + "unist-util-stringify-position": "^1.0.0", + "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", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "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" + } + }, + "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" + } + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } } - }, - "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==", - "dev": true, - "requires": { - "babel-runtime": "~6.26.0", - "chalk": "^2.3.0", - "humanize-duration": "~3.15.0" + } + }, + "vfile-sort": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/vfile-sort/-/vfile-sort-2.2.2.tgz", + "integrity": "sha512-tAyUqD2R1l/7Rn7ixdGkhXLD3zsg+XLAeUDUhXearjfIcpL1Hcsj5hHpCoy/gvfK/Ws61+e972fm0F7up7hfYA==", + "dev": true + }, + "vfile-statistics": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/vfile-statistics/-/vfile-statistics-1.1.4.tgz", + "integrity": "sha512-lXhElVO0Rq3frgPvFBwahmed3X03vjPF8OcjKMy8+F1xU/3Q3QU3tKEDp743SFtb74PdF0UWpxPvtOP0GCLheA==", + "dev": true + }, + "vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "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 } - }, - "wdio-sync": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/wdio-sync/-/wdio-sync-0.7.3.tgz", - "integrity": "sha512-ukASSHOQmOxaz5HTILR0jykqlHBtAPsBpMtwhpiG0aW9uc7SO7PF+E5LhVvTG4ypAh+UGmY3rTjohOsqDr39jw==", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "fibers": "^3.0.0", - "object.assign": "^4.0.3" + } + }, + "vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "requires": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "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" + } } - }, - "webdriverio": { - "version": "4.14.4", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-4.14.4.tgz", - "integrity": "sha512-Knp2vzuzP5c5ybgLu+zTwy/l1Gh0bRP4zAr8NWcrStbuomm9Krn9oRF0rZucT6AyORpXinETzmeowFwIoo7mNA==", - "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", - "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" - } + } + }, + "vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "dev": true, + "requires": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.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=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" } } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" - }, - "webpack": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.12.0.tgz", - "integrity": "sha512-Sw7MdIIOv/nkzPzee4o0EdvCuPmxT98+vVpIvwtcwcF1Q4SDSNp92vwcKc4REe7NItH9f1S4ra9FuQ7yuYZ8bQ==", - "dev": true, - "requires": { - "acorn": "^5.0.0", - "acorn-dynamic-import": "^2.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "async": "^2.1.2", - "enhanced-resolve": "^3.4.0", - "escope": "^3.6.0", - "interpret": "^1.0.0", - "json-loader": "^0.5.4", - "json5": "^0.5.1", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "mkdirp": "~0.5.0", - "node-libs-browser": "^2.0.0", - "source-map": "^0.5.3", - "supports-color": "^4.2.1", - "tapable": "^0.2.7", - "uglifyjs-webpack-plugin": "^0.4.6", - "watchpack": "^1.4.0", - "webpack-sources": "^1.0.1", - "yargs": "^8.0.2" - }, - "dependencies": { - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "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=", - "dev": true - }, - "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" - } - }, - "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" - } + } + }, + "vinyl-sourcemaps-apply": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "dev": true, + "requires": { + "source-map": "^0.5.1" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "walk": { + "version": "2.3.14", + "resolved": "https://registry.npmjs.org/walk/-/walk-2.3.14.tgz", + "integrity": "sha512-5skcWAUmySj6hkBdH6B6+3ddMjVQYH5Qy9QGbPmN8kVmLteXk+yVXg+yfk1nbX30EYakahLrr8iPcCxJQSCBeg==", + "dev": true, + "requires": { + "foreachasync": "^3.0.0" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "watchpack": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.2.tgz", + "integrity": "sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g==", + "dev": true, + "requires": { + "chokidar": "^3.4.0", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.0" + } + }, + "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": { + "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" } } - }, - "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 - }, - "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 - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "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" - } - }, - "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", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": 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, - "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" + } + }, + "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" + } } - }, - "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" + } + }, + "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" + } } - }, - "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" + } + }, + "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" + } } - }, - "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" - } + } + }, + "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" } } - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, - "requires": { - "has-flag": "^2.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, + "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" + } + } + } + }, + "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": { + "defaults": "^1.0.3" + } + }, + "webdriver": { + "version": "6.1.14", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-6.1.14.tgz", + "integrity": "sha512-6fXoGDnxWfJn9zqfYbc6+VEV5N1obd3K7iuRmJ7w/hH9d9XDxcrcx147T5egiy1qziko61hqYE/x9VtSQbjPcA==", + "dev": true, + "requires": { + "@wdio/config": "6.1.14", + "@wdio/logger": "6.0.16", + "@wdio/protocols": "6.1.14", + "@wdio/utils": "6.1.8", + "got": "^11.0.2", + "lodash.merge": "^4.6.1" + } + }, + "webdriverio": { + "version": "6.1.16", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-6.1.16.tgz", + "integrity": "sha512-vk6/XeErNnMooebCtxwIR//LqrastXO9gXL+eVUGNRAuG5omp8XCdT+MK2fmlw53xhcPULQ/y3h8ysYlPnPeyA==", + "dev": true, + "requires": { + "@wdio/config": "6.1.14", + "@wdio/logger": "6.0.16", + "@wdio/repl": "6.1.8", + "@wdio/utils": "6.1.8", + "archiver": "^4.0.1", + "css-value": "^0.0.1", + "devtools": "6.1.16", + "grapheme-splitter": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "lodash.isobject": "^3.0.2", + "lodash.isplainobject": "^4.0.6", + "lodash.zip": "^4.2.0", + "resq": "^1.6.0", + "rgb2hex": "^0.2.0", + "serialize-error": "^7.0.0", + "webdriver": "6.1.14" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "webpack": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.12.0.tgz", + "integrity": "sha512-Sw7MdIIOv/nkzPzee4o0EdvCuPmxT98+vVpIvwtcwcF1Q4SDSNp92vwcKc4REe7NItH9f1S4ra9FuQ7yuYZ8bQ==", + "dev": true, + "requires": { + "acorn": "^5.0.0", + "acorn-dynamic-import": "^2.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "async": "^2.1.2", + "enhanced-resolve": "^3.4.0", + "escope": "^3.6.0", + "interpret": "^1.0.0", + "json-loader": "^0.5.4", + "json5": "^0.5.1", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "mkdirp": "~0.5.0", + "node-libs-browser": "^2.0.0", + "source-map": "^0.5.3", + "supports-color": "^4.2.1", + "tapable": "^0.2.7", + "uglifyjs-webpack-plugin": "^0.4.6", + "watchpack": "^1.4.0", + "webpack-sources": "^1.0.1", + "yargs": "^8.0.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "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" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "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" + } + }, + "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" + } } - }, - "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" + } + }, + "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 + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "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" + } + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": 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, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.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" + } + }, + "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" + } + }, + "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 }, - "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" - } + "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" } } - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true - }, - "yargs": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", - "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", - "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" - } - }, - "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" + } + }, + "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", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "^2.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": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "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" + } + }, + "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" + } } - }, - "webpack-bundle-analyzer": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.6.0.tgz", - "integrity": "sha512-orUfvVYEfBMDXgEKAKVvab5iQ2wXneIEorGNsyuOyVYpjYrI7CUOhhXNDd3huMwQ3vNNWWlGP+hzflMFYNzi2g==", - "dev": true, - "requires": { - "acorn": "^6.0.7", - "acorn-walk": "^6.1.1", - "bfj": "^6.1.1", - "chalk": "^2.4.1", - "commander": "^2.18.0", - "ejs": "^2.6.1", - "express": "^4.16.3", - "filesize": "^3.6.1", - "gzip-size": "^5.0.0", - "lodash": "^4.17.15", - "mkdirp": "^0.5.1", - "opener": "^1.5.1", - "ws": "^6.0.0" - }, - "dependencies": { - "acorn": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", - "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==", - "dev": true - }, - "ejs": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", - "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", - "dev": true - }, - "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" + } + }, + "webpack-bundle-analyzer": { + "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", + "acorn-walk": "^7.1.1", + "bfj": "^6.1.1", + "chalk": "^2.4.1", + "commander": "^2.18.0", + "ejs": "^2.6.1", + "express": "^4.16.3", + "filesize": "^3.6.1", + "gzip-size": "^5.0.0", + "lodash": "^4.17.15", + "mkdirp": "^0.5.1", + "opener": "^1.5.1", + "ws": "^6.0.0" + }, + "dependencies": { + "acorn": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", + "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", + "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==", + "dev": true + }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", + "dev": true + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "webpack-core": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz", + "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=", + "dev": true, + "requires": { + "source-list-map": "~0.1.7", + "source-map": "~0.4.1" + }, + "dependencies": { + "source-list-map": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz", + "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "webpack-dev-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-2.0.6.tgz", + "integrity": "sha512-tj5LLD9r4tDuRIDa5Mu9lnY2qBBehAITv6A9irqXhw/HQquZgTx3BCd57zYbU2gMDnncA49ufK2qVQSbaKJwOw==", + "dev": true, + "requires": { + "loud-rejection": "^1.6.0", + "memory-fs": "~0.4.1", + "mime": "^2.1.0", + "path-is-absolute": "^1.0.0", + "range-parser": "^1.0.3", + "url-join": "^2.0.2", + "webpack-log": "^1.0.1" + }, + "dependencies": { + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "dev": true + } + } + }, + "webpack-log": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-1.2.0.tgz", + "integrity": "sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA==", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "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": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "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 + } + } + }, + "webpack-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/webpack-stream/-/webpack-stream-3.2.0.tgz", + "integrity": "sha1-Oh0WD7EdQXJ7fObzL3IkZPmLIYY=", + "dev": true, + "requires": { + "gulp-util": "^3.0.7", + "lodash.clone": "^4.3.2", + "lodash.some": "^4.2.2", + "memory-fs": "^0.3.0", + "through": "^2.3.8", + "vinyl": "^1.1.0", + "webpack": "^1.12.9" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "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", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "browserify-aes": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-0.4.0.tgz", + "integrity": "sha1-BnFJtmjfMcS1hTPgLQHoBthgjiw=", + "dev": true, + "requires": { + "inherits": "^2.0.1" + } + }, + "browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", + "dev": true, + "requires": { + "pako": "~0.2.0" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "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 + }, + "crypto-browserify": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.3.0.tgz", + "integrity": "sha1-ufx1u0oO1h3PHNXa6W6zDJw+UGw=", + "dev": true, + "requires": { + "browserify-aes": "0.4.0", + "pbkdf2-compat": "2.0.1", + "ripemd160": "0.2.0", + "sha.js": "2.2.6" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "enhanced-resolve": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", + "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.2.0", + "tapable": "^0.1.8" + }, + "dependencies": { + "memory-fs": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz", + "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", + "dev": true } } - } - }, - "webpack-core": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz", - "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=", - "dev": true, - "requires": { - "source-list-map": "~0.1.7", - "source-map": "~0.4.1" - }, - "dependencies": { - "source-list-map": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz", - "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=", - "dev": true - }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "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" + } } } - } - }, - "webpack-dev-middleware": { - "version": "2.0.6", - "resolved": "http://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-2.0.6.tgz", - "integrity": "sha512-tj5LLD9r4tDuRIDa5Mu9lnY2qBBehAITv6A9irqXhw/HQquZgTx3BCd57zYbU2gMDnncA49ufK2qVQSbaKJwOw==", - "dev": true, - "requires": { - "loud-rejection": "^1.6.0", - "memory-fs": "~0.4.1", - "mime": "^2.1.0", - "path-is-absolute": "^1.0.0", - "range-parser": "^1.0.3", - "url-join": "^2.0.2", - "webpack-log": "^1.0.1" - }, - "dependencies": { - "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", - "dev": true + }, + "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" } - } - }, - "webpack-log": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-1.2.0.tgz", - "integrity": "sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA==", - "dev": true, - "requires": { - "chalk": "^2.1.0", - "log-symbols": "^2.1.0", - "loglevelnext": "^1.0.1", - "uuid": "^3.1.0" - } - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "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 + }, + "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" } - } - }, - "webpack-stream": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/webpack-stream/-/webpack-stream-3.2.0.tgz", - "integrity": "sha1-Oh0WD7EdQXJ7fObzL3IkZPmLIYY=", - "dev": true, - "requires": { - "gulp-util": "^3.0.7", - "lodash.clone": "^4.3.2", - "lodash.some": "^4.2.2", - "memory-fs": "^0.3.0", - "through": "^2.3.8", - "vinyl": "^1.1.0", - "webpack": "^1.12.9" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - }, - "anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", - "dev": true, - "requires": { - "micromatch": "^2.1.5", - "normalize-path": "^2.0.0" - } - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "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 - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "browserify-aes": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-0.4.0.tgz", - "integrity": "sha1-BnFJtmjfMcS1hTPgLQHoBthgjiw=", - "dev": true, - "requires": { - "inherits": "^2.0.1" - } - }, - "browserify-zlib": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", - "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", - "dev": true, - "requires": { - "pako": "~0.2.0" - } - }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.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 + }, + "https-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", + "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=", + "dev": true + }, + "interpret": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-0.6.6.tgz", + "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 } - }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true - }, - "chokidar": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", - "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", - "dev": true, - "requires": { - "anymatch": "^1.3.0", - "async-each": "^1.0.0", - "fsevents": "^1.0.0", - "glob-parent": "^2.0.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^2.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.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-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 } - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" + } + }, + "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 } - }, - "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 - }, - "crypto-browserify": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.3.0.tgz", - "integrity": "sha1-ufx1u0oO1h3PHNXa6W6zDJw+UGw=", - "dev": true, - "requires": { - "browserify-aes": "0.4.0", - "pbkdf2-compat": "2.0.1", - "ripemd160": "0.2.0", - "sha.js": "2.2.6" + } + }, + "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" + } + }, + "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", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "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" + } + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + }, + "memory-fs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.3.0.tgz", + "integrity": "sha1-e8xrYp46Q+hx1+Kaymrop/FcuyA=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "node-libs-browser": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-0.7.0.tgz", + "integrity": "sha1-PicsCBnjCJNeJmdECNevDhSRuDs=", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.1.4", + "buffer": "^4.9.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "3.3.0", + "domain-browser": "^1.1.1", + "events": "^1.0.0", + "https-browserify": "0.0.1", + "os-browserify": "^0.2.0", + "path-browserify": "0.0.0", + "process": "^0.11.0", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.0.5", + "stream-browserify": "^2.0.1", + "stream-http": "^2.3.1", + "string_decoder": "^0.10.25", + "timers-browserify": "^2.0.2", + "tty-browserify": "0.0.0", + "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 } - }, - "enhanced-resolve": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", - "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.2.0", - "tapable": "^0.1.8" + } + }, + "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" + } + }, + "os-browserify": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz", + "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=", + "dev": true + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "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" + } + }, + "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 }, - "dependencies": { - "memory-fs": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz", - "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", - "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" + } + } } - } - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "dev": true - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^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" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.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==", - "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" - } - }, - "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" - } - }, - "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 - }, - "https-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", - "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=", - "dev": true - }, - "interpret": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-0.6.6.tgz", - "integrity": "sha1-/s16GOfOXKar+5U+H4YhOknxYls=", - "dev": true - }, - "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" - } - }, - "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" - } - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "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" - } - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "dev": true, - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" - } - }, - "memory-fs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.3.0.tgz", - "integrity": "sha1-e8xrYp46Q+hx1+Kaymrop/FcuyA=", - "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "node-libs-browser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-0.7.0.tgz", - "integrity": "sha1-PicsCBnjCJNeJmdECNevDhSRuDs=", - "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.1.4", - "buffer": "^4.9.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "3.3.0", - "domain-browser": "^1.1.1", - "events": "^1.0.0", - "https-browserify": "0.0.1", - "os-browserify": "^0.2.0", - "path-browserify": "0.0.0", - "process": "^0.11.0", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.0.5", - "stream-browserify": "^2.0.1", - "stream-http": "^2.3.1", - "string_decoder": "^0.10.25", - "timers-browserify": "^2.0.2", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.10.3", - "vm-browserify": "0.0.4" - } - }, - "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" - } - }, - "os-browserify": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz", - "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=", - "dev": true - }, - "pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", - "dev": true - }, - "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", - "dev": true - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "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 - }, - "ripemd160": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-0.2.0.tgz", - "integrity": "sha1-K/GYveFnys+lHAqSjoS2i74XH84=", - "dev": true - }, - "sha.js": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.2.6.tgz", - "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", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - }, - "tapable": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz", - "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=", - "dev": true - }, - "uglify-js": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz", - "integrity": "sha1-RhLAx7qu4rp8SH3kkErhIgefLKg=", - "dev": true, - "requires": { - "async": "~0.2.6", - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" }, - "dependencies": { - "async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", - "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": { + "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 + } } - } - }, - "util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } - }, - "watchpack": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-0.2.9.tgz", - "integrity": "sha1-Yuqkq15bo1/fwBgnVibjwPXj+ws=", - "dev": true, - "requires": { - "async": "^0.9.0", - "chokidar": "^1.0.0", - "graceful-fs": "^4.1.2" }, - "dependencies": { - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", - "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" } } - }, - "webpack": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-1.15.0.tgz", - "integrity": "sha1-T/MfU9sDM55VFkqdRo7gMklo/pg=", - "dev": true, - "requires": { - "acorn": "^3.0.0", - "async": "^1.3.0", - "clone": "^1.0.2", - "enhanced-resolve": "~0.9.0", - "interpret": "^0.6.4", - "loader-utils": "^0.2.11", - "memory-fs": "~0.3.0", - "mkdirp": "~0.5.0", - "node-libs-browser": "^0.7.0", - "optimist": "~0.6.0", - "supports-color": "^3.1.0", - "tapable": "~0.1.8", - "uglify-js": "~2.7.3", - "watchpack": "^0.2.1", - "webpack-core": "~0.6.9" - } - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" + } + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "dev": true + }, + "ripemd160": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-0.2.0.tgz", + "integrity": "sha1-K/GYveFnys+lHAqSjoS2i74XH84=", + "dev": true + }, + "sha.js": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.2.6.tgz", + "integrity": "sha1-F93t3F9yL7ZlAWWIlUYZd4ZzFbo=", + "dev": true + }, + "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" + } + }, + "tapable": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz", + "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", + "integrity": "sha1-RhLAx7qu4rp8SH3kkErhIgefLKg=", + "dev": true, + "requires": { + "async": "~0.2.6", + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true } } - } - }, - "websocket-driver": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", - "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", - "dev": true, - "requires": { - "http-parser-js": ">=0.4.0 <0.4.11", - "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=", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" - }, - "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" - }, - "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==", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.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==" - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "dev": true, + "requires": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "watchpack": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-0.2.9.tgz", + "integrity": "sha1-Yuqkq15bo1/fwBgnVibjwPXj+ws=", + "dev": true, + "requires": { + "async": "^0.9.0", + "chokidar": "^1.0.0", + "graceful-fs": "^4.1.2" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true } } + }, + "webpack": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-1.15.0.tgz", + "integrity": "sha1-T/MfU9sDM55VFkqdRo7gMklo/pg=", + "dev": true, + "requires": { + "acorn": "^3.0.0", + "async": "^1.3.0", + "clone": "^1.0.2", + "enhanced-resolve": "~0.9.0", + "interpret": "^0.6.4", + "loader-utils": "^0.2.11", + "memory-fs": "~0.3.0", + "mkdirp": "~0.5.0", + "node-libs-browser": "^0.7.0", + "optimist": "~0.6.0", + "supports-color": "^3.1.0", + "tapable": "~0.1.8", + "uglify-js": "~2.7.3", + "watchpack": "^0.2.1", + "webpack-core": "~0.6.9" + } + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "wrench": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/wrench/-/wrench-1.3.9.tgz", - "integrity": "sha1-bxPsNRRTF+spLKX2UxORskQRFBE=" - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + } + }, + "websocket-driver": { + "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.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "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": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "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 + }, + "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" + } } - }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "requires": { - "async-limiter": "~1.0.0" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrap-ansi": { + "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": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.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 } - }, - "x-is-string": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", - "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", - "dev": true - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" - }, - "xmlhttprequest-ssl": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", - "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "yargs": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", - "integrity": "sha1-BU3oth8i7v23IHBZ6u+da4P7kxo=", - "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==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", + "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==", + "dev": true + }, + "x-is-string": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", + "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", + "integrity": "sha1-BU3oth8i7v23IHBZ6u+da4P7kxo=", + "dev": true + }, + "yargs-parser": { + "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-limit": { + "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==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "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" + } } - }, - "yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", - "dev": true - }, - "zip-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz", - "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=", - "dev": true, - "requires": { - "archiver-utils": "^1.3.0", - "compress-commons": "^1.2.0", - "lodash": "^4.8.0", - "readable-stream": "^2.0.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", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "zip-stream": { + "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": "^2.1.0", + "compress-commons": "^3.0.0", + "readable-stream": "^3.6.0" + } } } - \ No newline at end of file +} diff --git a/package.json b/package.json old mode 100755 new mode 100644 index cc5b4e4e9f7..7fef561be33 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "3.5.0-pre", + "version": "3.27.0-pre", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { @@ -24,16 +24,25 @@ "node": ">=8.9.0" }, "devDependencies": { - "@babel/core": "^7.2.2", - "@babel/preset-env": "^7.2.3", + "@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", "documentation": "^5.2.2", - "es5-shim": "^4.5.2", + "es5-shim": "^4.5.14", "eslint-config-standard": "^10.2.1", - "eslint-plugin-import": "^2.2.0", + "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,15 +66,15 @@ "gulp-util": "^3.0.0", "is-docker": "^1.1.0", "istanbul": "^0.4.5", - "istanbul-instrumenter-loader": "^3.0.0", - "karma": "^3.1.3", + "karma": "^4.0.0", "karma-babel-preprocessor": "^6.0.1", - "karma-browserstack-launcher": "^1.3.0", + "karma-browserstack-launcher": "1.4.0", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^2.2.0", + "karma-coverage": "^2.0.1", "karma-coverage-istanbul-reporter": "^1.3.0", "karma-es5-shim": "^0.0.4", - "karma-firefox-launcher": "^1.0.1", + "karma-firefox-launcher": "^1.3.0", "karma-ie-launcher": "^1.0.0", "karma-mocha": "^1.3.0", "karma-mocha-reporter": "^2.2.5", @@ -78,32 +87,31 @@ "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": "^2.4.1", - "criteo-direct-rsa-validate": "^1.0.0", - "crypto-js": "^3.1.9-1", + "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.5", + "fun-hooks": "^0.9.9", "jsencrypt": "^3.0.0-rc.1", - "just-clone": "^1.0.2" + "just-clone": "^1.0.2", + "live-connect-js": "1.1.10" } } diff --git a/plugins/eslint/validateImports.js b/plugins/eslint/validateImports.js index 193455a47fd..a39bf9b26d5 100644 --- a/plugins/eslint/validateImports.js +++ b/plugins/eslint/validateImports.js @@ -31,6 +31,14 @@ function flagErrors(context, node, importPath) { ) { context.report(node, `import "${importPath}" cannot require module entry point`); } + + // don't allow extension-less local imports + if ( + !importPath.match(/^\w+/) && + !['.js', '.json'].includes(path.extname(absImportPath)) + ) { + context.report(node, `import "${importPath}" should include extension as .js or .json`); + } } } diff --git a/src/AnalyticsAdapter.js b/src/AnalyticsAdapter.js index 16d56725e39..f3297412a35 100644 --- a/src/AnalyticsAdapter.js +++ b/src/AnalyticsAdapter.js @@ -1,8 +1,8 @@ -import CONSTANTS from './constants'; -import { ajax } from './ajax'; +import CONSTANTS from './constants.json'; +import { ajax } from './ajax.js'; -const events = require('./events'); -const utils = require('./utils'); +const events = require('./events.js'); +const utils = require('./utils.js'); const { EVENTS: { diff --git a/src/Renderer.js b/src/Renderer.js index f35e9fe354d..85bcbb383e8 100644 --- a/src/Renderer.js +++ b/src/Renderer.js @@ -1,6 +1,6 @@ -import { loadExternalScript } from './adloader'; -import * as utils from './utils'; -import find from 'core-js/library/fn/array/find'; +import { loadExternalScript } from './adloader.js'; +import * as utils from './utils.js'; +import find from 'core-js-pure/features/array/find.js'; const moduleCode = 'outstream'; /** @@ -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 (!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}`); + } + + 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) { diff --git a/src/adServerManager.js b/src/adServerManager.js index 11ce087903d..af8fe34920e 100644 --- a/src/adServerManager.js +++ b/src/adServerManager.js @@ -1,5 +1,5 @@ -import { getGlobal } from './prebidGlobal'; -import { logWarn } from './utils'; +import { getGlobal } from './prebidGlobal.js'; +import { logWarn } from './utils.js'; const prebid = getGlobal(); diff --git a/src/adUnits.js b/src/adUnits.js index aa88cf6eac5..cdac649c5b8 100644 --- a/src/adUnits.js +++ b/src/adUnits.js @@ -1,4 +1,4 @@ -import { deepAccess } from './utils'; +import { deepAccess } from './utils.js'; let adUnits = {}; diff --git a/src/adapterManager.js b/src/adapterManager.js index c9802e0f903..2108bb7a4f6 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -1,20 +1,20 @@ /** @module adaptermanger */ -import { flatten, getBidderCodes, getDefinedParams, shuffle, timestamp, getBidderRequest, bind } from './utils'; -import { getLabels, resolveStatus } from './sizeMapping'; -import { processNativeAdUnitParams, nativeAdapters } from './native'; -import { newBidder } from './adapters/bidderFactory'; -import { ajaxBuilder } from './ajax'; -import { config, RANDOM } from './config'; -import { hook } from './hook'; -import includes from 'core-js/library/fn/array/includes'; -import find from 'core-js/library/fn/array/find'; -import { adunitCounter } from './adUnits'; -import { getRefererInfo } from './refererDetection'; +import { flatten, getBidderCodes, getDefinedParams, shuffle, timestamp, getBidderRequest, bind } from './utils.js'; +import { getLabels, resolveStatus } from './sizeMapping.js'; +import { processNativeAdUnitParams, nativeAdapters } from './native.js'; +import { newBidder } from './adapters/bidderFactory.js'; +import { ajaxBuilder } from './ajax.js'; +import { config, RANDOM } from './config.js'; +import { hook } from './hook.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import find from 'core-js-pure/features/array/find.js'; +import { adunitCounter } from './adUnits.js'; +import { getRefererInfo } from './refererDetection.js'; var utils = require('./utils.js'); var CONSTANTS = require('./constants.json'); -var events = require('./events'); +var events = require('./events.js'); let s2sTestingModule; // store s2sTesting module if it's loaded let adapterManager = {}; @@ -68,7 +68,8 @@ function getBids({bidderCode, auctionId, bidderRequestId, adUnits, labels, src}) bid = Object.assign({}, bid, getDefinedParams(adUnit, [ 'fpd', 'mediaType', - 'renderer' + 'renderer', + 'storedAuctionResponse' ])); let { @@ -115,6 +116,8 @@ function getBids({bidderCode, auctionId, bidderRequestId, adUnits, labels, src}) }, []).reduce(flatten, []).filter(val => val !== ''); } +const hookedGetBids = hook('sync', getBids, 'getBids'); + function getAdUnitCopyForPrebidServer(adUnits) { let adaptersServerSide = _s2sConfig.bidders; let adUnitsCopy = utils.deepClone(adUnits); @@ -228,7 +231,7 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a auctionId, bidderRequestId, tid, - bids: getBids({bidderCode, auctionId, bidderRequestId, 'adUnits': utils.deepClone(adUnitsS2SCopy), labels, src: CONSTANTS.S2S.SRC}), + bids: hookedGetBids({bidderCode, auctionId, bidderRequestId, 'adUnits': utils.deepClone(adUnitsS2SCopy), labels, src: CONSTANTS.S2S.SRC}), auctionStart: auctionStart, timeout: _s2sConfig.timeout, src: CONSTANTS.S2S.SRC, @@ -263,7 +266,7 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a bidderCode, auctionId, bidderRequestId, - bids: getBids({bidderCode, auctionId, bidderRequestId, 'adUnits': utils.deepClone(adUnitsClientCopy), labels, src: 'client'}), + bids: hookedGetBids({bidderCode, auctionId, bidderRequestId, 'adUnits': utils.deepClone(adUnitsClientCopy), labels, src: 'client'}), auctionStart: auctionStart, timeout: cbTimeout, refererInfo @@ -365,19 +368,25 @@ adapterManager.callBids = (adUnits, bidRequests, addBidResponse, doneCb, request request: requestCallbacks.request.bind(null, bidRequest.bidderCode), done: requestCallbacks.done } : undefined); - config.runWithBidder( - bidRequest.bidderCode, - bind.call( - adapter.callBids, - adapter, - bidRequest, - addBidResponse.bind(bidRequest), - doneCb.bind(bidRequest), - ajax, - onTimelyResponse, - config.callbackWithBidder(bidRequest.bidderCode) - ) - ); + const adapterDone = doneCb.bind(bidRequest); + try { + config.runWithBidder( + bidRequest.bidderCode, + bind.call( + adapter.callBids, + adapter, + bidRequest, + addBidResponse.bind(bidRequest), + adapterDone, + ajax, + onTimelyResponse, + config.callbackWithBidder(bidRequest.bidderCode) + ) + ); + } catch (e) { + utils.logError(`${bidRequest.bidderCode} Bid Adapter emitted an uncaught error when parsing their bidRequest`, {e, bidRequest}); + adapterDone(); + } }); }; diff --git a/src/adapters/analytics/example.js b/src/adapters/analytics/example.js index 37ef0ff8fe3..1321612b688 100644 --- a/src/adapters/analytics/example.js +++ b/src/adapters/analytics/example.js @@ -2,7 +2,7 @@ * example.js - analytics adapter for Example Analytics Library example */ -import adapter from '../../AnalyticsAdapter'; +import adapter from '../../AnalyticsAdapter.js'; export default adapter( { diff --git a/src/adapters/analytics/example2.js b/src/adapters/analytics/example2.js index b04e8874e48..eadf994ce36 100644 --- a/src/adapters/analytics/example2.js +++ b/src/adapters/analytics/example2.js @@ -1,10 +1,11 @@ -import { ajax } from '../../../src/ajax'; +/* eslint-disable no-console */ +import { ajax } from '../../../src/ajax.js'; /** * example2.js - analytics adapter for Example2 Analytics Endpoint example */ -import adapter from '../../AnalyticsAdapter'; +import adapter from '../../AnalyticsAdapter.js'; const url = 'https://httpbin.org/post'; const analyticsType = 'endpoint'; diff --git a/src/adapters/analytics/libraries/example.js b/src/adapters/analytics/libraries/example.js index 55ef2b8ca45..0d758fd5513 100644 --- a/src/adapters/analytics/libraries/example.js +++ b/src/adapters/analytics/libraries/example.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ /** @module example */ window.ExampleAnalyticsGlobalObject = function(hander, type, data) { diff --git a/src/adapters/analytics/libraries/example2.js b/src/adapters/analytics/libraries/example2.js index 913f21177d0..68e814b1417 100644 --- a/src/adapters/analytics/libraries/example2.js +++ b/src/adapters/analytics/libraries/example2.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ /** @module example */ window.ExampleAnalyticsGlobalObject2 = function(hander, type, data) { diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index b61aaa96169..8dd351563be 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -1,17 +1,20 @@ -import Adapter from '../adapter'; -import adapterManager from '../adapterManager'; -import { config } from '../config'; -import { createBid } from '../bidfactory'; -import { userSync } from '../userSync'; -import { nativeBidIsValid } from '../native'; -import { isValidVideoBid } from '../video'; +import Adapter from '../adapter.js'; +import adapterManager from '../adapterManager.js'; +import { config } from '../config.js'; +import { createBid } from '../bidfactory.js'; +import { userSync } from '../userSync.js'; +import { nativeBidIsValid } from '../native.js'; +import { isValidVideoBid } from '../video.js'; import CONSTANTS from '../constants.json'; -import events from '../events'; -import includes from 'core-js/library/fn/array/includes'; -import { ajax } from '../ajax'; -import { logWarn, logError, parseQueryStringParameters, delayExecution, parseSizesInput, getBidderRequest, flatten, uniques, timestamp, setDataInLocalStorage, getDataFromLocalStorage, deepAccess, isArray } from '../utils'; -import { ADPOD } from '../mediaTypes'; -import { getHook } from '../hook'; +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 { ADPOD } from '../mediaTypes.js'; +import { getHook, hook } from '../hook.js'; +import { getCoreStorageManager } from '../storageManager.js'; + +export const storage = getCoreStorageManager('bidderFactory'); /** * This file aims to support Adapters during the Prebid 0.x -> 1.x transition. @@ -103,7 +106,7 @@ import { getHook } from '../hook'; * @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. */ @@ -331,21 +334,7 @@ export function newBidder(spec) { }); function registerSyncs(responses, gdprConsent, uspConsent) { - if (spec.getUserSyncs && !adapterManager.aliasRegistry[spec.code]) { - let filterConfig = config.getConfig('userSync.filterSettings'); - let syncs = spec.getUserSyncs({ - iframeEnabled: !!(filterConfig && (filterConfig.iframe || filterConfig.all)), - pixelEnabled: !!(filterConfig && (filterConfig.image || filterConfig.all)), - }, responses, gdprConsent, uspConsent); - if (syncs) { - if (!Array.isArray(syncs)) { - syncs = [syncs]; - } - syncs.forEach((sync) => { - userSync.registerSync(sync.type, spec.code, sync.url) - }); - } - } + registerSyncInner(spec, responses, gdprConsent, uspConsent); } function filterAndWarn(bid) { @@ -357,6 +346,25 @@ export function newBidder(spec) { } } +export const registerSyncInner = hook('async', function(spec, responses, gdprConsent, uspConsent) { + const aliasSyncEnabled = config.getConfig('userSync.aliasSyncEnabled'); + if (spec.getUserSyncs && (aliasSyncEnabled || !adapterManager.aliasRegistry[spec.code])) { + let filterConfig = config.getConfig('userSync.filterSettings'); + let syncs = spec.getUserSyncs({ + iframeEnabled: !!(filterConfig && (filterConfig.iframe || filterConfig.all)), + pixelEnabled: !!(filterConfig && (filterConfig.image || filterConfig.all)), + }, responses, gdprConsent, uspConsent); + if (syncs) { + if (!Array.isArray(syncs)) { + syncs = [syncs]; + } + syncs.forEach((sync) => { + userSync.registerSync(sync.type, spec.code, sync.url) + }); + } + } +}, 'registerSyncs') + export function preloadBidderMappingFile(fn, adUnits) { if (!config.getConfig('adpod.brandCategoryExclusion')) { return fn.call(this, adUnits); @@ -373,27 +381,32 @@ export function preloadBidderMappingFile(fn, adUnits) { let info = bidderSpec.getSpec().getMappingFileInfo(); let refreshInDays = (info.refreshInDays) ? info.refreshInDays : DEFAULT_REFRESHIN_DAYS; let key = (info.localStorageKey) ? info.localStorageKey : bidderSpec.getSpec().code; - let mappingData = 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 + let mappingData = storage.getDataFromLocalStorage(key); + 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`); } - 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`); } } }); @@ -412,7 +425,7 @@ export function getIabSubCategory(bidderCode, category) { if (bidderSpec.getSpec().getMappingFileInfo) { let info = bidderSpec.getSpec().getMappingFileInfo(); let key = (info.localStorageKey) ? info.localStorageKey : bidderSpec.getBidderCode(); - let data = getDataFromLocalStorage(key); + let data = storage.getDataFromLocalStorage(key); if (data) { try { data = JSON.parse(data); diff --git a/src/adloader.js b/src/adloader.js index 22bfe0ef4f2..1c18ce82b16 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -1,5 +1,5 @@ -import includes from 'core-js/library/fn/array/includes'; -import * as utils from './utils'; +import includes from 'core-js-pure/features/array/includes.js'; +import * as utils from './utils.js'; const _requestCache = {}; // The below list contains modules or vendors whom Prebid allows to load external JS. diff --git a/src/adserver.js b/src/adserver.js index 1341e9166da..61af8862972 100644 --- a/src/adserver.js +++ b/src/adserver.js @@ -1,5 +1,5 @@ -import { formatQS } from './url'; -import { targeting } from './targeting'; +import { formatQS } from './utils.js'; +import { targeting } from './targeting.js'; // Adserver parent class const AdServer = function(attr) { diff --git a/src/ajax.js b/src/ajax.js index a9ec75b30ee..b1e4cbdbdff 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -1,7 +1,6 @@ -import {parse as parseURL, format as formatURL} from './url'; -import { config } from './config'; +import { config } from './config.js'; -var utils = require('./utils'); +var utils = require('./utils.js'); const XHR_DONE = 4; @@ -61,9 +60,9 @@ export function ajaxBuilder(timeout = 3000, {request, done} = {}) { } if (method === 'GET' && data) { - let urlInfo = parseURL(url, options); + let urlInfo = utils.parseUrl(url, options); Object.assign(urlInfo.search, data); - url = formatURL(urlInfo); + url = utils.buildUrl(urlInfo); } x.open(method, url, true); diff --git a/src/auction.js b/src/auction.js index fe1b70085e9..b82b4752479 100644 --- a/src/auction.js +++ b/src/auction.js @@ -57,23 +57,22 @@ * @property {function(): void} callBids - sends requests to all adapters for bids */ -import {flatten, timestamp, adUnitsFilter, deepAccess, getBidRequest, getValue} from './utils'; -import { parse as parseURL } from './url'; -import { getPriceBucketString } from './cpmBucketManager'; -import { getNativeTargeting } from './native'; -import { getCacheUrl, store } from './videoCache'; -import { Renderer } from './Renderer'; -import { config } from './config'; -import { userSync } from './userSync'; -import { hook } from './hook'; -import find from 'core-js/library/fn/array/find'; -import { OUTSTREAM } from './video'; -import { VIDEO } from './mediaTypes'; +import {flatten, timestamp, adUnitsFilter, deepAccess, getBidRequest, getValue, parseUrl} from './utils.js'; +import { getPriceBucketString } from './cpmBucketManager.js'; +import { getNativeTargeting } from './native.js'; +import { getCacheUrl, store } from './videoCache.js'; +import { Renderer } from './Renderer.js'; +import { config } from './config.js'; +import { userSync } from './userSync.js'; +import { hook } from './hook.js'; +import find from 'core-js-pure/features/array/find.js'; +import { OUTSTREAM } from './video.js'; +import { VIDEO } from './mediaTypes.js'; const { syncUsers } = userSync; -const utils = require('./utils'); -const adapterManager = require('./adapterManager').default; -const events = require('./events'); +const utils = require('./utils.js'); +const adapterManager = require('./adapterManager.js').default; +const events = require('./events.js'); const CONSTANTS = require('./constants.json'); export const AUCTION_STARTED = 'started'; @@ -120,7 +119,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a let _winningBids = []; let _timelyBidders = new Set(); - function addBidRequests(bidderRequests) { _bidderRequests = _bidderRequests.concat(bidderRequests) }; + function addBidRequests(bidderRequests) { _bidderRequests = _bidderRequests.concat(bidderRequests); } function addBidReceived(bidsReceived) { _bidsReceived = _bidsReceived.concat(bidsReceived); } function addNoBid(noBid) { _noBids = _noBids.concat(noBid); } @@ -168,14 +167,14 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a _auctionEnd = Date.now(); events.emit(CONSTANTS.EVENTS.AUCTION_END, getProperties()); - bidsBackCallback(_adUnitCodes, function () { + bidsBackCallback(_adUnits, function () { try { if (_callback != null) { const adUnitCodes = _adUnitCodes; const bids = _bidsReceived .filter(utils.bind.call(adUnitsFilter, this, adUnitCodes)) .reduce(groupByPlacement, {}); - _callback.apply($$PREBID_GLOBAL$$, [bids, timedOut]); + _callback.apply($$PREBID_GLOBAL$$, [bids, timedOut, _auctionId]); _callback = null; } } catch (e) { @@ -213,62 +212,73 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a let bidRequests = adapterManager.makeBidRequests(_adUnits, _auctionStart, _auctionId, _timeout, _labels); utils.logInfo(`Bids Requested for Auction with id: ${_auctionId}`, bidRequests); - bidRequests.forEach(bidRequest => { - addBidRequests(bidRequest); - }); - - let requests = {}; if (bidRequests.length < 1) { utils.logWarn('No valid bid requests returned for auction'); auctionDone(); } else { - let call = { - bidRequests, - run: () => { - startAuctionTimer(); - - _auctionStatus = AUCTION_IN_PROGRESS; - - events.emit(CONSTANTS.EVENTS.AUCTION_INIT, getProperties()); - - let callbacks = auctionCallbacks(auctionDone, this); - adapterManager.callBids(_adUnits, bidRequests, function(...args) { - addBidResponse.apply({ - dispatch: callbacks.addBidResponse, - bidderRequest: this - }, args) - }, callbacks.adapterDone, { - request(source, origin) { - increment(outstandingRequests, origin); - increment(requests, source); - - if (!sourceInfo[source]) { - sourceInfo[source] = { - SRA: true, - origin - }; - } - if (requests[source] > 1) { - sourceInfo[source].SRA = false; - } - }, - done(origin) { - outstandingRequests[origin]--; - if (queuedCalls[0]) { - if (runIfOriginHasCapacity(queuedCalls[0])) { - queuedCalls.shift(); - } + addBidderRequests.call({ + dispatch: addBidderRequestsCallback, + context: this + }, bidRequests); + } + } + + /** + * callback executed after addBidderRequests completes + * @param {BidRequest[]} bidRequests + */ + function addBidderRequestsCallback(bidRequests) { + bidRequests.forEach(bidRequest => { + addBidRequests(bidRequest); + }); + + let requests = {}; + let call = { + bidRequests, + run: () => { + startAuctionTimer(); + + _auctionStatus = AUCTION_IN_PROGRESS; + + events.emit(CONSTANTS.EVENTS.AUCTION_INIT, getProperties()); + + let callbacks = auctionCallbacks(auctionDone, this); + adapterManager.callBids(_adUnits, bidRequests, function(...args) { + addBidResponse.apply({ + dispatch: callbacks.addBidResponse, + bidderRequest: this + }, args) + }, callbacks.adapterDone, { + request(source, origin) { + increment(outstandingRequests, origin); + increment(requests, source); + + if (!sourceInfo[source]) { + sourceInfo[source] = { + SRA: true, + origin + }; + } + if (requests[source] > 1) { + sourceInfo[source].SRA = false; + } + }, + done(origin) { + outstandingRequests[origin]--; + if (queuedCalls[0]) { + if (runIfOriginHasCapacity(queuedCalls[0])) { + queuedCalls.shift(); } } - }, _timeout, onTimelyResponse); - } - }; - - if (!runIfOriginHasCapacity(call)) { - utils.logWarn('queueing auction due to limited endpoint capacity'); - queuedCalls.push(call); + } + }, _timeout, onTimelyResponse); } + }; + + if (!runIfOriginHasCapacity(call)) { + utils.logWarn('queueing auction due to limited endpoint capacity'); + queuedCalls.push(call); } function runIfOriginHasCapacity(call) { @@ -344,6 +354,10 @@ export const addBidResponse = hook('async', function(adUnitCode, bid) { this.dispatch.call(this.bidderRequest, adUnitCode, bid); }, 'addBidResponse'); +export const addBidderRequests = hook('sync', function(bidderRequests) { + this.dispatch.call(this.context, bidderRequests); +}, 'addBidderRequests'); + export const bidsBackCallback = hook('async', function (adUnits, callback) { if (callback) { callback(); @@ -469,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. @@ -636,7 +650,7 @@ export function getStandardBidderSettings(mediaType, bidderCode, bidReq) { // Adding hb_cache_host if (config.getConfig('cache.url') && (!bidderCode || utils.deepAccess(bidderSettings, `${bidderCode}.sendStandardTargeting`) !== false)) { - const urlInfo = parseURL(config.getConfig('cache.url')); + const urlInfo = parseUrl(config.getConfig('cache.url')); if (typeof find(adserverTargeting, targetingKeyVal => targetingKeyVal.key === TARGETING_KEYS.CACHE_HOST) === 'undefined') { adserverTargeting.push(createKeyVal(TARGETING_KEYS.CACHE_HOST, function(bidResponse) { diff --git a/src/auctionManager.js b/src/auctionManager.js index 219a5e55805..3d4bd0afe99 100644 --- a/src/auctionManager.js +++ b/src/auctionManager.js @@ -16,9 +16,9 @@ * @property {function(): Object} getStandardBidderAdServerTargeting - returns standard bidder targeting for all the adapters. Refer http://prebid.org/dev-docs/publisher-api-reference.html#module_pbjs.bidderSettings for more details */ -import { uniques, flatten, logWarn } from './utils'; -import { newAuction, getStandardBidderSettings, AUCTION_COMPLETED } from './auction'; -import find from 'core-js/library/fn/array/find'; +import { uniques, flatten, logWarn } from './utils.js'; +import { newAuction, getStandardBidderSettings, AUCTION_COMPLETED } from './auction.js'; +import find from 'core-js-pure/features/array/find.js'; const CONSTANTS = require('./constants.json'); diff --git a/src/config.js b/src/config.js index 19a582e86d5..3284be52296 100644 --- a/src/config.js +++ b/src/config.js @@ -12,22 +12,23 @@ * @property {(string|Object)} [video-outstream] */ -import { isValidPriceConfig } from './cpmBucketManager'; -import find from 'core-js/library/fn/array/find'; -import includes from 'core-js/library/fn/array/includes'; -import Set from 'core-js/library/fn/set'; -import { parseQS } from './url'; +import { isValidPriceConfig } from './cpmBucketManager.js'; +import find from 'core-js-pure/features/array/find.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import Set from 'core-js-pure/features/set'; +import { mergeDeep } from './utils.js'; -const from = require('core-js/library/fn/array/from'); -const utils = require('./utils'); -const CONSTANTS = require('./constants'); +const from = require('core-js-pure/features/array/from.js'); +const utils = require('./utils.js'); +const CONSTANTS = require('./constants.json'); -const DEFAULT_DEBUG = (parseQS(window.location.search)[CONSTANTS.DEBUG_MODE] || '').toUpperCase() === 'TRUE'; +const DEFAULT_DEBUG = utils.getParameterByName(CONSTANTS.DEBUG_MODE).toUpperCase() === 'TRUE'; const DEFAULT_BIDDER_TIMEOUT = 3000; const DEFAULT_PUBLISHER_DOMAIN = window.location.origin; const DEFAULT_ENABLE_SEND_ALL_BIDS = true; const DEFAULT_DISABLE_AJAX_TIMEOUT = false; const DEFAULT_BID_CACHE = false; +const DEFAULT_DEVICE_ACCESS = true; const DEFAULT_TIMEOUTBUFFER = 400; @@ -158,6 +159,18 @@ export function newConfig() { this._useBidCache = val; }, + /** + * deviceAccess set to false will disable setCookie, getCookie, hasLocalStorage + * @type {boolean} + */ + _deviceAccess: DEFAULT_DEVICE_ACCESS, + get deviceAccess() { + return this._deviceAccess; + }, + set deviceAccess(val) { + this._deviceAccess = val; + }, + _bidderSequence: DEFAULT_BIDDER_SEQUENCE, get bidderSequence() { return this._bidderSequence; @@ -186,7 +199,6 @@ export function newConfig() { set disableAjaxTimeout(val) { this._disableAjaxTimeout = val; }, - }; if (config) { @@ -243,7 +255,7 @@ export function newConfig() { memo[topic] = currBidderConfig[topic]; } else { if (utils.isPlainObject(currBidderConfig[topic])) { - memo[topic] = Object.assign({}, config[topic], currBidderConfig[topic]); + memo[topic] = mergeDeep({}, config[topic], currBidderConfig[topic]); } else { memo[topic] = currBidderConfig[topic]; } @@ -429,14 +441,23 @@ export function newConfig() { function callbackWithBidder(bidder) { return function(cb) { return function(...args) { - return runWithBidder(bidder, utils.bind.call(cb, this, ...args)) + if (typeof cb === 'function') { + return runWithBidder(bidder, utils.bind.call(cb, this, ...args)) + } else { + utils.logWarn('config.callbackWithBidder callback is not a function'); + } } } } + function getCurrentBidder() { + return currBidder; + } + resetConfig(); return { + getCurrentBidder, getConfig, setConfig, setDefaults, diff --git a/src/constants.json b/src/constants.json index 0b6b144a336..5965d77a6c4 100644 --- a/src/constants.json +++ b/src/constants.json @@ -95,9 +95,7 @@ }, "BID_STATUS" : { "BID_TARGETING_SET": "targetingSet", - "RENDERED": "rendered" - }, - "SUBMODULES_THAT_ALWAYS_REFRESH_ID": { - "parrableId": true + "RENDERED": "rendered", + "BID_REJECTED": "bidRejected" } } diff --git a/src/cpmBucketManager.js b/src/cpmBucketManager.js index 24586988a13..a6b76cc38e2 100644 --- a/src/cpmBucketManager.js +++ b/src/cpmBucketManager.js @@ -1,5 +1,5 @@ -import find from 'core-js/library/fn/array/find'; -const utils = require('./utils'); +import find from 'core-js-pure/features/array/find.js'; +const utils = require('./utils.js'); const _defaultPrecision = 2; const _lgPriceConfig = { diff --git a/src/debugging.js b/src/debugging.js index 98ff67f4707..dc479f74674 100644 --- a/src/debugging.js +++ b/src/debugging.js @@ -1,11 +1,12 @@ -import { config } from './config'; -import { logMessage as utilsLogMessage, logWarn as utilsLogWarn } from './utils'; -import { addBidResponse } from './auction'; +import { config } from './config.js'; +import { logMessage as utilsLogMessage, logWarn as utilsLogWarn } from './utils.js'; +import { addBidderRequests, addBidResponse } from './auction.js'; const OVERRIDE_KEY = '$$PREBID_GLOBAL$$:debugging'; -export let boundHook; +export let addBidResponseBound; +export let addBidderRequestsBound; function logMessage(msg) { utilsLogMessage('DEBUG: ' + msg); @@ -15,52 +16,113 @@ function logWarn(msg) { utilsLogWarn('DEBUG: ' + msg); } -function removeHook() { - addBidResponse.getHooks({hook: boundHook}).remove() +function addHooks(overrides) { + addBidResponseBound = addBidResponseHook.bind(overrides); + addBidResponse.before(addBidResponseBound, 5); + + addBidderRequestsBound = addBidderRequestsHook.bind(overrides); + addBidderRequests.before(addBidderRequestsBound, 5); +} + +function removeHooks() { + addBidResponse.getHooks({hook: addBidResponseBound}).remove(); + addBidderRequests.getHooks({hook: addBidderRequestsBound}).remove(); } -function enableOverrides(overrides, fromSession = false) { +export function enableOverrides(overrides, fromSession = false) { config.setConfig({'debug': true}); + removeHooks(); + addHooks(overrides); logMessage(`bidder overrides enabled${fromSession ? ' from session' : ''}`); - - removeHook(); - - boundHook = addBidResponseHook.bind(overrides); - addBidResponse.before(boundHook, 5); } export function disableOverrides() { - removeHook(); + removeHooks(); logMessage('bidder overrides disabled'); } +/** + * @param {{bidder:string, adUnitCode:string}} overrideObj + * @param {string} bidderCode + * @param {string} adUnitCode + * @returns {boolean} + */ +export function bidExcluded(overrideObj, bidderCode, adUnitCode) { + if (overrideObj.bidder && overrideObj.bidder !== bidderCode) { + return true; + } + if (overrideObj.adUnitCode && overrideObj.adUnitCode !== adUnitCode) { + return true; + } + return false; +} + +/** + * @param {string[]} bidders + * @param {string} bidderCode + * @returns {boolean} + */ +export function bidderExcluded(bidders, bidderCode) { + return (Array.isArray(bidders) && bidders.indexOf(bidderCode) === -1); +} + +/** + * @param {Object} overrideObj + * @param {Object} bidObj + * @param {Object} bidType + * @returns {Object} bidObj with overridden properties + */ +export function applyBidOverrides(overrideObj, bidObj, bidType) { + return Object.keys(overrideObj).filter(key => (['adUnitCode', 'bidder'].indexOf(key) === -1)).reduce(function(result, key) { + logMessage(`bidder overrides changed '${result.adUnitCode}/${result.bidderCode}' ${bidType}.${key} from '${result[key]}.js' to '${overrideObj[key]}'`); + result[key] = overrideObj[key]; + return result; + }, bidObj); +} + export function addBidResponseHook(next, adUnitCode, bid) { - let overrides = this; - if (Array.isArray(overrides.bidders) && overrides.bidders.indexOf(bid.bidderCode) === -1) { + const overrides = this; + + if (bidderExcluded(overrides.bidders, bid.bidderCode)) { logWarn(`bidder '${bid.bidderCode}' excluded from auction by bidder overrides`); return; } if (Array.isArray(overrides.bids)) { - overrides.bids.forEach(overrideBid => { - if (overrideBid.bidder && overrideBid.bidder !== bid.bidderCode) { - return; - } - if (overrideBid.adUnitCode && overrideBid.adUnitCode !== adUnitCode) { - return; + overrides.bids.forEach(function(overrideBid) { + if (!bidExcluded(overrideBid, bid.bidderCode, adUnitCode)) { + applyBidOverrides(overrideBid, bid, 'bidder'); } + }); + } - bid = Object.assign({}, bid); + next(adUnitCode, bid); +} - Object.keys(overrideBid).filter(key => ['bidder', 'adUnitCode'].indexOf(key) === -1).forEach((key) => { - let value = overrideBid[key]; - logMessage(`bidder overrides changed '${adUnitCode}/${bid.bidderCode}' bid.${key} from '${bid[key]}' to '${value}'`); - bid[key] = value; +export function addBidderRequestsHook(next, bidderRequests) { + const overrides = this; + + const includedBidderRequests = bidderRequests.filter(function(bidderRequest) { + if (bidderExcluded(overrides.bidders, bidderRequest.bidderCode)) { + logWarn(`bidRequest '${bidderRequest.bidderCode}' excluded from auction by bidder overrides`); + return false; + } + return true; + }); + + if (Array.isArray(overrides.bidRequests)) { + includedBidderRequests.forEach(function(bidderRequest) { + overrides.bidRequests.forEach(function(overrideBid) { + bidderRequest.bids.forEach(function(bid) { + if (!bidExcluded(overrideBid, bidderRequest.bidderCode, bid.adUnitCode)) { + applyBidOverrides(overrideBid, bid, 'bidRequest'); + } + }); }); }); } - next(adUnitCode, bid); + next(includedBidderRequests); } export function getConfig(debugging) { diff --git a/src/events.js b/src/events.js index 6ef3f7a46cb..e7a11635476 100644 --- a/src/events.js +++ b/src/events.js @@ -1,8 +1,8 @@ /** * events.js */ -var utils = require('./utils'); -var CONSTANTS = require('./constants'); +var utils = require('./utils.js'); +var CONSTANTS = require('./constants.json'); var slice = Array.prototype.slice; var push = Array.prototype.push; @@ -113,14 +113,14 @@ module.exports = (function () { utils._each(event[id].que, function (_handler) { var que = event[id].que; if (_handler === handler) { - que.splice(utils.indexOf.call(que, _handler), 1); + que.splice(que.indexOf(_handler), 1); } }); } else { utils._each(event.que, function (_handler) { var que = event.que; if (_handler === handler) { - que.splice(utils.indexOf.call(que, _handler), 1); + que.splice(que.indexOf(_handler), 1); } }); } diff --git a/src/hook.js b/src/hook.js index 220e1c39111..9050bf2f7dc 100644 --- a/src/hook.js +++ b/src/hook.js @@ -1,5 +1,5 @@ -import funHooks from 'fun-hooks/no-eval'; +import funHooks from 'fun-hooks/no-eval/index.js'; export let hook = funHooks({ ready: funHooks.SYNC | funHooks.ASYNC | funHooks.QUEUE diff --git a/src/native.js b/src/native.js index 6252eb133b3..e41d7740ffa 100644 --- a/src/native.js +++ b/src/native.js @@ -1,5 +1,5 @@ -import { deepAccess, getBidRequest, getKeyByValue, insertHtmlIntoIframe, logError, triggerPixel } from './utils'; -import includes from 'core-js/library/fn/array/includes'; +import { deepAccess, getBidRequest, getKeyByValue, insertHtmlIntoIframe, logError, triggerPixel } from './utils.js'; +import includes from 'core-js-pure/features/array/includes.js'; const CONSTANTS = require('./constants.json'); diff --git a/src/prebid.js b/src/prebid.js index f1ead426496..1710849ba92 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -1,24 +1,25 @@ /** @module pbjs */ -import { getGlobal } from './prebidGlobal'; -import { flatten, uniques, isGptPubadsDefined, adUnitsFilter, isArrayOfNums } from './utils'; -import { listenMessagesFromCreative } from './secureCreatives'; +import { getGlobal } from './prebidGlobal.js'; +import { flatten, uniques, isGptPubadsDefined, adUnitsFilter, isArrayOfNums } from './utils.js'; +import { listenMessagesFromCreative } from './secureCreatives.js'; import { userSync } from './userSync.js'; -import { config } from './config'; -import { auctionManager } from './auctionManager'; -import { targeting } from './targeting'; -import { hook } from './hook'; -import { sessionLoader } from './debugging'; -import includes from 'core-js/library/fn/array/includes'; -import { adunitCounter } from './adUnits'; -import { isRendererRequired, executeRenderer } from './Renderer'; -import { createBid } from './bidfactory'; +import { config } from './config.js'; +import { auctionManager } from './auctionManager.js'; +import { targeting } from './targeting.js'; +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 { createBid } from './bidfactory.js'; +import { storageCallbacks } from './storageManager.js'; const $$PREBID_GLOBAL$$ = getGlobal(); const CONSTANTS = require('./constants.json'); const utils = require('./utils.js'); -const adapterManager = require('./adapterManager').default; -const events = require('./events'); +const adapterManager = require('./adapterManager.js').default; +const events = require('./events.js'); const { triggerUserSyncs } = userSync; /* private variables */ @@ -68,20 +69,74 @@ function setRenderSize(doc, width, height) { } } -export const checkAdUnitSetup = hook('sync', function (adUnits) { - function validateSizes(sizes, targLength) { - let cleanSizes = []; - if (utils.isArray(sizes) && ((targLength) ? sizes.length === targLength : sizes.length > 0)) { - // check if an array of arrays or array of numbers - if (sizes.every(sz => isArrayOfNums(sz, 2))) { - cleanSizes = sizes; - } else if (isArrayOfNums(sizes, 2)) { - cleanSizes.push(sizes); - } +function validateSizes(sizes, targLength) { + let cleanSizes = []; + if (utils.isArray(sizes) && ((targLength) ? sizes.length === targLength : sizes.length > 0)) { + // check if an array of arrays or array of numbers + if (sizes.every(sz => isArrayOfNums(sz, 2))) { + cleanSizes = sizes; + } else if (isArrayOfNums(sizes, 2)) { + cleanSizes.push(sizes); } - return cleanSizes; } + return cleanSizes; +} +function validateBannerMediaType(adUnit) { + const banner = adUnit.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; + } 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 + } +} + +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.'); + } + 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; + } +} + +function validateNativeMediaType(adUnit) { + const native = adUnit.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; + } + 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; + } + 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; + } +} + +export const adUnitSetupChecks = { + validateBannerMediaType, + validateVideoMediaType, + validateNativeMediaType, + validateSizes +}; + +export const checkAdUnitSetup = hook('sync', function (adUnits) { return adUnits.filter(adUnit => { const mediaTypes = adUnit.mediaTypes; if (!mediaTypes || Object.keys(mediaTypes).length === 0) { @@ -90,45 +145,18 @@ export const checkAdUnitSetup = hook('sync', function (adUnits) { } if (mediaTypes.banner) { - const bannerSizes = validateSizes(mediaTypes.banner.sizes); - if (bannerSizes.length > 0) { - mediaTypes.banner.sizes = bannerSizes; - // TODO eventually remove this internal copy once we're ready to deprecate bidders from reading this adUnit.sizes property - adUnit.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; - } + validateBannerMediaType(adUnit); } if (mediaTypes.video) { const video = mediaTypes.video; if (video.playerSize) { - let tarPlayerSizeLen = (typeof video.playerSize[0] === 'number') ? 2 : 1; - const videoSizes = validateSizes(video.playerSize, tarPlayerSizeLen); - if (videoSizes.length > 0) { - adUnit.sizes = video.playerSize = 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; - } + validateVideoMediaType(adUnit); } } if (mediaTypes.native) { - const nativeObj = mediaTypes.native; - if (nativeObj.image && nativeObj.image.sizes && !Array.isArray(nativeObj.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; - } - if (nativeObj.image && nativeObj.image.aspect_ratios && !Array.isArray(nativeObj.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; - } - if (nativeObj.icon && nativeObj.icon.sizes && !Array.isArray(nativeObj.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; - } + validateNativeMediaType(adUnit); } return true; }); @@ -250,7 +278,7 @@ $$PREBID_GLOBAL$$.setTargetingForGPTAsync = function (adUnit, customSlotMatching let targetingSet = targeting.getAllTargeting(adUnit); // first reset any old targeting - targeting.resetPresetTargeting(adUnit); + targeting.resetPresetTargeting(adUnit, customSlotMatching); // now set new targeting keys targeting.setTargetingForGPT(targetingSet, customSlotMatching); @@ -493,9 +521,22 @@ $$PREBID_GLOBAL$$.requestBids = hook('async', function ({ bidsBackHandler, timeo adUnitCodes.forEach(code => targeting.setLatestAuctionForAdUnit(code, auction.getAuctionId())); auction.callBids(); - return auction; }); +export function executeStorageCallbacks(fn, reqBidsConfigObj) { + runAll(storageCallbacks); + fn.call(this, reqBidsConfigObj); + function runAll(queue) { + var queued; + while ((queued = queue.shift())) { + queued(); + } + } +} + +// 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); + /** * * Add adunit(s) diff --git a/src/refererDetection.js b/src/refererDetection.js index 2acb0b68716..60198678666 100644 --- a/src/refererDetection.js +++ b/src/refererDetection.js @@ -8,7 +8,7 @@ * Canonical URL which refers to an HTML link element, with the attribute of rel="canonical", found in the element of your webpage */ -import { logWarn } from './utils'; +import { logWarn } from './utils.js'; export function detectReferer(win) { /** diff --git a/src/secureCreatives.js b/src/secureCreatives.js index 7584c5d2bf7..34de2be275c 100644 --- a/src/secureCreatives.js +++ b/src/secureCreatives.js @@ -3,18 +3,19 @@ access to a publisher page from creative payloads. */ -import events from './events'; -import { fireNativeTrackers, getAssetMessage } from './native'; -import { EVENTS } from './constants'; -import { isSlotMatchingAdUnitCode, logWarn, replaceAuctionPrice } from './utils'; -import { auctionManager } from './auctionManager'; -import find from 'core-js/library/fn/array/find'; -import { isRendererRequired, executeRenderer } from './Renderer'; +import events from './events.js'; +import { fireNativeTrackers, getAssetMessage } from './native.js'; +import { EVENTS } from './constants.json'; +import { logWarn, replaceAuctionPrice } from './utils.js'; +import { auctionManager } from './auctionManager.js'; +import find from 'core-js-pure/features/array/find.js'; +import { isRendererRequired, executeRenderer } from './Renderer.js'; +import includes from 'core-js-pure/features/array/includes.js'; const BID_WON = EVENTS.BID_WON; export function listenMessagesFromCreative() { - addEventListener('message', receiveMessage, false); + window.addEventListener('message', receiveMessage, false); } function receiveMessage(ev) { @@ -32,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); @@ -61,25 +62,25 @@ 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); } } -function resizeRemoteCreative({ adUnitCode, width, height }) { +function resizeRemoteCreative({ adId, adUnitCode, width, height }) { // resize both container div + iframe ['div', 'iframe'].forEach(elmType => { // not select element that gets removed after dfp render @@ -94,14 +95,14 @@ function resizeRemoteCreative({ adUnitCode, width, height }) { }); function getElementByAdUnit(elmType) { - let id = getElementIdBasedOnAdServer(adUnitCode); + let id = getElementIdBasedOnAdServer(adId, adUnitCode); let parentDivEle = document.getElementById(id); return parentDivEle && parentDivEle.querySelector(elmType); } - function getElementIdBasedOnAdServer(adUnitCode) { + function getElementIdBasedOnAdServer(adId, adUnitCode) { if (window.googletag) { - return getDfpElementId(adUnitCode) + return getDfpElementId(adId) } else if (window.apntag) { return getAstElementId(adUnitCode) } else { @@ -109,8 +110,12 @@ function resizeRemoteCreative({ adUnitCode, width, height }) { } } - function getDfpElementId(adUnitCode) { - return find(window.googletag.pubads().getSlots().filter(isSlotMatchingAdUnitCode(adUnitCode)), slot => slot).getSlotElementId() + function getDfpElementId(adId) { + return find(window.googletag.pubads().getSlots(), slot => { + return find(slot.getTargetingKeys(), key => { + return includes(slot.getTargeting(key), adId); + }); + }).getSlotElementId(); } function getAstElementId(adUnitCode) { diff --git a/src/sizeMapping.js b/src/sizeMapping.js index a3422a6cdc4..313da3f422a 100644 --- a/src/sizeMapping.js +++ b/src/sizeMapping.js @@ -1,6 +1,6 @@ -import { config } from './config'; -import {logWarn, isPlainObject, deepAccess, deepClone, getWindowTop} from './utils'; -import includes from 'core-js/library/fn/array/includes'; +import { config } from './config.js'; +import {logWarn, isPlainObject, deepAccess, deepClone, getWindowTop} from './utils.js'; +import includes from 'core-js-pure/features/array/includes.js'; let sizeConfig = []; @@ -125,6 +125,8 @@ function evaluateSizeConfig(configs) { ) { let ruleMatch = false; + // TODO: (Prebid - 4.0) Remove empty mediaQuery string check. Disallow empty mediaQuery in sizeConfig. + // Refer: https://github.com/prebid/Prebid.js/pull/4691, https://github.com/prebid/Prebid.js/issues/4810 for more details. if (config.mediaQuery === '') { ruleMatch = true; } else { diff --git a/src/storageManager.js b/src/storageManager.js new file mode 100644 index 00000000000..0d88a8ccea1 --- /dev/null +++ b/src/storageManager.js @@ -0,0 +1,311 @@ +import { hook } from './hook.js'; +import * as utils from './utils.js'; +import includes from 'core-js-pure/features/array/includes.js'; + +const moduleTypeWhiteList = ['core', 'prebid-module']; + +export let storageCallbacks = []; + +/** + * Storage options + * @typedef {Object} storageOptions + * @property {Number=} gvlid - Vendor id + * @property {string} moduleName - Module name + * @property {string=} moduleType - Module type, value can be anyone of core or prebid-module + */ + +/** + * Returns list of storage related functions with gvlid, module name and module type in its scope. + * All three argument are optional here. Below shows the usage of of these + * - GVL Id: Pass GVL id if you are a vendor + * - Module name: All modules need to pass module name + * - Module type: Some modules may need these functions but are not vendor. e.g prebid core files in src and modules like currency. + * @param {storageOptions} options + */ +export function newStorageManager({gvlid, moduleName, moduleType} = {}) { + function isValid(cb) { + if (includes(moduleTypeWhiteList, moduleType)) { + let result = { + valid: true + } + return cb(result); + } else { + let value; + let hookDetails = { + hasEnforcementHook: false + } + validateStorageEnforcement(gvlid, moduleName, hookDetails, function(result) { + if (result && result.hasEnforcementHook) { + value = cb(result); + } else { + let result = { + hasEnforcementHook: false, + valid: utils.hasDeviceAccess() + } + value = cb(result); + } + }); + return value; + } + } + + /** + * @param {string} key + * @param {string} value + * @param {string} [expires=''] + * @param {string} [sameSite='/'] + * @param {string} [domain] domain (e.g., 'example.com' or 'subdomain.example.com'). + * If not specified, defaults to the host portion of the current document location. + * If a domain is specified, subdomains are always included. + * Domain must match the domain of the JavaScript origin. Setting cookies to foreign domains will be silently ignored. + */ + const setCookie = function (key, value, expires, sameSite, domain, done) { + let cb = function (result) { + if (result && result.valid) { + const domainPortion = (domain && domain !== '') ? ` ;domain=${encodeURIComponent(domain)}` : ''; + const expiresPortion = (expires && expires !== '') ? ` ;expires=${expires}` : ''; + const isNone = (sameSite != null && sameSite.toLowerCase() == 'none') + const secure = (isNone) ? '; Secure' : ''; + document.cookie = `${key}=${encodeURIComponent(value)}${expiresPortion}; path=/${domainPortion}${sameSite ? `; SameSite=${sameSite}` : ''}${secure}`; + } + } + if (done && typeof done === 'function') { + storageCallbacks.push(function() { + let result = isValid(cb); + done(result); + }); + } else { + return isValid(cb); + } + }; + + /** + * @param {string} name + * @returns {(string|null)} + */ + const getCookie = function(name, done) { + let cb = function (result) { + if (result && result.valid) { + let m = window.document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]*)\\s*(;|$)'); + return m ? decodeURIComponent(m[2]) : null; + } + return null; + } + if (done && typeof done === 'function') { + storageCallbacks.push(function() { + let result = isValid(cb); + done(result); + }); + } else { + return isValid(cb); + } + }; + + /** + * @returns {boolean} + */ + const localStorageIsEnabled = function (done) { + let cb = function (result) { + if (result && result.valid) { + try { + localStorage.setItem('prebid.cookieTest', '1'); + return localStorage.getItem('prebid.cookieTest') === '1'; + } catch (error) {} + } + return false; + } + if (done && typeof done === 'function') { + storageCallbacks.push(function() { + let result = isValid(cb); + done(result); + }); + } else { + return isValid(cb); + } + } + + /** + * @returns {boolean} + */ + const cookiesAreEnabled = function (done) { + let cb = function (result) { + if (result && result.valid) { + if (utils.checkCookieSupport()) { + return true; + } + window.document.cookie = 'prebid.cookieTest'; + return window.document.cookie.indexOf('prebid.cookieTest') !== -1; + } + return false; + } + if (done && typeof done === 'function') { + storageCallbacks.push(function() { + let result = isValid(cb); + done(result); + }); + } else { + return isValid(cb); + } + } + + /** + * @param {string} key + * @param {string} value + */ + const setDataInLocalStorage = function (key, value, done) { + let cb = function (result) { + if (result && result.valid) { + window.localStorage.setItem(key, value); + } + } + if (done && typeof done === 'function') { + storageCallbacks.push(function() { + let result = isValid(cb); + done(result); + }); + } else { + return isValid(cb); + } + } + + /** + * @param {string} key + * @returns {(string|null)} + */ + const getDataFromLocalStorage = function (key, done) { + let cb = function (result) { + if (result && result.valid) { + return window.localStorage.getItem(key); + } + return null; + } + if (done && typeof done === 'function') { + storageCallbacks.push(function() { + let result = isValid(cb); + done(result); + }); + } else { + return isValid(cb); + } + } + + /** + * @param {string} key + */ + const removeDataFromLocalStorage = function (key, done) { + let cb = function (result) { + if (result && result.valid) { + window.localStorage.removeItem(key); + } + } + if (done && typeof done === 'function') { + storageCallbacks.push(function() { + let result = isValid(cb); + done(result); + }); + } else { + return isValid(cb); + } + } + + /** + * @returns {boolean} + */ + const hasLocalStorage = function (done) { + let cb = function (result) { + if (result && result.valid) { + try { + return !!window.localStorage; + } catch (e) { + utils.logError('Local storage api disabled'); + } + } + return false; + } + if (done && typeof done === 'function') { + storageCallbacks.push(function() { + let result = isValid(cb); + done(result); + }); + } else { + return isValid(cb); + } + } + + /** + * Returns all cookie values from the jar whose names contain the `keyLike` + * Needs to exist in `utils.js` as it follows the StorageHandler interface defined in live-connect-js. If that module were to be removed, this function can go as well. + * @param {string} keyLike + * @return {[]} + */ + const findSimilarCookies = function(keyLike, done) { + let cb = function (result) { + if (result && result.valid) { + const all = []; + if (utils.hasDeviceAccess()) { + const cookies = document.cookie.split(';'); + while (cookies.length) { + const cookie = cookies.pop(); + let separatorIndex = cookie.indexOf('='); + separatorIndex = separatorIndex < 0 ? cookie.length : separatorIndex; + const cookieName = decodeURIComponent(cookie.slice(0, separatorIndex).replace(/^\s+/, '')); + if (cookieName.indexOf(keyLike) >= 0) { + all.push(decodeURIComponent(cookie.slice(separatorIndex + 1))); + } + } + } + return all; + } + } + + if (done && typeof done === 'function') { + storageCallbacks.push(function() { + let result = isValid(cb); + done(result); + }); + } else { + return isValid(cb); + } + } + + return { + setCookie, + getCookie, + localStorageIsEnabled, + cookiesAreEnabled, + setDataInLocalStorage, + getDataFromLocalStorage, + removeDataFromLocalStorage, + hasLocalStorage, + findSimilarCookies + } +} + +/** + * This hook validates the storage enforcement if gdprEnforcement module is included + */ +export const validateStorageEnforcement = hook('async', function(gvlid, moduleName, hookDetails, callback) { + callback(hookDetails); +}, 'validateStorageEnforcement'); + +/** + * This function returns storage functions to access cookies and localstorage. This function will bypass the gdpr enforcement requirement. Prebid as a software needs to use storage in some scenarios and is not a vendor so GDPR enforcement rules does not apply on Prebid. + * @param {string} moduleName Module name + */ +export function getCoreStorageManager(moduleName) { + return newStorageManager({moduleName: moduleName, moduleType: 'core'}); +} + +/** + * Note: Core modules or Prebid modules like Currency, SizeMapping should use getCoreStorageManager + * This function returns storage functions to access cookies and localstorage. Bidders and User id modules should import this and use it in their module if needed. GVL ID and Module name are optional param but gvl id is needed for when gdpr enforcement module is used. + * @param {Number=} gvlid Vendor id + * @param {string=} moduleName BidderCode or module name + */ +export function getStorageManager(gvlid, moduleName) { + return newStorageManager({gvlid: gvlid, moduleName: moduleName}); +} + +export function resetData() { + storageCallbacks = []; +} diff --git a/src/targeting.js b/src/targeting.js index 7c24fdf59f4..45c098554a5 100644 --- a/src/targeting.js +++ b/src/targeting.js @@ -1,10 +1,10 @@ -import { uniques, isGptPubadsDefined, getHighestCpm, getOldestHighestCpmBid, groupBy, isAdUnitCodeMatchingSlot, timestamp, deepAccess, deepClone, logError, logWarn, logInfo } from './utils'; -import { config } from './config'; -import { NATIVE_TARGETING_KEYS } from './native'; -import { auctionManager } from './auctionManager'; -import { sizeSupported } from './sizeMapping'; -import { ADPOD } from './mediaTypes'; -import includes from 'core-js/library/fn/array/includes'; +import { uniques, isGptPubadsDefined, getHighestCpm, getOldestHighestCpmBid, groupBy, isAdUnitCodeMatchingSlot, timestamp, deepAccess, deepClone, logError, logWarn, logInfo } from './utils.js'; +import { config } from './config.js'; +import { NATIVE_TARGETING_KEYS } from './native.js'; +import { auctionManager } from './auctionManager.js'; +import { sizeSupported } from './sizeMapping.js'; +import { ADPOD } from './mediaTypes.js'; +import includes from 'core-js-pure/features/array/includes.js'; const utils = require('./utils.js'); var CONSTANTS = require('./constants.json'); @@ -34,6 +34,7 @@ export let filters = { // If adUnitBidLimit is set above 0 return top N number of bids export function getHighestCpmBidsFromBidPool(bidsReceived, highestCpmCallback, adUnitBidLimit = 0) { const bids = []; + const dealPrioritization = config.getConfig('sendBidsControl.dealPrioritization'); // bucket by adUnitcode let buckets = groupBy(bidsReceived, 'adUnitCode'); // filter top bid for each bucket by bidder @@ -43,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.sort((a, b) => b.cpm - a.cpm); + bucketBids = dealPrioritization ? bucketBids(sortByDealAndPriceBucketOrCpm(true)) : bucketBids.sort((a, b) => b.cpm - a.cpm); bids.push(...bucketBids.slice(0, adUnitBidLimit)); } else { bids.push(...bucketBids); @@ -73,17 +74,23 @@ export function getHighestCpmBidsFromBidPool(bidsReceived, highestCpmCallback, a * "hb_pb": "2" * }] */ -export function sortByDealAndPriceBucket(a, b) { - if (a.adUnitTargeting.hb_deal !== undefined && b.adUnitTargeting.hb_deal === undefined) { - return -1; - } +export function sortByDealAndPriceBucketOrCpm(useCpm = false) { + return function(a, b) { + if (a.adUnitTargeting.hb_deal !== undefined && b.adUnitTargeting.hb_deal === undefined) { + return -1; + } - if ((a.adUnitTargeting.hb_deal === undefined && b.adUnitTargeting.hb_deal !== undefined)) { - return 1; - } + if ((a.adUnitTargeting.hb_deal === undefined && b.adUnitTargeting.hb_deal !== undefined)) { + return 1; + } - // assuming both values either have a deal or don't have a deal - sort by the hb_pb param - return b.adUnitTargeting.hb_pb - a.adUnitTargeting.hb_pb; + // assuming both values either have a deal or don't have a deal - sort by the hb_pb param + if (useCpm) { + return b.cpm - a.cpm; + } + + return b.adUnitTargeting.hb_pb - a.adUnitTargeting.hb_pb; + } } /** @@ -103,16 +110,18 @@ export function newTargeting(auctionManager) { latestAuctionForAdUnit[adUnitCode] = auctionId; }; - targeting.resetPresetTargeting = function(adUnitCode) { + targeting.resetPresetTargeting = function(adUnitCode, customSlotMatching) { if (isGptPubadsDefined()) { const adUnitCodes = getAdUnitCodes(adUnitCode); const adUnits = auctionManager.getAdUnits().filter(adUnit => includes(adUnitCodes, adUnit.code)); window.googletag.pubads().getSlots().forEach(slot => { + let customSlotMatchingFunc = utils.isFn(customSlotMatching) && customSlotMatching(slot); pbTargetingKeys.forEach(function(key) { // reset only registered adunits adUnits.forEach(function(unit) { if (unit.code === slot.getAdUnitPath() || - unit.code === slot.getSlotElementId()) { + unit.code === slot.getSlotElementId() || + (utils.isFn(customSlotMatchingFunc) && customSlotMatchingFunc(unit.code))) { slot.setTargeting(key, null); } }); @@ -233,7 +242,7 @@ export function newTargeting(auctionManager) { adUnitCode, adUnitTargeting: targetingCopy[adUnitCode] }; - }).sort(sortByDealAndPriceBucket); + }).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) { diff --git a/src/url.js b/src/url.js deleted file mode 100644 index c63bca2ca41..00000000000 --- a/src/url.js +++ /dev/null @@ -1,55 +0,0 @@ -export function parseQS(query) { - return !query ? {} : query - .replace(/^\?/, '') - .split('&') - .reduce((acc, criteria) => { - let [k, v] = criteria.split('='); - if (/\[\]$/.test(k)) { - k = k.replace('[]', ''); - acc[k] = acc[k] || []; - acc[k].push(v); - } else { - acc[k] = v || ''; - } - return acc; - }, {}); -} - -export function formatQS(query) { - return Object - .keys(query) - .map(k => Array.isArray(query[k]) - ? query[k].map(v => `${k}[]=${v}`).join('&') - : `${k}=${query[k]}`) - .join('&'); -} - -export function parse(url, options) { - let parsed = document.createElement('a'); - if (options && 'noDecodeWholeURL' in options && options.noDecodeWholeURL) { - parsed.href = url; - } else { - parsed.href = decodeURIComponent(url); - } - // in window.location 'search' is string, not object - let qsAsString = (options && 'decodeSearchAsString' in options && options.decodeSearchAsString); - return { - href: parsed.href, - protocol: (parsed.protocol || '').replace(/:$/, ''), - hostname: parsed.hostname, - port: +parsed.port, - pathname: parsed.pathname.replace(/^(?!\/)/, '/'), - search: (qsAsString) ? parsed.search : parseQS(parsed.search || ''), - hash: (parsed.hash || '').replace(/^#/, ''), - host: parsed.host || window.location.host - }; -} - -export function format(obj) { - return (obj.protocol || 'http') + '://' + - (obj.host || - obj.hostname + (obj.port ? `:${obj.port}` : '')) + - (obj.pathname || '') + - (obj.search ? `?${formatQS(obj.search || '')}` : '') + - (obj.hash ? `#${obj.hash}` : ''); -} diff --git a/src/userSync.js b/src/userSync.js index fb5f4172a0d..fceeb1d722d 100644 --- a/src/userSync.js +++ b/src/userSync.js @@ -1,23 +1,28 @@ -import * as utils from './utils'; -import { config } from './config'; -import includes from 'core-js/library/fn/array/includes'; +import * as utils from './utils.js'; +import { config } from './config.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import { getCoreStorageManager } from './storageManager.js'; + +export const USERSYNC_DEFAULT_CONFIG = { + syncEnabled: true, + filterSettings: { + image: { + bidders: '*', + filter: 'include' + } + }, + syncsPerBidder: 5, + syncDelay: 3000, + auctionDelay: 0 +}; // Set userSync default values config.setDefaults({ - 'userSync': { - syncEnabled: true, - filterSettings: { - image: { - bidders: '*', - filter: 'include' - } - }, - syncsPerBidder: 5, - syncDelay: 3000, - auctionDelay: 0 - } + 'userSync': utils.deepClone(USERSYNC_DEFAULT_CONFIG) }); +const storage = getCoreStorageManager('usersync'); + /** * Factory function which creates a new UserSyncPool. * @@ -45,6 +50,20 @@ export function newUserSync(userSyncDependencies) { let usConfig = userSyncDependencies.config; // Update if it's (re)set config.getConfig('userSync', (conf) => { + // Added this logic for https://github.com/prebid/Prebid.js/issues/4864 + // if userSync.filterSettings does not contain image/all configs, merge in default image config to ensure image pixels are fired + if (conf.userSync) { + let fs = conf.userSync.filterSettings; + if (utils.isPlainObject(fs)) { + if (!fs.image && !fs.all) { + conf.userSync.filterSettings.image = { + bidders: '*', + filter: 'include' + }; + } + } + } + usConfig = Object.assign(usConfig, conf.userSync); }); @@ -283,7 +302,7 @@ export function newUserSync(userSyncDependencies) { return publicApi; } -const browserSupportsCookies = !utils.isSafariBrowser() && utils.cookiesAreEnabled(); +const browserSupportsCookies = !utils.isSafariBrowser() && storage.cookiesAreEnabled(); export const userSync = newUserSync({ config: config.getConfig('userSync'), diff --git a/src/utils.js b/src/utils.js index d3f37e5c7b5..88328ff10aa 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,11 +1,13 @@ -import { config } from './config'; +/* eslint-disable no-console */ +import { config } from './config.js'; import clone from 'just-clone'; -import find from 'core-js/library/fn/array/find'; -import includes from 'core-js/library/fn/array/includes'; +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'; -const CONSTANTS = require('./constants'); +const CONSTANTS = require('./constants.json'); -export { default as deepAccess } from 'dlv/index'; +export { default as deepAccess } from 'dlv/index.js'; export { default as deepSetValue } from 'dset'; var tArr = 'Array'; @@ -35,7 +37,10 @@ export const internal = { logError, logWarn, logMessage, - logInfo + logInfo, + parseQS, + formatQS, + deepEqual }; var uniqueRef = {}; @@ -49,28 +54,6 @@ export let bind = function(a, b) { return b; }.bind(null, 1, uniqueRef)() === un }; }; -/* - * Substitutes into a string from a given map using the token - * Usage - * var str = 'text %%REPLACE%% this text with %%SOMETHING%%'; - * var map = {}; - * map['replace'] = 'it was subbed'; - * map['something'] = 'something else'; - * console.log(replaceTokenInString(str, map, '%%')); => "text it was subbed this text with something else" - */ -export function replaceTokenInString(str, map, token) { - _each(map, function (value, key) { - value = (value === undefined) ? '' : value; - - var keyString = token + key.toUpperCase() + token; - var re = new RegExp(keyString, 'g'); - - str = str.replace(re, value); - }); - - return str; -} - /* utility method to get incremental integer starting from 1 */ var getIncrementalInteger = (function () { var count = 0; @@ -119,7 +102,7 @@ export function getBidIdParameter(key, paramsObj) { export function tryAppendQueryString(existingUrl, key, value) { if (value) { - return existingUrl += key + '=' + encodeURIComponent(value) + '&'; + return existingUrl + key + '=' + encodeURIComponent(value) + '&'; } return existingUrl; @@ -127,12 +110,13 @@ export function tryAppendQueryString(existingUrl, key, value) { // parse a query string object passed in bid params // bid params should be an object such as {key: "value", key1 : "value1"} +// aliases to formatQS export function parseQueryStringParameters(queryObj) { let result = ''; for (var k in queryObj) { if (queryObj.hasOwnProperty(k)) { result += k + '=' + encodeURIComponent(queryObj[k]) + '&'; } } - + result = result.replace(/&$/, ''); return result; } @@ -319,53 +303,9 @@ export function createInvisibleIframe() { * and if it does return the value */ export function getParameterByName(name) { - var regexS = '[\\?&]' + name + '=([^&#]*)'; - var regex = new RegExp(regexS); - var results = regex.exec(window.location.search); - if (results === null) { - return ''; - } - - return decodeURIComponent(results[1].replace(/\+/g, ' ')); + return parseQS(getWindowLocation().search)[name] || ''; } -/** - * This function validates paramaters. - * @param {Object} paramObj [description] - * @param {string[]} requiredParamsArr [description] - * @return {boolean} Bool if paramaters are valid - */ -export function hasValidBidRequest(paramObj, requiredParamsArr, adapter) { - var found = false; - - function findParam(value, key) { - if (key === requiredParamsArr[i]) { - found = true; - } - } - - for (var i = 0; i < requiredParamsArr.length; i++) { - found = false; - - _each(paramObj, findParam); - - if (!found) { - logError('Params are missing for bid request. One of these required paramaters are missing: ' + requiredParamsArr, adapter); - return false; - } - } - - return true; -} - -// Handle addEventListener gracefully in older browsers -export function addEventHandler(element, event, func) { - if (element.addEventListener) { - element.addEventListener(event, func, true); - } else if (element.attachEvent) { - element.attachEvent('on' + event, func); - } -} /** * Return if the object is of the * given type. @@ -470,15 +410,6 @@ export function contains(a, obj) { return false; } -export let indexOf = (function () { - if (Array.prototype.indexOf) { - return Array.prototype.indexOf; - } - - // ie8 no longer supported - // return polyfills.indexOf; -}()); - /** * Map an array or object into another array * given a function @@ -646,32 +577,6 @@ export function createTrackPixelIframeHtml(url, encodeUri = true, sandbox = '') `; } -/** - * Returns iframe document in a browser agnostic way - * @param {Object} iframe reference - * @return {Object} iframe `document` reference - */ -export function getIframeDocument(iframe) { - if (!iframe) { - return; - } - - let doc; - try { - if (iframe.contentWindow) { - doc = iframe.contentWindow.document; - } else if (iframe.contentDocument.document) { - doc = iframe.contentDocument.document; - } else { - doc = iframe.contentDocument; - } - } catch (e) { - internal.logError('Cannot get iframe document', e); - } - - return doc; -} - export function getValueString(param, val, defaultValue) { if (val === undefined || val === null) { return defaultValue; @@ -791,16 +696,6 @@ export function adUnitsFilter(filter, bid) { return includes(filter, bid && bid.adUnitCode); } -/** - * Check if parent iframe of passed document supports content rendering via 'srcdoc' property - * @param {HTMLDocument} doc document to check support of 'srcdoc' - */ -export function isSrcdocSupported(doc) { - // Firefox is excluded due to https://bugzilla.mozilla.org/show_bug.cgi?id=1265961 - return doc.defaultView && doc.defaultView.frameElement && - 'srcdoc' in doc.defaultView.frameElement && !/firefox/i.test(navigator.userAgent); -} - export function deepClone(obj) { return clone(obj); } @@ -814,7 +709,7 @@ export function inIframe() { } export function isSafariBrowser() { - return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + return /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent); } export function replaceAuctionPrice(str, cpm) { @@ -826,37 +721,20 @@ export function timestamp() { return new Date().getTime(); } -export function checkCookieSupport() { - if (window.navigator.cookieEnabled || !!document.cookie.length) { - return true; - } -} -export function cookiesAreEnabled() { - if (internal.checkCookieSupport()) { - return true; - } - window.document.cookie = 'prebid.cookieTest'; - return window.document.cookie.indexOf('prebid.cookieTest') != -1; -} - -export function getCookie(name) { - let m = window.document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]*)\\s*(;|$)'); - return m ? decodeURIComponent(m[2]) : null; -} - -export function setCookie(key, value, expires, sameSite) { - document.cookie = `${key}=${encodeURIComponent(value)}${(expires !== '') ? `; expires=${expires}` : ''}; path=/${sameSite ? `; SameSite=${sameSite}` : ''}`; +/** + * When the deviceAccess flag config option is false, no cookies should be read or set + * @returns {boolean} + */ +export function hasDeviceAccess() { + return config.getConfig('deviceAccess') !== false; } /** - * @returns {boolean} + * @returns {(boolean|undefined)} */ -export function localStorageIsEnabled () { - try { - localStorage.setItem('prebid.cookieTest', '1'); - return localStorage.getItem('prebid.cookieTest') === '1'; - } catch (error) { - return false; +export function checkCookieSupport() { + if (window.navigator.cookieEnabled || !!document.cookie.length) { + return true; } } @@ -899,19 +777,6 @@ export function groupBy(xs, key) { }, {}); } -/** - * Returns content for a friendly iframe to execute a URL in script tag - * @param {string} url URL to be executed in a script tag in a friendly iframe - * and are macros left to be replaced if required - */ -export function createContentToExecuteExtScriptInFriendlyFrame(url) { - if (!url) { - return ''; - } - - return ``; -} - /** * Build an object consisting of only defined parameters to avoid creating an * object with defined keys and undefined values. @@ -1014,6 +879,24 @@ export function isSlotMatchingAdUnitCode(adUnitCode) { return (slot) => compareCodeAndSlot(slot, adUnitCode); } +/** + * @summary Uses the adUnit's code in order to find a matching gptSlot on the page + */ +export function getGptSlotInfoForAdUnitCode(adUnitCode) { + let matchingSlot; + if (isGptPubadsDefined()) { + // find the first matching gpt slot on the page + matchingSlot = find(window.googletag.pubads().getSlots(), isSlotMatchingAdUnitCode(adUnitCode)); + } + if (matchingSlot) { + return { + gptSlot: matchingSlot.getAdUnitPath(), + divId: matchingSlot.getSlotElementId() + } + } + return {}; +}; + /** * Constructs warning message for when unsupported bidders are dropped from an adunit * @param {Object} adUnit ad unit from which the bidder is being dropped @@ -1030,18 +913,6 @@ export function unsupportedBidderMessage(adUnit, bidder) { `; } -/** - * Delete property from object - * @param {Object} object - * @param {string} prop - * @return {Object} object - */ -export function deletePropertyFromObject(object, prop) { - let result = Object.assign({}, object); - delete result[prop]; - return result; -} - /** * Checks input is integer or not * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger @@ -1178,32 +1049,6 @@ export function convertTypes(types, params) { return params; } -export function setDataInLocalStorage(key, value) { - if (hasLocalStorage()) { - window.localStorage.setItem(key, value); - } -} - -export function getDataFromLocalStorage(key) { - if (hasLocalStorage()) { - return window.localStorage.getItem(key); - } -} - -export function removeDataFromLocalStorage(key) { - if (hasLocalStorage()) { - window.localStorage.removeItem(key); - } -} - -export function hasLocalStorage() { - try { - return !!window.localStorage; - } catch (e) { - logError('Local storage api disabled'); - } -} - export function isArrayOfNums(val, size) { return (isArray(val)) && ((size) ? val.length === size : true) && (val.every(v => isInteger(v))); } @@ -1266,3 +1111,93 @@ export function compareOn(property) { return 0; } } + +export function parseQS(query) { + return !query ? {} : query + .replace(/^\?/, '') + .split('&') + .reduce((acc, criteria) => { + let [k, v] = criteria.split('='); + if (/\[\]$/.test(k)) { + k = k.replace('[]', ''); + acc[k] = acc[k] || []; + acc[k].push(v); + } else { + acc[k] = v || ''; + } + return acc; + }, {}); +} + +export function formatQS(query) { + return Object + .keys(query) + .map(k => Array.isArray(query[k]) + ? query[k].map(v => `${k}[]=${v}`).join('&') + : `${k}=${query[k]}`) + .join('&'); +} + +export function parseUrl(url, options) { + let parsed = document.createElement('a'); + if (options && 'noDecodeWholeURL' in options && options.noDecodeWholeURL) { + parsed.href = url; + } else { + parsed.href = decodeURIComponent(url); + } + // in window.location 'search' is string, not object + let qsAsString = (options && 'decodeSearchAsString' in options && options.decodeSearchAsString); + return { + href: parsed.href, + protocol: (parsed.protocol || '').replace(/:$/, ''), + hostname: parsed.hostname, + port: +parsed.port, + pathname: parsed.pathname.replace(/^(?!\/)/, '/'), + search: (qsAsString) ? parsed.search : internal.parseQS(parsed.search || ''), + hash: (parsed.hash || '').replace(/^#/, ''), + host: parsed.host || window.location.host + }; +} + +export function buildUrl(obj) { + return (obj.protocol || 'http') + '://' + + (obj.host || + obj.hostname + (obj.port ? `:${obj.port}` : '')) + + (obj.pathname || '') + + (obj.search ? `?${internal.formatQS(obj.search || '')}` : '') + + (obj.hash ? `#${obj.hash}` : ''); +} + +/** + * This function compares two objects for checking their equivalence. + * @param {Object} obj1 + * @param {Object} obj2 + * @returns {boolean} + */ +export function deepEqual(obj1, obj2) { + return deepequal(obj1, obj2); +} + +export function mergeDeep(target, ...sources) { + if (!sources.length) return target; + const source = sources.shift(); + + if (isPlainObject(target) && isPlainObject(source)) { + for (const key in source) { + if (isPlainObject(source[key])) { + if (!target[key]) Object.assign(target, { [key]: {} }); + mergeDeep(target[key], source[key]); + } else if (isArray(source[key])) { + if (!target[key]) { + Object.assign(target, { [key]: source[key] }); + } else if (isArray(target[key])) { + target[key] = target[key].concat(source[key]); + } + } else { + Object.assign(target, { [key]: source[key] }); + } + } + } + + return mergeDeep(target, ...sources); +} diff --git a/src/video.js b/src/video.js index 57f44a76764..befeb2ded39 100644 --- a/src/video.js +++ b/src/video.js @@ -1,8 +1,8 @@ -import adapterManager from './adapterManager'; -import { getBidRequest, deepAccess, logError } from './utils'; -import { config } from '../src/config'; -import includes from 'core-js/library/fn/array/includes'; -import { hook } from './hook'; +import adapterManager from './adapterManager.js'; +import { getBidRequest, deepAccess, logError } from './utils.js'; +import { config } from '../src/config.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import { hook } from './hook.js'; const VIDEO_MEDIA_TYPE = 'video'; export const OUTSTREAM = 'outstream'; diff --git a/src/videoCache.js b/src/videoCache.js index 4a715cb1fe3..9f1fd7e4117 100644 --- a/src/videoCache.js +++ b/src/videoCache.js @@ -9,8 +9,9 @@ * This trickery helps integrate with ad servers, which set character limits on request params. */ -import { ajax } from './ajax'; -import { config } from '../src/config'; +import { ajax } from './ajax.js'; +import { config } from './config.js'; +import * as utils from './utils.js'; /** * @typedef {object} CacheableUrlBid @@ -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/.eslintrc.js b/test/.eslintrc.js index 4cd5a854ac4..842bccd99b1 100644 --- a/test/.eslintrc.js +++ b/test/.eslintrc.js @@ -35,6 +35,6 @@ module.exports = { "no-unused-vars": "off", "no-use-before-define": "off", "no-useless-escape": "off", - "one-var": "off", + "one-var": "off" } }; diff --git a/test/fake-server/README.md b/test/fake-server/README.md new file mode 100644 index 00000000000..2e93fa44947 --- /dev/null +++ b/test/fake-server/README.md @@ -0,0 +1,28 @@ +## fake-server + +A simple http server that matches incoming requests to a stored list of `request-response` pair, and returns a fake response. The server is meant to replace actual calls to `appnexus` adapter (extendable to any other adapter) endpoint when the e2e tests runs. + + +## How to add a Request - Response pair ? + +All the `request-response` pairs are stored in the `fixtures/` directory. They are organized by their test group and test name. + +Follow the steps below to add another `request-response` pair. + +1. Inside the `/fixtures` directory, create a directory and give it a suitable name. + - If you are creating a one-off type of test, you can name this directory with a name that describes the test; for example `basic-banner`. + - If you plan to create a series of tests focusing on one feature/topic, then you can create a generic container directory to hold all your tests together; for example `longform`. + - If you did the latter case, please proceed to create the necessary test directories describing them with a meaningful and **unique** test name. +2. If you are planning to handle multiple bidder requests as part of your tests, you will need to create a specific directory for each request. For example, you could create a pair named like so `longform_biddersettings_1` and `longform_biddersettings_2`. +3. Once all your directories are created, inside the bottom test folder(s), create **three files**: + - `description.md` (Contains path of test page and spec file. Also, contains the ad unit that generates the **request-response** pair) + - `request.json` (This object will be matched against the acutal incoming request) + - `response.json` (This object will be returned as response of the fake-server, if the response object's request pair matchest the incoming request) + +For reference, please have a look at `fixtures/basic-banner` or `fixtures/longform` directories (as matching your scenario). + +## How is the server initiated ? + +When the command `gulp e2e-test --host=test.localhost` is executed, gulp task `test` automatically spawns the `fake-server` which runs on port `4444`. + +On execution of the tests, the server automatically stops. \ No newline at end of file diff --git a/test/fake-server/fake-responder.js b/test/fake-server/fake-responder.js new file mode 100644 index 00000000000..c884b00ca9c --- /dev/null +++ b/test/fake-server/fake-responder.js @@ -0,0 +1,75 @@ +/* eslint no-console: 0 */ +const deepEqual = require('deep-equal'); +const generateFixtures = require('./fixtures'); +const path = require('path'); + +// path to the fixture directory +const fixturesPath = path.join(__dirname, 'fixtures'); + +// An object storing 'Request-Response' pairs. +let REQ_RES_MAP = generateFixtures(fixturesPath); + +/** + * Matches 'req.body' with the responseBody pair + * @param {object} requestBody - `req.body` of incoming request hitting middleware 'fakeResponder'. + * @returns {objct} responseBody + */ +const matchResponse = function (requestBody) { + let actualUuids = []; + + const requestResponsePairs = Object.keys(REQ_RES_MAP).map(testName => REQ_RES_MAP[testName]); + + // delete 'uuid' property + requestBody.tags.forEach(body => { + // store the 'uuid' before deleting it. + actualUuids.push(body.uuid); + + // delete the 'uuid' + delete body.uuid; + }); + + ['sdk', 'referrer_detection', 'gdpr_consent'].forEach(prop => { + if (requestBody && requestBody[prop]) { + delete requestBody[prop]; + } + }); + + // delete 'uuid' from `expected request body` + requestResponsePairs + .forEach(reqRes => { reqRes.request.httpRequest && reqRes.request.httpRequest.body.tags.forEach(body => body.uuid && delete body.uuid) }); + + // match the 'actual' requestBody with the 'expected' requestBody and find the 'responseBody' + const responseBody = requestResponsePairs.filter(reqRes => reqRes.request.httpRequest && deepEqual(reqRes.request.httpRequest.body.tags, requestBody.tags))[0].response.httpResponse.body; + + // ENABLE THE FOLLOWING CODE FOR TROUBLE-SHOOTING FAKED REQUESTS; COMMENT AGAIN WHEN DONE + // console.log('value found for responseBody:', responseBody); + // responseBody.tags.forEach((tag, index) => { + // console.log('value found for responseBody.tag[', index, ']:ads', tag.ads); + // }); + + // copy the actual uuids to the responseBody + // TODO:: what if responseBody is 'undefined' + responseBody.tags.forEach(body => { + body.uuid = actualUuids.shift(); + }); + + return responseBody; +} + +/** + * An ExpressJs middleware function that checks the incoming Request Body + * and returns the corresponding Fake Response Body pertaining to that Request. + */ + +const fakeResponder = function (req, res, next) { + const request = JSON.parse(req.body); + + const response = matchResponse(request); + + res.type('json'); + res.write(JSON.stringify(response)); + + next(); +} + +module.exports = fakeResponder; diff --git a/test/fake-server/fixtures/basic-banner/description.md b/test/fake-server/fixtures/basic-banner/description.md new file mode 100644 index 00000000000..45ef571aaac --- /dev/null +++ b/test/fake-server/fixtures/basic-banner/description.md @@ -0,0 +1,34 @@ +Test Page - 'test/pages/banner.html' +Test Spec File - 'test/spec/e2e/banner/basic_banner_ad.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'div-gpt-ad-1460505748561-0', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13144370 + } + }] +}, { + code: 'div-gpt-ad-1460505748561-1', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + bids: [{ + bidder: "appnexus", + params: { + placementId: 13144370 + } + }] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-banner/request.json b/test/fake-server/fixtures/basic-banner/request.json new file mode 100644 index 00000000000..ea85b5a6842 --- /dev/null +++ b/test/fake-server/fixtures/basic-banner/request.json @@ -0,0 +1,61 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 300, + "height": 250 + }, + { + "width": 300, + "height": 600 + } + ], + "primary_size": { + "width": 300, + "height": 250 + }, + "ad_types": [ + "banner" + ], + "id": 13144370, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 1 + }, + { + "sizes": [ + { + "width": 300, + "height": 250 + }, + { + "width": 300, + "height": 600 + } + ], + "primary_size": { + "width": 300, + "height": 250 + }, + "ad_types": [ + "banner" + ], + "id": 13144370, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-banner/response.json b/test/fake-server/fixtures/basic-banner/response.json new file mode 100644 index 00000000000..dc73d3fa3d2 --- /dev/null +++ b/test/fake-server/fixtures/basic-banner/response.json @@ -0,0 +1,92 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13144370, + "auction_id": "8147841645883553832", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKzCKAzBAAAAwDWAAUBCJKPpe4FEKjwl-js2byJcRiq5MnUovf28WEqNgkAAAkCABEJBywAABkAAACA61HgPyEREgApEQkAMREb8GkwsqKiBjjtSEDtSEgAUABYnPFbYABotc95eACAAQGKAQCSAQNVU0SYAawCoAH6AagBAbABALgBAcABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3MzQ3MjE0Nik7AR0scicsIDk2ODQ2MDM1Nh4A8PWSAqUCIXp6ZmhVQWl1c0s0S0VOT0JseTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlJSUNhQUJ3Q0hncWdBRWtpQUVxa0FFQW1BRUFvQUVCcUFFRHNBRUF1UUVwaTRpREFBRGdQOEVCS1l1SWd3QUE0RF9KQVozRkl5WjA1Tm9fMlFFQUFBQUFBQUR3UC1BQkFQVUJBQUFBQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU9BQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEcnJDdUNyb0RDVk5KVGpNNk5EY3pOZUFEcUJXSUJBQ1FCQUNZQkFIQkIFRQkBCHlRUQkJAQEUTmdFQVBFEY0BkEg0QkFDSUJmOGuaAokBIUl3OTBCOikBJG5QRmJJQVFvQUQROFhEZ1B6b0pVMGxPTXpvME56TTFRS2dWUxFoDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJTDTrYdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9oZWxsb193b3JsZAVO8EA_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAOsAsgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw248F6YBACiBAsxMC43NS43NC42OagEkECyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggA4AQB8ATTgZcuiAUBmAUAoAX______wEDFAHABQDJBWmAFPA_0gUJCQkMcAAA2AUB4AUB8AUB-gUECAAQAJAGAJgGALgGAMEGCSM08L_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgHyBgIIAIAHAYgHAKAHAQ..&s=68cfb6ed042ea47f5d3fc2c32cc068500e542066", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "banner", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 96846035, + "media_type_id": 1, + "media_subtype_id": 1, + "cpm": 0.5, + "cpm_publisher_currency": 0.5, + "is_bin_price_applied": false, + "publisher_currency_code": "$", + "brand_category_id": 0, + "test": 99999, + "client_initiated_ad_counting": true, + "rtb": { + "banner": { + "content": "
", + "width": 300, + "height": 250 + }, + "trackers": [ + { + "impression_urls": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue&e=wqT_3QK7CKA7BAAAAwDWAAUBCJKPpe4FEKjwl-js2byJcRiq5MnUovf28WEqNgkAAAECCOA_EQEHNAAA4D8ZAAAAgOtR4D8hERIAKREJADERG6gwsqKiBjjtSEDtSEgCUNOBly5YnPFbYABotc95eJK4BYABAYoBA1VTRJIBAQbwUpgBrAKgAfoBqAEBsAEAuAEBwAEEyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTczNDcyMTQ2KTt1ZigncicsIDk2ODQ2MDM1Nh4A8PWSAqUCIXp6ZmhVQWl1c0s0S0VOT0JseTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlJSUNhQUJ3Q0hncWdBRWtpQUVxa0FFQW1BRUFvQUVCcUFFRHNBRUF1UUVwaTRpREFBRGdQOEVCS1l1SWd3QUE0RF9KQVozRkl5WjA1Tm9fMlFFQUFBQUFBQUR3UC1BQkFQVUJBQUFBQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU9BQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEcnJDdUNyb0RDVk5KVGpNNk5EY3pOZUFEcUJXSUJBQ1FCQUNZQkFIQkIFRQkBCHlRUQkJAQEUTmdFQVBFEY0BkEg0QkFDSUJmOGuaAokBIUl3OTBCOikBJG5QRmJJQVFvQUQROFhEZ1B6b0pVMGxPTXpvME56TTFRS2dWUxFoDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJTDTrYdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9oZWxsb193b3JsZAVO8EA_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAOsAsgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw248F6YBACiBAsxMC43NS43NC42OagEkECyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggB4AQB8ATTgZcuiAUBmAUAoAX______wEDFAHABQDJBWmIFPA_0gUJCQkMcAAA2AUB4AUB8AUB-gUECAAQAJAGAJgGALgGAMEGCSM08D_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgHyBgIIAIAHAYgHAKAHAQ..&s=951a029669a69e3f0c527c937c2d852be92802e1" + ], + "video_events": {} + } + ] + } + } + ] + }, + { + "tag_id": 13144370, + "auction_id": "8147841645883553832", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKzCKAzBAAAAwDWAAUBCJKPpe4FEKjwl-js2byJcRiq5MnUovf28WEqNgkAAAkCABEJBywAABkAAACA61HgPyEREgApEQkAMREb8GkwsqKiBjjtSEDtSEgAUABYnPFbYABotc95eACAAQGKAQCSAQNVU0SYAawCoAH6AagBAbABALgBAcABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3MzQ3MjE0Nik7AR0scicsIDk2ODQ2MDM1Nh4A8PWSAqUCIXp6ZmhVQWl1c0s0S0VOT0JseTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlJSUNhQUJ3Q0hncWdBRWtpQUVxa0FFQW1BRUFvQUVCcUFFRHNBRUF1UUVwaTRpREFBRGdQOEVCS1l1SWd3QUE0RF9KQVozRkl5WjA1Tm9fMlFFQUFBQUFBQUR3UC1BQkFQVUJBQUFBQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU9BQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEcnJDdUNyb0RDVk5KVGpNNk5EY3pOZUFEcUJXSUJBQ1FCQUNZQkFIQkIFRQkBCHlRUQkJAQEUTmdFQVBFEY0BkEg0QkFDSUJmOGuaAokBIUl3OTBCOikBJG5QRmJJQVFvQUQROFhEZ1B6b0pVMGxPTXpvME56TTFRS2dWUxFoDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJTDTrYdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9oZWxsb193b3JsZAVO8EA_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAOsAsgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw248F6YBACiBAsxMC43NS43NC42OagEkECyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggA4AQB8ATTgZcuiAUBmAUAoAX______wEDFAHABQDJBWmAFPA_0gUJCQkMcAAA2AUB4AUB8AUB-gUECAAQAJAGAJgGALgGAMEGCSM08L_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgHyBgIIAIAHAYgHAKAHAQ..&s=68cfb6ed042ea47f5d3fc2c32cc068500e542066", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "banner", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 968460356666, + "media_type_id": 1, + "media_subtype_id": 1, + "cpm": 0.5, + "cpm_publisher_currency": 0.5, + "is_bin_price_applied": false, + "publisher_currency_code": "$", + "brand_category_id": 0, + "client_initiated_ad_counting": true, + "rtb": { + "banner": { + "content": "
", + "width": 300, + "height": 250 + }, + "trackers": [ + { + "impression_urls": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue&e=wqT_3QK7CKA7BAAAAwDWAAUBCJKPpe4FEKjwl-js2byJcRiq5MnUovf28WEqNgkAAAECCOA_EQEHNAAA4D8ZAAAAgOtR4D8hERIAKREJADERG6gwsqKiBjjtSEDtSEgCUNOBly5YnPFbYABotc95eJK4BYABAYoBA1VTRJIBAQbwUpgBrAKgAfoBqAEBsAEAuAEBwAEEyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTczNDcyMTQ2KTt1ZigncicsIDk2ODQ2MDM1Nh4A8PWSAqUCIXp6ZmhVQWl1c0s0S0VOT0JseTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlJSUNhQUJ3Q0hncWdBRWtpQUVxa0FFQW1BRUFvQUVCcUFFRHNBRUF1UUVwaTRpREFBRGdQOEVCS1l1SWd3QUE0RF9KQVozRkl5WjA1Tm9fMlFFQUFBQUFBQUR3UC1BQkFQVUJBQUFBQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU9BQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEcnJDdUNyb0RDVk5KVGpNNk5EY3pOZUFEcUJXSUJBQ1FCQUNZQkFIQkIFRQkBCHlRUQkJAQEUTmdFQVBFEY0BkEg0QkFDSUJmOGuaAokBIUl3OTBCOikBJG5QRmJJQVFvQUQROFhEZ1B6b0pVMGxPTXpvME56TTFRS2dWUxFoDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJTDTrYdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2dwdC9oZWxsb193b3JsZAVO8EA_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAOsAsgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw248F6YBACiBAsxMC43NS43NC42OagEkECyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggB4AQB8ATTgZcuiAUBmAUAoAX______wEDFAHABQDJBWmIFPA_0gUJCQkMcAAA2AUB4AUB8AUB-gUECAAQAJAGAJgGALgGAMEGCSM08D_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgHyBgIIAIAHAYgHAKAHAQ..&s=951a029669a69e3f0c527c937c2d852be92802e1" + ], + "video_events": {} + } + ] + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-instream/description.md b/test/fake-server/fixtures/basic-instream/description.md new file mode 100644 index 00000000000..5d185f23ad3 --- /dev/null +++ b/test/fake-server/fixtures/basic-instream/description.md @@ -0,0 +1,28 @@ +Test Page - 'test/pages/instream.html' +Test Spec File - 'test/spec/e2e/instream/basic_instream_ad.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'video1', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480] + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: '13232361', + video: { + skipppable: false, + playback_methods: ['auto_play_sound_off'] + } + } + } + ] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-instream/request.json b/test/fake-server/fixtures/basic-instream/request.json new file mode 100644 index 00000000000..db07ad3e98a --- /dev/null +++ b/test/fake-server/fixtures/basic-instream/request.json @@ -0,0 +1,34 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 13232361, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "require_asset_url": true, + "video": {}, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-instream/response.json b/test/fake-server/fixtures/basic-instream/response.json new file mode 100644 index 00000000000..5f51034f0be --- /dev/null +++ b/test/fake-server/fixtures/basic-instream/response.json @@ -0,0 +1,42 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [{ + "tag_id": 13232361, + "auction_id": "1398509384102899505", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Finstream.html&e=wqT_3QKxCKAxBAAAAwDWAAUBCKXQzPAFELHeg_SAnKC0ExjCs_b6q5D9_0oqNgkAAAkCABEJBywAABkAAADgehQUQCEREgApEQkAMREb8Hkw6dGnBjjtSEDtSEgAUABYnPFbYABozbp1eACAAQGKAQCSAQNVU0SYAQGgAQGoAQGwAQC4AQPAAQDIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzgzMTM3NjUpO3VmKCdyJywgOTc1MTc3NzEsIC4eAPD1kgK1AiF5andtb2dpMi1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNmRHbkJsZ0FZTUlHYUFCd0tIZ0dnQUU4aUFFR2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFVUU1FQjg2MXFwQUFBRkVESkFmZjUwcVFyNGVvXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHR2aThDcm9EQ1ZOSlRqTTZORGN6T09BRC1SaUlCQUNRQkFDWUJBSEJCBUUJAQh5UVEJCQEBFE5nRUFQRRGNAZAsNEJBQ0lCWUlscVFVAREBFDx3UHcuLpoCiQEhTGc5WkRRNjkBJG5QRmJJQVFvQUQVSFRVUURvSlUwbE9Nem8wTnpNNFFQa1lTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBSZUFBLsICP2h0dHA6Ly9wcmViaWQub3JnL2Rldi1kb2NzL3Nob3ctdmlkZW8td2l0aC1hLWRmcC12aWRlby10YWcuaHRtbNgCAOACrZhI6gIzaHQFSkh0ZXN0LmxvY2FsaG9zdDo5OTk5BRQ4L3BhZ2VzL2luc3RyZWFtBT7IgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvCanwXpgEAKIECzEwLjc1Ljc0LjY5qAS0LLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM42gQCCADgBADwBMuBwC6IBQGYBQCgBf______AQMUAcAFAMkFaX8U8D_SBQkJCQx4AADYBQHgBQHwBcOVC_oFBAgAEACQBgGYBgC4BgDBBgklKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=6805157848bdfdf973d0dbafff4bb9b4c4ce7e60", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [{ + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQklKBNeAAAAABEx74AO4IBoExklKBNeAAAAACDLgcAuKAAw7Ug47UhA0-hISLuv1AFQ6dGnBljDlQtiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcuBwC6wAQE.&s=07e6e5f2f03cc92e899c3ddbf4e2988e966caaa2&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97517771, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10.000000, + "cpm_publisher_currency": 10.000000, + "publisher_currency_code": "$", + "brand_category_id": 36, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": ["auto_play_sound_on"], + "frameworks": ["vpaid_1_0", "vpaid_2_0"], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Finstream.html&e=wqT_3QKNCaCNBAAAAwDWAAUBCKXQzPAFELHeg_SAnKC0ExjCs_b6q5D9_0oqNgkAAAECCBRAEQEHNAAAFEAZAAAA4HoUFEAhERIAKREJADERG6gw6dGnBjjtSEDtSEgCUMuBwC5YnPFbYABozbp1eJG4BYABAYoBA1VTRJIBAQbwUpgBAaABAagBAbABALgBA8ABBMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3ODMxMzc2NSk7dWYoJ3InLCA5NzUxNzc3MSwgLh4A8PWSArUCIXlqd21vZ2kyLUx3S0VNdUJ3QzRZQUNDYzhWc3dBRGdBUUFSSTdVaFE2ZEduQmxnQVlNSUdhQUJ3S0hnR2dBRThpQUVHa0FFQW1BRUFvQUVCcUFFRHNBRUF1UUh6cldxa0FBQVVRTUVCODYxcXBBQUFGRURKQWZmNTBxUXI0ZW9fMlFFQUFBQUFBQUR3UC1BQkFQVUJBQUFBQUpnQ0FLQUNBTFVDQUFBQUFMMENBQUFBQU9BQ0FPZ0NBUGdDQUlBREFaZ0RBYWdEdHZpOENyb0RDVk5KVGpNNk5EY3pPT0FELVJpSUJBQ1FCQUNZQkFIQkIFRQkBCHlRUQkJAQEUTmdFQVBFEY0BkCw0QkFDSUJZSWxxUVUBEQEUPHdQdy4umgKJASFMZzlaRFE2OQEkblBGYklBUW9BRBVIVFVRRG9KVTBsT016bzBOek00UVBrWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8FJlQUEuwgI_aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc2hvdy12aWRlby13aXRoLWEtZGZwLXZpZGVvLXRhZy5odG1s2AIA4AKtmEjqAjNodAVKSHRlc3QubG9jYWxob3N0Ojk5OTkFFDgvcGFnZXMvaW5zdHJlYW0FPmjyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-4ElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw398F6YBACiBAsxMC43NS43NC42OagEtCyyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczONoEAggB4AQA8ATLgcAuiAUBmAUAoAX______wEDFAHABQDJBWnbFPA_0gUJCQkMeAAA2AUB4AUB8AXDlQv6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=68b9d39d60a72307a201e479000a8c7be5508188" + } + } + }] + }] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-native/description.md b/test/fake-server/fixtures/basic-native/description.md new file mode 100644 index 00000000000..950cc5da7d7 --- /dev/null +++ b/test/fake-server/fixtures/basic-native/description.md @@ -0,0 +1,62 @@ +Test Page - 'test/pages/native.html' +Test Spec File - 'test/spec/e2e/native/basic_native_ad.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: '/19968336/prebid_native_example_1', + sizes: [360, 360], + mediaTypes: { + native: { + title: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + } + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232354, + allowSmallerSizes: true + } + }] +}, { + code: '/19968336/prebid_native_example_2', + sizes: [ + [1, 1] + ], + mediaTypes: { + native: { + title: { + required: true + }, + body: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + }, + icon: { + required: false + }, + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232354, + allowSmallerSizes: true + } + }] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-native/request.json b/test/fake-server/fixtures/basic-native/request.json new file mode 100644 index 00000000000..08e75d5bd69 --- /dev/null +++ b/test/fake-server/fixtures/basic-native/request.json @@ -0,0 +1,81 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 1, + "height": 1 + } + ], + "ad_types": [ + "native" + ], + "id": 13232354, + "allow_smaller_sizes": true, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "native": { + "layouts": [ + { + "title": { + "required": true + }, + "main_image": { + "required": true + }, + "sponsored_by": { + "required": true + } + } + ] + }, + "hb_source": 1 + }, + { + "sizes": [ + { + "width": 1, + "height": 1 + } + ], + "ad_types": [ + "native" + ], + "id": 13232354, + "allow_smaller_sizes": true, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "native": { + "layouts": [ + { + "title": { + "required": true + }, + "description": { + "required": true + }, + "main_image": { + "required": true + }, + "sponsored_by": { + "required": true + }, + "icon": { + "required": false + } + } + ] + }, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-native/response.json b/test/fake-server/fixtures/basic-native/response.json new file mode 100644 index 00000000000..fb85110663d --- /dev/null +++ b/test/fake-server/fixtures/basic-native/response.json @@ -0,0 +1,116 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13232354, + "auction_id": "2566965852006062421", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fnative.html&e=wqT_3QLhB6DhAwAAAwDWAAUBCNDZme8FENWyhPv4uuzPIxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMOLRpwY47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc1MzgyMjI0KTsBHThyJywgOTc0OTQ0MDMsIDEdHvDQkgKpAiFCenhPTlFqOC1Md0tFSVBMdmk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNHRHbkJsZ0FZSUlDYUFCd0FIZ0FnQUdtQVlnQl9GLVFBUUNZQVFDZ0FRR29BUU93QVFDNUFmT3RhcVFBQUNSQXdRSHpyV3FrQUFBa1FNa0JRTDdBTHVfbzFqX1pBUUFBQUFBQUFQQV80QUVBOVFFQUFBQUFtQUlBb0FJQXRRSUFBQUFBdlFJQUFBQUE0QUlBNkFJQS1BSUFnQU1CbUFNQnFBUDgBxIh1Z01KVTBsT016bzBOelF5NEFQbUZvZ0VBSkFFQUpnRUFjRQldBQEIREpCBQgJARgyQVFBOFFRCQ0BAVBQZ0VBSWdGaGlVLpoCiQEhYWdfb0o6LQEkblBGYklBUW9BRBVYDGtRRG8yhQAQUU9ZV1MRWAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0MoGVBQS7YAgDgAq2YSOoCMWh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5BRTwvC9wYWdlcy9uYXRpdmUuaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qATruAKyBA4IABABGAAgACgAMAA4ArgEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQy2gQCCADgBAHwBIPLvi6IBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQkMeAAA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYJJTTwv8gGANAG9S_aBhYKEAkUGQFQEAAYAOAGDPIGAggAgAcBiAcAoAdB&s=54514bb848c51d509dfe3e21af09b77edfe9738e", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "native", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97494403, + "media_type_id": 12, + "media_subtype_id": 65, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 53, + "client_initiated_ad_counting": true, + "viewability": { + "config": "" + }, + "rtb": { + "native": { + "title": "This is a Prebid Native Creative", + "sponsored": "Prebid.org", + "main_img": { + "url": "http://vcdn.adnxs.com/p/creative-image/94/22/cd/0f/9422cd0f-f400-45d3-80f5-2b92629d9257.jpg", + "width": 3000, + "height": 2250, + "prevent_crop": false + }, + "link": { + "url": "http://prebid.org/dev-docs/show-native-ads.html", + "click_trackers": [ + "http://sin3-ib.adnxs.com/click?AAAAAAAAJEAAAAAAAAAkQAAAAAAAACRAAAAAAAAAJEAAAAAAAAAkQFUZYY_XsZ8jKnKSKrrb42HQbOZdAAAAAOLoyQBtJAAAbSQAAAIAAACDpc8FnPgWAAAAAABVU0QAVVNEAAEAAQBNXQAAAAABAQQCAAAAALoA8BZszgAAAAA./bcr=AAAAAAAA8D8=/cnd=%21ag_oJQj8-LwKEIPLvi4YnPFbIAQoADEAAAAAAAAkQDoJU0lOMzo0NzQyQOYWSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA./cca=OTMyNSNTSU4zOjQ3NDI=/bn=89169/" + ] + }, + "impression_trackers": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fnative.html&e=wqT_3QLpB6DpAwAAAwDWAAUBCNDZme8FENWyhPv4uuzPIxiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlCDy74uWJzxW2AAaM26dXjRuAWAAQGKAQNVU0SSAQEG8FKYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzUzODIyMjQpO3VmKCdyJywgOTc0OTQ0MDMsIC4eAPDQkgKpAiFCenhPTlFqOC1Md0tFSVBMdmk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNHRHbkJsZ0FZSUlDYUFCd0FIZ0FnQUdtQVlnQl9GLVFBUUNZQVFDZ0FRR29BUU93QVFDNUFmT3RhcVFBQUNSQXdRSHpyV3FrQUFBa1FNa0JRTDdBTHVfbzFqX1pBUUFBQUFBQUFQQV80QUVBOVFFQUFBQUFtQUlBb0FJQXRRSUFBQUFBdlFJQUFBQUE0QUlBNkFJQS1BSUFnQU1CbUFNQnFBUDgBxIh1Z01KVTBsT016bzBOelF5NEFQbUZvZ0VBSkFFQUpnRUFjRQldBQEIREpCBQgJARgyQVFBOFFRCQ0BAVBQZ0VBSWdGaGlVLpoCiQEhYWdfb0o6LQEkblBGYklBUW9BRBVYDGtRRG8yhQAQUU9ZV1MRWAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0MoGVBQS7YAgDgAq2YSOoCMWh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5BRTwlS9wYWdlcy9uYXRpdmUuaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qATruAKyBA4IABABGAAgACgAMAA4ArgEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQy2gQCCAHgBAHwBEH6IIgFAZgFAKAF_xEBGAHABQDJBQAFARTwP9IFCQkFC3wAAADYBQHgBQHwBZn0IfoFBAgAEACQBgGYBgC4BgDBBgEhQAAA8D_IBgDQBvUv2gYWChAAOgEAUBAAGADgBgzyBgIIAIAHAYgHAKAHQQ..&s=6b203c7aee654cffa9c0b3771f6945f6d1e8d06c" + ], + "id": 97494403 + } + } + } + ] + }, + { + "tag_id": 13232354, + "auction_id": "6083251961435599864", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fnative.html&e=wqT_3QLhB6DhAwAAAwDWAAUBCNDZme8FEPjnxITbrYO2VBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMOLRpwY47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc1MzgyMjI0KTsBHSxyJywgOTc0OTQyMDQ2HgDw0JICqQIhYlR3OWZBajgtTHdLRUx6SnZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWUlJQ2FBQndBSGdBZ0FHbUFZZ0JfRi1RQVFDWUFRQ2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCeVdmYjBYeWIxVF9aQVFBQUFBQUFBUEFfNEFFQTlRRUFBQUFBbUFJQW9BSUF0UUlBQUFBQXZRSUFBQUFBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQVA4AcSIdWdNSlUwbE9Nem8wTnpReTRBUG1Gb2dFQUpBRUFKZ0VBY0UJXQUBCERKQgUICQEYMkFRQThRUQkNAQFUUGdFQUlnRmhpVS6aAokBIW9ROTNPUTYtASRuUEZiSUFRb0FEFVgMa1FEbzKFABBRT1lXUxFYDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQygZUFBLtgCAOACrZhI6gIxaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkFFPC8L3BhZ2VzL25hdGl2ZS5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBOu4ArIEDggAEAEYACAAKAAwADgCuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDLaBAIIAOAEAfAEvMm-LogFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJCQx4AADYBQHgBQHwBZn0IfoFBAgAEACQBgGYBgC4BgDBBgklNPC_yAYA0Ab1L9oGFgoQCRQZAVAQABgA4AYM8gYCCACABwGIBwCgB0E.&s=99a73b39ab82dd9384eee306ff03276ab688cfe5", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "native", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97494204, + "media_type_id": 12, + "media_subtype_id": 65, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 53, + "client_initiated_ad_counting": true, + "viewability": { + "config": "" + }, + "rtb": { + "native": { + "title": "This is a Prebid Native Creative", + "desc": "This is a Prebid Native Creative. There are many like it, but this one is mine.", + "sponsored": "Prebid.org", + "icon": { + "url": "http://vcdn.adnxs.com/p/creative-image/1a/3e/e9/5b/1a3ee95b-06cd-4260-98c7-0258627c9197.png", + "width": 127, + "height": 83, + "prevent_crop": false + }, + "main_img": { + "url": "http://vcdn.adnxs.com/p/creative-image/f8/7f/0f/13/f87f0f13-230c-4f05-8087-db9216e393de.jpg", + "width": 989, + "height": 742, + "prevent_crop": false + }, + "link": { + "url": "http://prebid.org/dev-docs/show-native-ads.html", + "click_trackers": [ + "http://sin3-ib.adnxs.com/click?AAAAAAAAJEAAAAAAAAAkQAAAAAAAACRAAAAAAAAAJEAAAAAAAAAkQPgzkbBtDWxUKnKSKrrb42HQbOZdAAAAAOLoyQBtJAAAbSQAAAIAAAC8pM8FnPgWAAAAAABVU0QAVVNEAAEAAQBNXQAAAAABAQQCAAAAALoAJhcX3AAAAAA./bcr=AAAAAAAA8D8=/cnd=%21oQ93OQj8-LwKELzJvi4YnPFbIAQoADEAAAAAAAAkQDoJU0lOMzo0NzQyQOYWSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA./cca=OTMyNSNTSU4zOjQ3NDI=/bn=89169/" + ] + }, + "impression_trackers": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fnative.html&e=wqT_3QLpB6DpAwAAAwDWAAUBCNDZme8FEPjnxITbrYO2VBiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlC8yb4uWJzxW2AAaM26dXjRuAWAAQGKAQNVU0SSAQEG8FKYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzUzODIyMjQpO3VmKCdyJywgOTc0OTQyMDQsIC4eAPDQkgKpAiFiVHc5ZkFqOC1Md0tFTHpKdmk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNHRHbkJsZ0FZSUlDYUFCd0FIZ0FnQUdtQVlnQl9GLVFBUUNZQVFDZ0FRR29BUU93QVFDNUFmT3RhcVFBQUNSQXdRSHpyV3FrQUFBa1FNa0J5V2ZiMFh5YjFUX1pBUUFBQUFBQUFQQV80QUVBOVFFQUFBQUFtQUlBb0FJQXRRSUFBQUFBdlFJQUFBQUE0QUlBNkFJQS1BSUFnQU1CbUFNQnFBUDgBxIh1Z01KVTBsT016bzBOelF5NEFQbUZvZ0VBSkFFQUpnRUFjRQldBQEIREpCBQgJARgyQVFBOFFRCQ0BAVRQZ0VBSWdGaGlVLpoCiQEhb1E5M09RNi0BJG5QRmJJQVFvQUQVWAxrUURvMoUAEFFPWVdTEVgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDKBlQUEu2AIA4AKtmEjqAjFodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OQUU8LwvcGFnZXMvbmF0aXZlLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagE67gCsgQOCAAQARgAIAAoADAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDc0MtoEAggB4AQB8AS8yb4uiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkJDHgAANgFAeAFAfAFmfQh-gUECAAQAJAGAZgGALgGAMEGCSU48D_IBgDQBvUv2gYWChAAOgEAUBAAGADgBgzyBgIIAIAHAYgHAKAHQQ..&s=5c316c116b6e2bdb19f3950c4c769821e735688e" + ], + "id": 97494204 + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-outstream/description.md b/test/fake-server/fixtures/basic-outstream/description.md new file mode 100644 index 00000000000..c5855d6af15 --- /dev/null +++ b/test/fake-server/fixtures/basic-outstream/description.md @@ -0,0 +1,44 @@ +Test Page - 'test/pages/outstream.html' +Test Spec File - 'test/spec/e2e/outstream/basic_outstream_ad.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'video_ad_unit_1', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480] + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232385, + video: { + skippable: true, + playback_method: ['auto_play_sound_off'] + } + } + }] +}, { + code: 'video_ad_unit_2', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480] + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232385, + video: { + skippable: true, + playback_method: ['auto_play_sound_off'] + } + } + }] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-outstream/request.json b/test/fake-server/fixtures/basic-outstream/request.json new file mode 100644 index 00000000000..611a518fc2d --- /dev/null +++ b/test/fake-server/fixtures/basic-outstream/request.json @@ -0,0 +1,50 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [{ + "sizes": [{ + "width": 640, + "height": 480 + }], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": ["video"], + "id": 13232385, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "video": { + "skippable": true, + "playback_method": ["auto_play_sound_off"] + }, + "hb_source": 1 + }, { + "sizes": [{ + "width": 640, + "height": 480 + }], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": ["video"], + "id": 13232385, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "video": { + "skippable": true, + "playback_method": ["auto_play_sound_off"] + }, + "hb_source": 1 + }], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/basic-outstream/response.json b/test/fake-server/fixtures/basic-outstream/response.json new file mode 100644 index 00000000000..13b4e527b1f --- /dev/null +++ b/test/fake-server/fixtures/basic-outstream/response.json @@ -0,0 +1,105 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13232385, + "auction_id": "527250675737245396", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Foutstream.html&e=wqT_3QKwCKAwBAAAAwDWAAUBCOiWpO8FENTtnJej9sqoBxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMIHSpwY47UhA7UhIAFAAWJzxW2AAaOWljwF4AIABAYoBAJIBA1VTRJgBAaABAagBAbABALgBA8ABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3NTU1Mzg5NikFHTRyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFUenpuS1FqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSG5NQW5aODYzalA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TOEE4RDgumgKJASFXdzkxSDo5ASRuUEZiSUFRb0FEFVhYa1FEb0pVMGxPTXpvME9ETTBRUGtXU1ENTwxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8EllQUEuwgI4aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc2hvdy1vdXRzdHJlYW0tdmlkZW8tYWRzLmh0bWzYAgDgAq2YSOoCNA1DSHRlc3QubG9jYWxob3N0Ojk5OTkFFBgvcGFnZXMvFUkALgE_yIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzLwmj8F6YBACiBAsxMC43NS43NC42OagEmM8CsgQSCAQQBBiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ4MzTaBAIIAOAEAPAEy4HALogFAZgFAKAF_____wUDFAHABQDJBWlyFPA_0gUJCQkMeAAA2AUB4AUB8AXDlQv6BQQIABAAkAYBmAYAuAYAwQYJJTTwv8gGANAG9S_aBhYKEAkUGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=9953ce4d94992db04897ab580bf81b3e274b2601", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQloC-ldAAAAABHUNucysitRBxloC-ldAAAAACDLgcAuKAAw7Ug47UhA0-hISLuv1AFQgdKnBljDlQtiAi0taAFwAXgAgAECiAEEkAGABZgB4AOgAQCoAcuBwC6wAQE.&s=979aee1106a0bea5609a3c23fdc46153ad6d9eec&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97517771, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 36, + "renderer_url": "http://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js", + "renderer_id": 2, + "renderer_config": "{\"skippable\":{\"videoThreshold\":null,\"skipLocation\":\"top-right\"}}", + "client_initiated_ad_counting": true, + "viewability": { + "config": "tv=vh2-121&d=1x1&s=3479483&st=0&vctx=4&ts=1575553896&vc=iab;vid_ccr=1&vjs=http%3A%2F%2Fcdn.adnxs.com%2Fv%2Fvideo%2F182%2Ftrk.js&cb=http%3A%2F%2Fsin3-ib.adnxs.com%2Fvevent%3Fan_audit%3D0%26referrer%3Dhttp%253A%252F%252Ftest.localhost%253A9999%252Ftest%252Fpages%252Foutstream.html%26e%3DwqT_3QK4CKA4BAAAAwDWAAUBCOiWpO8FENTtnJej9sqoBxiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIHSpwY47UhA7UhIAlDLgcAuWJzxW2AAaOWljwF4urgFgAEBigEDVVNEkgUG8FKYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzU1NTM4OTYpO3VmKCdyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFUenpuS1FqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSG5NQW5aODYzalA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TOEE4RDgumgKJASFXdzkxSDo5ASRuUEZiSUFRb0FEFVhYa1FEb0pVMGxPTXpvME9ETTBRUGtXU1ENTwxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8EllQUEuwgI4aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc2hvdy1vdXRzdHJlYW0tdmlkZW8tYWRzLmh0bWzYAgDgAq2YSOoCNA1DSHRlc3QubG9jYWxob3N0Ojk5OTkFFBgvcGFnZXMvFUkALgE_yIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzLwmj8F6YBACiBAsxMC43NS43NC42OagEmM8CsgQSCAQQBBiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ4MzTaBAIIAeAEAPAEy4HALogFAZgFAKAF_____wUDFAHABQDJBWl6FPA_0gUJCQkMeAAA2AUB4AUB8AXDlQv6BQQIABAAkAYBmAYAuAYAwQYJJTTwP8gGANAG9S_aBhYKEAkUGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA%26s%3D5adef946cd5f0d8db86d67860914e02ef6f91d6b&cet=0&cecb=&rdcb=http%3A%2F%2Fsin3-ib.adnxs.com%2Frd_log%3Fan_audit%3D0%26referrer%3Dhttp%253A%252F%252Ftest.localhost%253A9999%252Ftest%252Fpages%252Foutstream.html%26e%3DwqT_3QKMCaCMBAAAAwDWAAUBCOiWpO8FENTtnJej9sqoBxiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIHSpwY47UhA7UhIAlDLgcAuWJzxW2AAaOWljwF4urgFgAEBigEDVVNEkgUG8FKYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzU1NTM4OTYpO3VmKCdyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFUenpuS1FqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSG5NQW5aODYzalA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TOEE4RDgumgKJASFXdzkxSDo5ASRuUEZiSUFRb0FEFVhYa1FEb0pVMGxPTXpvME9ETTBRUGtXU1ENTwxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8EllQUEuwgI4aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc2hvdy1vdXRzdHJlYW0tdmlkZW8tYWRzLmh0bWzYAgDgAq2YSOoCNA1DSHRlc3QubG9jYWxob3N0Ojk5OTkFFBgvcGFnZXMvFUkALgE_aPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7gSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzDffwXpgEAKIECzEwLjc1Ljc0LjY5qASYzwKyBBIIBBAEGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDgzNNoEAggB4AQA8ATLgcAuiAUBmAUAoAX_____BQMUAcAFAMkFac4U8D_SBQkJCQx4AADYBQHgBQHwBcOVC_oFBAgAEACQBgGYBgC4BgDBBgklNPA_yAYA0Ab1L9oGFgoQCRQZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.%26s%3Df2a73057b50fb0c9e98a6093141472a4ed2e401e&bridge=1.11.0&rblog=auc=527250675737245396;bm=9325;sm=9325;cr=97517771;pl=13232385&vid_context=anoutstream;anbannerstream;anoverlayplayer" + }, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_off" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "content": "adnxs00:00:30.000" + } + } + } + ] + }, + { + "tag_id": 13232385, + "auction_id": "3449642271543746980", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Foutstream.html&e=wqT_3QKwCKAwBAAAAwDWAAUBCOiWpO8FEKTDpazn6-XvLxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMIHSpwY47UhA7UhIAFAAWJzxW2AAaOWljwF4AIABAYoBAJIBA1VTRJgBAaABAagBAbABALgBA8ABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3NTU1Mzg5NikFHTRyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFvendNV2dqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSHIwdDF2TTdMaVA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TPEE4RDgumgKJASFXdzkxSFE2OQEkblBGYklBUW9BRBVYWGtRRG9KVTBsT016bzBPRE0wUVBrV1NRDU8MUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBJZUFBLsICOGh0dHA6Ly9wcmViaWQub3JnL2Rldi1kb2NzL3Nob3ctb3V0c3RyZWFtLXZpZGVvLWFkcy5odG1s2AIA4AKtmEjqAjQNQ0h0ZXN0LmxvY2FsaG9zdDo5OTk5BRQYL3BhZ2VzLxVJAC4BP8iAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My8Jo_BemAQAogQLMTAuNzUuNzQuNjmoBJjPArIEEggEEAQYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0ODM02gQCCADgBADwBMuBwC6IBQGYBQCgBf____8FAxQBwAUAyQVpchTwP9IFCQkJDHgAANgFAeAFAfAFw5UL-gUECAAQAJAGAZgGALgGAMEGCSU08L_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=e43b45a2391036da6d93eda546d8808de0169bb1", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQloC-ldAAAAABGkYYl1XpffLxloC-ldAAAAACDLgcAuKAAw7Ug47UhA0-hISLuv1AFQgdKnBljDlQtiAi0taAFwAXgAgAECiAEEkAGABZgB4AOgAQCoAcuBwC6wAQE.&s=414834fdc6e268f284292aedf8b01ee525c3e999&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97517771, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 36, + "renderer_url": "http://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js", + "renderer_id": 2, + "renderer_config": "{\"skippable\":{\"videoThreshold\":null,\"skipLocation\":\"top-right\"}}", + "client_initiated_ad_counting": true, + "viewability": { + "config": "tv=vh2-121&d=1x1&s=3479483&st=0&vctx=4&ts=1575553896&vc=iab;vid_ccr=1&vjs=http%3A%2F%2Fcdn.adnxs.com%2Fv%2Fvideo%2F182%2Ftrk.js&cb=http%3A%2F%2Fsin3-ib.adnxs.com%2Fvevent%3Fan_audit%3D0%26referrer%3Dhttp%253A%252F%252Ftest.localhost%253A9999%252Ftest%252Fpages%252Foutstream.html%26e%3DwqT_3QK4CKA4BAAAAwDWAAUBCOiWpO8FEKTDpazn6-XvLxiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIHSpwY47UhA7UhIAlDLgcAuWJzxW2AAaOWljwF4urgFgAEBigEDVVNEkgUG8FKYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzU1NTM4OTYpO3VmKCdyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFvendNV2dqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSHIwdDF2TTdMaVA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TPEE4RDgumgKJASFXdzkxSFE2OQEkblBGYklBUW9BRBVYWGtRRG9KVTBsT016bzBPRE0wUVBrV1NRDU8MUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBJZUFBLsICOGh0dHA6Ly9wcmViaWQub3JnL2Rldi1kb2NzL3Nob3ctb3V0c3RyZWFtLXZpZGVvLWFkcy5odG1s2AIA4AKtmEjqAjQNQ0h0ZXN0LmxvY2FsaG9zdDo5OTk5BRQYL3BhZ2VzLxVJAC4BP8iAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My8Jo_BemAQAogQLMTAuNzUuNzQuNjmoBJjPArIEEggEEAQYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0ODM02gQCCAHgBADwBMuBwC6IBQGYBQCgBf____8FAxQBwAUAyQVpehTwP9IFCQkJDHgAANgFAeAFAfAFw5UL-gUECAAQAJAGAZgGALgGAMEGCSU08D_IBgDQBvUv2gYWChAJFBkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..%26s%3Dc2a8dac8959d9366981afc868ec5b54853090944&cet=0&cecb=&rdcb=http%3A%2F%2Fsin3-ib.adnxs.com%2Frd_log%3Fan_audit%3D0%26referrer%3Dhttp%253A%252F%252Ftest.localhost%253A9999%252Ftest%252Fpages%252Foutstream.html%26e%3DwqT_3QKMCaCMBAAAAwDWAAUBCOiWpO8FEKTDpazn6-XvLxiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIHSpwY47UhA7UhIAlDLgcAuWJzxW2AAaOWljwF4urgFgAEBigEDVVNEkgUG8FKYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzU1NTM4OTYpO3VmKCdyJywgOTc1MTc3NzEsIC4eAPCakgK1AiFvendNV2dqWS1Md0tFTXVCd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRZ2RLbkJsZ0FZSUlDYUFCd0FIZ0FnQUhBQVlnQkFKQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRSHIwdDF2TTdMaVA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BOWo0dkFxNkF3bFRTVTR6T2pRNE16VGdBX2tXaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhpSmFrRg0TPEE4RDgumgKJASFXdzkxSFE2OQEkblBGYklBUW9BRBVYWGtRRG9KVTBsT016bzBPRE0wUVBrV1NRDU8MUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBJZUFBLsICOGh0dHA6Ly9wcmViaWQub3JnL2Rldi1kb2NzL3Nob3ctb3V0c3RyZWFtLXZpZGVvLWFkcy5odG1s2AIA4AKtmEjqAjQNQ0h0ZXN0LmxvY2FsaG9zdDo5OTk5BRQYL3BhZ2VzLxVJAC4BP2jyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-4ElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92Mw338F6YBACiBAsxMC43NS43NC42OagEmM8CsgQSCAQQBBiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ4MzTaBAIIAeAEAPAEy4HALogFAZgFAKAF_____wUDFAHABQDJBWnOFPA_0gUJCQkMeAAA2AUB4AUB8AXDlQv6BQQIABAAkAYBmAYAuAYAwQYJJTTwP8gGANAG9S_aBhYKEAkUGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA%26s%3D4e9e218d8f075cb19c4a4e8da2a7e716fa15d3c5&bridge=1.11.0&rblog=auc=3449642271543746980;bm=9325;sm=9325;cr=97517771;pl=13232385&vid_context=anoutstream;anbannerstream;anoverlayplayer" + }, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_off" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "content": "adnxs00:00:30.000" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/index.js b/test/fake-server/fixtures/index.js new file mode 100644 index 00000000000..bd58bda5ad5 --- /dev/null +++ b/test/fake-server/fixtures/index.js @@ -0,0 +1,41 @@ +/* eslint-disable no-console */ + +const path = require('path'); +const fs = require('fs'); + +const REQ_RES_PAIRS = {}; + +/** + * @param {String} dirname - Path of the fixture directory + * @returns {object} reqResPair - An object containing 'request' - 'response' segregated by ad unit media type. + */ +function getReqResPairs (dirname) { + try { + const filenames = fs.readdirSync(dirname, { withFileTypes: true }); + filenames.forEach(filename => { + if (filename.isDirectory()) { + getReqResPairs(`${dirname}/${filename.name}`); + } else { + if (filename.name === 'request.json' || filename.name === 'response.json') { + const parentDir = path.basename(dirname); + if (!REQ_RES_PAIRS[parentDir]) { + REQ_RES_PAIRS[parentDir] = { + request: {}, + response: {} + } + } + if (filename.name === 'request.json') { + REQ_RES_PAIRS[parentDir]['request'] = JSON.parse(fs.readFileSync(`${dirname}/${filename.name}`, { encoding: 'utf-8' })); + } else { + REQ_RES_PAIRS[parentDir]['response'] = JSON.parse(fs.readFileSync(`${dirname}/${filename.name}`, { encoding: 'utf-8' })); + } + } + } + }); + return REQ_RES_PAIRS; + } catch (e) { + console.error(`Error:: ${e.message}`); + } +} + +module.exports = getReqResPairs; diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_1/description.md b/test/fake-server/fixtures/longform/longform_biddersettings_1/description.md new file mode 100644 index 00000000000..207e851af74 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_1/description.md @@ -0,0 +1,41 @@ +Test Page - 'integrationExamples/longform/basic_w_bidderSettings.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_bidderSettings.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + debug: true, + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_1/request.json b/test/fake-server/fixtures/longform/longform_biddersettings_1/request.json new file mode 100644 index 00000000000..aba76398093 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_1/request.json @@ -0,0 +1,387 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_1/response.json b/test/fake-server/fixtures/longform/longform_biddersettings_1/response.json new file mode 100644 index 00000000000..e3ea15d7c6e --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_1/response.json @@ -0,0 +1,114 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "2678252910506723691", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "3548675574061430850", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "8693167356543642173", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "7686428711280367086", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "3784359541475413084", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "7233136875958651734", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "159775901183771330", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "6558726890185052779", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "6624810255570939818", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "528384387675374412", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "2535665225687089273", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "2166694611986638079", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "9137369006412413609", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "3524702228053475248", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2d4806af582cf6", + "tag_id": 15394006, + "auction_id": "57990683038266307", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_2/description.md b/test/fake-server/fixtures/longform/longform_biddersettings_2/description.md new file mode 100644 index 00000000000..cafbb17f61b --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_2/description.md @@ -0,0 +1,28 @@ +Test Page - 'integrationExamples/longform/basic_w_bidderSettings.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_bidderSettings.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_2/request.json b/test/fake-server/fixtures/longform/longform_biddersettings_2/request.json new file mode 100644 index 00000000000..f2f20700ffe --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_2/request.json @@ -0,0 +1,137 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_biddersettings_2/response.json b/test/fake-server/fixtures/longform/longform_biddersettings_2/response.json new file mode 100644 index 00000000000..e2332806dbb --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_biddersettings_2/response.json @@ -0,0 +1,188 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "245a09bd675168", + "tag_id": 15394006, + "auction_id": "3810681093956255668", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QKVCKAVBAAAAwDWAAUBCKD4kfAFELT_vOy9yJDxNBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIUxEMWZkUWlua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOE13Q2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFZVS10N09mcU9BXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTS1BRG9SaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJaRWxxUVUJE0RBRHdQdy4umgKJASFLdy1SRkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV6UUtFWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9AUBZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagErLkEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTPaBAIIAOAEAPAE0uyfR4gFAZgFAKAF____________AcAFAMkFAGVbFPA_0gUJCQULfAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=66ba37441db5e28c87ee52e729333fd9324333f9", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQkgfAReAAAAABG0P4_dQ0LiNBkgfAReAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=6931bf3569012d0e1f02cb5a2e88dfcafe00dba9&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QLxCOhxBAAAAwDWAAUBCKD4kfAFELT_vOy9yJDxNBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4vLgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFMRDFmZFFpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjhNd0NrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWVUtdDdPZnFPQV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU0tQURvUmlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWkVscVFVCRNEQUR3UHcuLpoCiQEhS3ctUkZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVelFLRVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkMyHQDwlUFTVF9NT0RJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKy5BLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUz2gQCCAHgBADwBGGFIIgFAZgFAKAF_xEBFAHABQDJBWm2FPA_0gUJCQkMeAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=ea46ec90cf31744c7be2af5d5f239ab4eed29098" + } + } + } + ] + }, + { + "uuid": "245a09bd675168", + "tag_id": 15394006, + "auction_id": "7325897349627488405", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QKUCKAUBAAAAwDWAAUBCKD4kfAFEJXRloy0mrTVZRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIXJUeTNJd2lta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOE13Q2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFVSzAtQ2hwcWRrXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTS1BRG9SaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJaRWxxUVUJE0RBRHdQdy4umgKJASFBQTlLQlE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV6UUtFWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9AUBZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagErLkEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTPaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAGVbFPA_0gUJCQULeAAAANgFAeAFAfAF4Fj6BQQIABAAkAYBmAYAuAYAwQYBIDAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=271fd8a0ccdfc36e320f707164588ed1b33e9861", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQkgfAReAAAAABGVqIVB09CqZRkgfAReAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICLS1oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=115ac2b842cf3efeb5acaeda94ddf05632c345ca&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QLwCOhwBAAAAwDWAAUBCKD4kfAFEJXRloy0mrTVZRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4vLgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFyVHkzSXdpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjhNd0NrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVUswLUNocHFka18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU0tQURvUmlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWkVscVFVCRNEQUR3UHcuLpoCiQEhQUE5S0JRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVelFLRVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkMyHQDwlUFTVF9NT0RJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKy5BLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUz2gQCCAHgBADwBGGFIIgFAZgFAKAF_xEBFAHABQDJBWm2FPA_0gUJCQkMdAAA2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgkkKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=f73e060b15a6bbcca65f918a296f155b78c74eca" + } + } + } + ] + }, + { + "uuid": "245a09bd675168", + "tag_id": 15394006, + "auction_id": "968802322305726102", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QKVCKAVBAAAAwDWAAUBCKD4kfAFEJbt7LTEkvi4DRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTsBHTByJywgMTQ5NDE0MTg4Nh8A8P2SArkCIUtUejN5d2lHa184UEVLekNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOE13Q2tBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFTT3dTTWVaYnVJXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGMxTS1BRG9SaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJaRWxxUVUJE0RBRHdQdy4umgKJASF0ZzY4Nmc2PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOelV6UUtFWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9AUBZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagErLkEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTPaBAIIAOAEAPAErMKfR4gFAZgFAKAF____________AcAFAMkFAGVbFPA_0gUJCQULfAAAANgFAeAFAfAF8owB-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=e35825a106304da78477df1575f981395be21d5f", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQkgfAReAAAAABGWNptGlOBxDRkgfAReAAAAACCswp9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jyjAFiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAazCn0ewAQE.&s=677bedd5b2d21fdc3f940cbae279261c8f84c2e7&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149414188, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 32, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 29000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QLxCOhxBAAAAwDWAAUBCKD4kfAFEJbt7LTEkvi4DRiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQrMKfR1ic8VtgAGjNunV4vLgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTt1ZigncicsIDE0OTQxNDE4OCwgMTUZH_D9kgK5AiFLVHozeXdpR2tfOFBFS3pDbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjhNd0NrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBU093U01lWmJ1SV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjMU0tQURvUmlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWkVscVFVCRNEQUR3UHcuLpoCiQEhdGc2ODZnNj0BJG5QRmJJQVFvQUQVSFRxUURvSlUwbE9Nem8wTnpVelFLRVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkMyHQDwlUFTVF9NT0RJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKy5BLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUz2gQCCAHgBADwBGGFIIgFAZgFAKAF_xEBFAHABQDJBWm2FPA_0gUJCQkMeAAA2AUB4AUB8AXyjAH6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=0707b1385afa81517cd338f1516aeccc46fe33e1" + } + } + } + ] + }, + { + "uuid": "245a09bd675168", + "tag_id": 15394006, + "auction_id": "1273216786519070425", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "245a09bd675168", + "tag_id": 15394006, + "auction_id": "1769115862397582681", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QKUCKAUBAAAAwDWAAUBCKD4kfAFENn63YWPsMrGGBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIXp6djFzd2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOE13Q2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFZbW5MamdJaXVRXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTS1BRG9SaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJaRWxxUVUJE0RBRHdQdy4umgKJASFGdzkxRFE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV6UUtFWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9AUBZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagErLkEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTPaBAIIAOAEAPAExOefR4gFAZgFAKAF____________AcAFAMkFAGVbFPA_0gUJCQULeAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYBIDAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=fb3a15e7ff747fccd750671b763e312d97083c72", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQkgfAReAAAAABFZfbfwgCmNGBkgfAReAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICLS1oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=7f4b8dd7c7dd9faecebac2e9ec6d7ef8da08da16&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_bidderSettings.html&e=wqT_3QLwCOhwBAAAAwDWAAUBCKD4kfAFENn63YWPsMrGGBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4vLgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3MzUyMjI0KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiF6enYxc3dpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjhNd0NrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWW1uTGpnSWl1UV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU0tQURvUmlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWkVscVFVCRNEQUR3UHcuLpoCiQEhRnc5MURRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVelFLRVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJTaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2JpZGRlclNldHRpbmdzLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkMyHQDwsEFTVF9NT0RJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKy5BLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUz2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBWm2FPA_0gUJCQkMdAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgkkKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=3a27c12c33ebaaae43dbce1cafb0bae43b753fa0" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/description.md b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/description.md new file mode 100644 index 00000000000..45ae30a7a41 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/description.md @@ -0,0 +1,43 @@ +Test Page - 'integrationExamples/longform/basic_w_custom_adserver_translation.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_custom_adserver_translation.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: true + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + }, + brandCategoryTranslation: { + translationFile: 'custom_adserver_translation.json' + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/request.json b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/request.json new file mode 100644 index 00000000000..e7497ac78f3 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/request.json @@ -0,0 +1,402 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/response.json b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/response.json new file mode 100644 index 00000000000..b4d8483a539 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_1/response.json @@ -0,0 +1,294 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "7360998998672342781", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCN73l_AFEP39-97ssuGTZhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIVNqMmZTQWlua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaQmtTcHl1c2Q4XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFOZzhKRnc2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfC2Lmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAE0uyfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAZXZw2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYFIiwA8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=c92cbcde5c8bf8e053f86493dd4c4698da0392de", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQne-wVeAAAAABH9_t7LloUnZhne-wVeAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=8e35c1264cd1b4f1d89f929c3a4a334cf6a68eca&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-COh-BAAAAwDWAAUBCN73l_AFEP39-97ssuGTZhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV40rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFTajJmU0FpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnV1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWkJrU3B5dXNkOF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhTmc4SkZ3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBJLGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBNLsn0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=ca640dffaea7bfcf2b0f2e11d8877821189b74bb" + } + } + } + ] + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "1919339751435064934", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCN73l_AFEOasy7zbqrfRGhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIU1EMUZJQWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFRclZ0ZGpIUGVBXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASE1QTdmLVE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfC2Lmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAZXZw2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYFIiwA8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=c3130de64bc0b8df258e603dfb96f78550ab0c3c", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQne-wVeAAAAABFm1pK3Vd2iGhne-wVeAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=2c3cee10303d9b93531bed443c0781d905270598&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-COh-BAAAAwDWAAUBCN73l_AFEOasy7zbqrfRGhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV40rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFNRDFGSUFpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnV1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBUXJWdGRqSFBlQV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhNUE3Zi1RNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBJLGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBIvhn0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx4AADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=996a3937245f03e5eefb0cb69917d2d8d7f60424" + } + } + } + ] + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "3257875652791896280", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "5756905673624319729", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "4205438746002589111", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "204849530930208960", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "3482944224379652843", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "2123689132466331410", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "6150444453316813936", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "2810956382376737966", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "7164199537578897638", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKhCKAhBAAAAwDWAAUBCN73l_AFEObhocvZsJa2Yxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIXNENXVfQWlta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYSEZfdmZOei1NXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFDd19DQnc2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfC2Lmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAZXZs2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgUhLADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=2b9ed1e2e7f27fea52cbdc64cb700195bbd14d75", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQne-wVeAAAAABHmcGiZhVlsYxne-wVeAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICLS1oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=8ba7f141449cb45f8b6e12361a62d8d68aa9c812&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL9COh9BAAAAwDWAAUBCN73l_AFEObhocvZsJa2Yxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV40rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFzRDV1X0FpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnV1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWEhGX3ZmTnotTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhQ3dfQ0J3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBJLGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBK_ln0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx0AADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSQo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=527640949733fba32740156d743d421eb1fe2863" + } + } + } + ] + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "8404712946290777461", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCN73l_AFEPW6p5bQvOLRdBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIWp6MkdiZ2lta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaQ0RhTlBDYk9NXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0BBRHdQdy4umgKJASFOUS0yRjo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56TXpRSzRZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwZWVBQS7YAgDgAq2YSOoCYGh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19jdXN0b21fYWRzZXJ2ZXJfdHJhbnNsYQE18LYuaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qASSxgSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggA4AQA8ATf359HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABldnDYBQHgBQHwBay8FPoFBAgAEACQBgGYBgC4BgDBBgUiLADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=ed84428f432d6e743bcad6f7862aed957bece82b", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQne-wVeAAAAABF13ckC5YmjdBne-wVeAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=7024b063fcacac27e184ed097ad5878c4dd4dc1d&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-COh-BAAAAwDWAAUBCN73l_AFEPW6p5bQvOLRdBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV40rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiFqejJHYmdpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnV1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWkNEYU5QQ2JPTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNAQUR3UHcuLpoCiQEhTlEtMkY6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNXwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7wn0lGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAeAEAPAE39-fR4gFAZgFAKAF______8BBRQBwAUAyQVpwxTwP9IFCQkJDHgAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGCSUo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=aefe9625d8e866e048a156abdf26d7c626e6a398" + } + } + } + ] + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "4063389973481762703", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCN73l_AFEI_fjorv9IOyOBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUwNDYyKTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIV96eHRIQWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFSVExWM2x4c2VJXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFEZy1VQ1E2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfC2Lmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAExd2fR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAZXZw2AUB4AUB8AXC8hf6BQQIABAAkAYBmAYAuAYAwQYFIiwA8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=2fb33b5204f9b75c58d89487725a9d55139f9ff4", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQne-wVeAAAAABGPr0Pxpg9kOBne-wVeAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=f9ec8d0b81c1cf4eefc58a7990f4a0a78440725f&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-CKB-BAAAAwDWAAUBCN73l_AFEI_fjorv9IOyOBiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXjSuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc0NTA0NjIpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIV96eHRIQWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCdXVZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFSVExWM2x4c2VJXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFEZy1VQ1E2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOek16UUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNXwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7wn0lGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEksYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAeAEAPAExd2fR4gFAZgFAKAF______8BBRQBwAUAyQVpwxTwP9IFCQkJDHgAANgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGCSUo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=6b79542e3cee0319d8cb83d1daf127c3aeea9b28" + } + } + } + ] + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "5097385192927446024", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "201bba5bb8827", + "tag_id": 15394006, + "auction_id": "2612757136292876686", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/description.md b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/description.md new file mode 100644 index 00000000000..45ae30a7a41 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/description.md @@ -0,0 +1,43 @@ +Test Page - 'integrationExamples/longform/basic_w_custom_adserver_translation.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_custom_adserver_translation.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: true + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + }, + brandCategoryTranslation: { + translationFile: 'custom_adserver_translation.json' + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/request.json b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/request.json new file mode 100644 index 00000000000..f4cea46918f --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/request.json @@ -0,0 +1,142 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/response.json b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/response.json new file mode 100644 index 00000000000..6a81de25ebe --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_custom_adserver_translation_2/response.json @@ -0,0 +1,188 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "285a2f41615348", + "tag_id": 15394006, + "auction_id": "2837696487158070058", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCNSDmPAFEKr2uMu5veGwJxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIV9EemhKUWlta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCN3VZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFTbnRDdFVIdU9BXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TmVBRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmOGtxUVUJE0RBRHdQdy4umgKJASFOdzh1Rnc2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek0xUUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfDtLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEq8YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzXaBAIIAOAEAPAE39-fR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBay8FPoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPC_0Ab1L9oGFgoQAAAAAAU3DQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=3414eb9e83df14945d2dbfb00e17fb3f2bad2e33", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnUAQZeAAAAABEqO26Z64VhJxnUAQZeAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=e5a720a9884e1df845be9c33658ab69f4c56981e&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-COh-BAAAAwDWAAUBCNSDmPAFEKr2uMu5veGwJxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiFfRHpoSlFpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjd1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBU250Q3RVSHVPQV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek5lQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjhrcVFVCRNEQUR3UHcuLpoCiQEhTnc4dUZ3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNMVFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKvGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM12gQCCAHgBADwBN_fn0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx4AADYBQHgBQHwBay8FPoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=99418325b8f5ec79e22c1a9aedd73f03de616c2d" + } + } + } + ] + }, + { + "uuid": "285a2f41615348", + "tag_id": 15394006, + "auction_id": "8688113570839045503", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKhCKAhBAAAAwDWAAUBCNSDmPAFEP_K8rCtqJjJeBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIUN6d3Rud2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCN3VZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFWUzRZeVVvR09JXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TmVBRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmOGtxUVUJE0RBRHdQdy4umgKJASFKQTlsRUE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek0xUUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfDXLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEq8YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzXaBAIIAOAEAPAExOefR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBZk9-gUECAAQAJAGAZgGALgGAMEGBSEsAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=2e7c9d18300402e2e183667711728f7743b70a2b", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQnUAQZeAAAAABF_pRzWQmGSeBnUAQZeAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICLS1oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=febf12010c66ac7247f571f03c33175ca9036b32&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL9COh9BAAAAwDWAAUBCNSDmPAFEP_K8rCtqJjJeBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFDend0bndpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjd1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVlM0WXlVb0dPSV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek5lQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjhrcVFVCRNEQUR3UHcuLpoCiQEhSkE5bEVBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNMVFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKvGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM12gQCCAHgBADwBMTnn0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx0AADYBQHgBQHwBZk9-gUECAAQAJAGAZgGALgGAMEGCSQo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=92aa9e9c89384c435ab9c7fa62b963d8fc087ef7" + } + } + } + ] + }, + { + "uuid": "285a2f41615348", + "tag_id": 15394006, + "auction_id": "4162295099171231907", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKhCKAhBAAAAwDWAAUBCNSDmPAFEKOxzaPwqtzhORiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIWREMGtXZ2lta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCN3VZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhSFRjUzNjWS1VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TmVBRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmOGtxUVUJE0RBRHdQdy4umgKJASFEUTg2Q0E2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek0xUUs0WVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8GVlQUEu2AIA4AKtmEjqAmBodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfY3VzdG9tX2Fkc2VydmVyX3RyYW5zbGEBNfDXLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagEq8YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzXaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGBSEsAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=95047e919846faea401c778106fb33dae0c95b02", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQnUAQZeAAAAABGjWHMEV3HDORnUAQZeAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICLS1oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=50350aadc603f4bb6c59888515d60e9182da0eb8&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL9COh9BAAAAwDWAAUBCNSDmPAFEKOxzaPwqtzhORiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFkRDBrV2dpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjd1WUNrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYUhUY1MzY1ktVV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek5lQURyaGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjhrcVFVCRNEQUR3UHcuLpoCiQEhRFE4NkNBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNMVFLNFlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBlZUFBLtgCAOACrZhI6gJgaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X2N1c3RvbV9hZHNlcnZlcl90cmFuc2xhATV8Lmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChYyFgAgTEVBRl9OQU1FAR0IHgoaNh0ACEFTVAE-8J9JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQLMTAuNzUuNzQuNjmoBKvGBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM12gQCCAHgBADwBK_ln0eIBQGYBQCgBf______AQUUAcAFAMkFacMU8D_SBQkJCQx0AADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSQo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=82c42e6aa09e7c842254552ae524791fa3693bbb" + } + } + } + ] + }, + { + "uuid": "285a2f41615348", + "tag_id": 15394006, + "auction_id": "1076114531988487576", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QKiCKAiBAAAAwDWAAUBCNSDmPAFEJj7vIbyjsj3Dhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NDUxOTg4KTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIVRqMWVUZ2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCN3VZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFZOUNHX2M3MHRvXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TmVBRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmOGtxUVUJE0BBRHdQdy4umgKJASFFQThNQzo9ASRuUEZiSUFRb0FEFUhUa1FEb0pVMGxPTXpvME56TTFRSzRZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwZWVBQS7YAgDgAq2YSOoCYGh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19jdXN0b21fYWRzZXJ2ZXJfdHJhbnNsYQE18O0uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qASrxgSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggA4AQA8ATF3Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAAAABTcNAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=c49afba7ca4b5193f7da37b17e1fbfbee2328f61", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "http://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnUAQZeAAAAABGYPc8gdyDvDhnUAQZeAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAi0taAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=47618eb9096567900e84fd1c6aff09d753b2fe91&event_type=1", + "usersync_url": "http%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "http://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_custom_adserver_translation.html&e=wqT_3QL-CKB-BAAAAwDWAAUBCNSDmPAFEJj7vIbyjsj3Dhiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXjWuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc0NTE5ODgpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIVRqMWVUZ2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCN3VZQ2tBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFZOUNHX2M3MHRvXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TmVBRHJoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmOGtxUVUJE0BBRHdQdy4umgKJASFFQThNQzo9ASRuUEZiSUFRb0FEFUhUa1FEb0pVMGxPTXpvME56TTFRSzRZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwZWVBQS7YAgDgAq2YSOoCYGh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19jdXN0b21fYWRzZXJ2ZXJfdHJhbnNsYQE1fC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvCfSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qASrxgSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggB4AQA8ATF3Z9HiAUBmAUAoAX______wEFFAHABQDJBWnDFPA_0gUJCQkMeAAA2AUB4AUB8AXC8hf6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=72d1ec3db5baaa29c1b0e5f07c012db606675fe5" + } + } + } + ] + }, + { + "uuid": "285a2f41615348", + "tag_id": 15394006, + "auction_id": "7495588537924508785", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_1/description.md b/test/fake-server/fixtures/longform/longform_priceGran_1/description.md new file mode 100644 index 00000000000..8bc4d242f46 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_1/description.md @@ -0,0 +1,62 @@ +Test Page - 'integrationExamples/longform/basic_w_priceGran.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_priceGran.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +const customConfigObject = { + 'buckets': [{ + 'precision': 2, // default is 2 if omitted - means 2.1234 rounded to 2 decimal places = 2.12 + 'min': 0, + 'max': 5, + 'increment': 0.01 // from $0 to $5, 1-cent increments + }, + { + 'precision': 2, + 'min': 5, + 'max': 8, + 'increment': 0.05 // from $5 to $8, round down to the previous 5-cent increment + }, + { + 'precision': 2, + 'min': 8, + 'max': 40, + 'increment': 0.5 // from $8 to $40, round down to the previous 50-cent increment + }] +}; + +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + }, + priceGranularity: customConfigObject +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_1/request.json b/test/fake-server/fixtures/longform/longform_priceGran_1/request.json new file mode 100644 index 00000000000..aba76398093 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_1/request.json @@ -0,0 +1,387 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_1/response.json b/test/fake-server/fixtures/longform/longform_priceGran_1/response.json new file mode 100644 index 00000000000..4665aa4ef9c --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_1/response.json @@ -0,0 +1,366 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "1249897353793397796", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEKTIuZTW4KGsERiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCITFqdjBlZ2lta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFXU1JOVU1OTk9jXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFTUTgtR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAE39-fR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkdADYBQHgBQHwBay8FPoFBAgAEACQBgGYBgC4BgDBBgkkKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=e9887c670ae9fcb7eb2a0253037c64c3587f4bcb", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnKwgleAAAAABEkZI5iBYdYERnJwgleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=68a5c49da3a6ecf3dfc0835cb3da72b3b2c7b080&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEKTIuZTW4KGsERiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiExanYwZWdpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBV1NSTlVNTk5PY18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhU1E4LUd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMeAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=9514ae5f8aae1ee9dddd24dce3e812ae76e0e783" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "4278372095219023172", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEMT65MOLmPWvOxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIUxEeUhqUWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaQWJScDluWS1FXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASEtQTVuX2c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkdADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgkkKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=987d4bb0c7611d41b5974ec412469da2241084cd", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnKwgleAAAAABFEPXm4wNRfOxnJwgleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=75aaa9ec84807690ceff60e39fbba6625240f9f3&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEMT65MOLmPWvOxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFMRHlIalFpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWkFiUnA5blktRV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhLUE1bl9nNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMeAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=9872a378866ce61fc366ca8c34bdd9302fa41a9b" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "8860024420878272196", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKRCKARBAAAAwDWAAUBCMmFp_AFEMSN8Z3LqMj6ehiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIU9EMjhLZ2lta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFkZExBS3hfN09nXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFIdzlLREE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkcADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSMo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=1289862cbe265fd9af13d2aab9635e3232421ec1", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQnKwgleAAAAABHERryzRCH1ehnJwgleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=0b094204d5c18803149e081bd2bc0077d25ebb14&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLtCOhtBAAAAwDWAAUBCMmFp_AFEMSN8Z3LqMj6ehiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFPRDI4S2dpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZGRMQUt4XzdPZ18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhSHc5S0RBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMdAAA2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgkkKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=f35771975371bb250fd6701914534b4f595fcf68" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "5236733650551797458", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKRCKARBAAAAwDWAAUBCMmFp_AFENLt5YOosKfWSBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIThUMjJsZ2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFkczByb2Ytbk9VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFOZzkxRkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAExOefR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkcADYBQHgBQHwBZk9-gUECAAQAJAGAZgGALgGAMEGCSMo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=e997907677e4e2f9b641d51b522a901b85944899", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQnKwgleAAAAABHSdnmAgp2sSBnJwgleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=d70eef0df40cece50465a13d05a2dc11b65eadeb&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLtCOhtBAAAAwDWAAUBCMmFp_AFENLt5YOosKfWSBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiE4VDIybGdpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZHMwcm9mLW5PVV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhTmc5MUZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_DtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAGn1FQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=e8b6716ad3d2fcbdb79976f72d60f8e90ce8f5a6" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "4987762881548953446", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "201567478388503336", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEKjm-NzbkYfmAhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIXV6NlFDd2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFkejE5MUdLNk8wXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0BBRHdQdy4umgKJASFTZy1SRzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56TXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0DgFlQUEu2AIA4AKtmEjqAk5odHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcHJpY2VHcmFuLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qASv5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggA4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAaWR0ANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=4a887316a3197dfae07c1443a4debc62a2f17fef", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnKwgleAAAAABEoM567jRzMAhnJwgleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=eef6278d136f8df4879846840f97933e9d67388a&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEKjm-NzbkYfmAhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiF1ejZRQ3dpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZHoxOTFHSzZPMF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNAQUR3UHcuLpoCiQEhU2ctUkc6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8JplQUEu2AIA4AKtmEjqAk5odHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcHJpY2VHcmFuLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkNVU1RPTREdCEFTVAEL8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAeAEAPAEYYIgiAUBmAUAoAX_EQEUAcAFAMkFabMU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=e68b089e4fc94aa7566784ccbff299e50c8bc090" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "3876520534914199302", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "4833995299234629234", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "8352235304492782614", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEJaok6aeuMb0cxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE0MTg4Nh8A8P2SArkCIUpUMS1FZ2lHa184UEVLekNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFmQ1lIN1I1bmVzXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASExUTY4OFE2PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAErMKfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkdADYBQHgBQHwBfKMAfoFBAgAEACQBgGYBgC4BgDBBgkkKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=7081f4ad4ae9837aaff4b4f59abc4ce7f8b02cb6", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnKwgleAAAAABEW1MTkwRnpcxnJwgleAAAAACCswp9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jyjAFiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAazCn0ewAQE.&s=71f281c81d1ae269bde275b84aa955c833ab1dea&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149414188, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 32, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 29000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEJaok6aeuMb0cxiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQrMKfR1ic8VtgAGjNunV4w7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxNDE4OCwgMTUZH_D9kgK5AiFKVDEtRWdpR2tfOFBFS3pDbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBZkNZSDdSNW5lc18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhMVE2ODhRNj0BJG5QRmJJQVFvQUQVSFRxUURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMeAAA2AUB4AUB8AXyjAH6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=05fc37623521011853ff69d194aa6d692b6c0504" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "2318891724556922037", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "5654583906891472332", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEMy7oJeqw8e8Thiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIXZ6Ml9mZ2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFhYzY5MFRlZi1rXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0BBRHdQdy4umgKJASFJZzhjRDo9ASRuUEZiSUFRb0FEFUhUa1FEb0pVMGxPTXpvME56TXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0DgFlQUEu2AIA4AKtmEjqAk5odHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcHJpY2VHcmFuLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qASv5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggA4AQA8ATF3Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAaWR0ANgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=f929565158c7caa5b85e88fa456cdd04d0e4b6d8", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnKwgleAAAAABHMHeiiGh55ThnJwgleAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=a93773067b8588465b9c007e19970bd9e08c1b6c&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCKBuBAAAAwDWAAUBCMmFp_AFEMy7oJeqw8e8Thiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXjDuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc2OTc5OTMpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIXZ6Ml9mZ2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFhYzY5MFRlZi1rXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0BBRHdQdy4umgKJASFJZzhjRDo9ASRuUEZiSUFRb0FEFUhUa1FEb0pVMGxPTXpvME56TXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwmmVBQS7YAgDgAq2YSOoCTmh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19wcmljZUdyYW4uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTV9NT0RFTF9MRUFGX05BTUUSAPICHgoaQ1VTVE9NER0IQVNUAQvwkElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qASv5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggB4AQA8ARhgiCIBQGYBQCgBf8RARQBwAUAyQVpsxTwP9IFCQkJDHgAANgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGCSUo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=a3a24cbf148bb959f539e883af3d118f64e81bc9" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "2268711976967571175", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "8379392370800588084", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "6225030428438795793", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "1592368529919250324", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_2/description.md b/test/fake-server/fixtures/longform/longform_priceGran_2/description.md new file mode 100644 index 00000000000..8bc4d242f46 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_2/description.md @@ -0,0 +1,62 @@ +Test Page - 'integrationExamples/longform/basic_w_priceGran.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_priceGran.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +const customConfigObject = { + 'buckets': [{ + 'precision': 2, // default is 2 if omitted - means 2.1234 rounded to 2 decimal places = 2.12 + 'min': 0, + 'max': 5, + 'increment': 0.01 // from $0 to $5, 1-cent increments + }, + { + 'precision': 2, + 'min': 5, + 'max': 8, + 'increment': 0.05 // from $5 to $8, round down to the previous 5-cent increment + }, + { + 'precision': 2, + 'min': 8, + 'max': 40, + 'increment': 0.5 // from $8 to $40, round down to the previous 50-cent increment + }] +}; + +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + }, + priceGranularity: customConfigObject +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_2/request.json b/test/fake-server/fixtures/longform/longform_priceGran_2/request.json new file mode 100644 index 00000000000..f2f20700ffe --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_2/request.json @@ -0,0 +1,137 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_priceGran_2/response.json b/test/fake-server/fixtures/longform/longform_priceGran_2/response.json new file mode 100644 index 00000000000..ee7494ea665 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_priceGran_2/response.json @@ -0,0 +1,188 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "6123799897847039642", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKRCKARBAAAAwDWAAUBCMmFp_AFEJqN_JX98Yb-VBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIUN6dzV3Z2lta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYQm5aNWdRbi1NXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASFJQS1IREE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkcADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSMo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=a7e4ff14c60153db90971365f90e514f45875324", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQnJwgleAAAAABGaBr_Sjxv8VBnJwgleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=842283d9de78fba7e92fac09f95bb63902a0b54a&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLtCOhtBAAAAwDWAAUBCMmFp_AFEJqN_JX98Yb-VBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4zrgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFDenc1d2dpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWEJuWjVnUW4tTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhSUEtSERBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMdAAA2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgkkKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=0fb74d544be103e1440c3ee8f7abc14d2c322d15" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "889501690217653627", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEPvKoYSxoomsDBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIWt6eTlHUWlua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFRSzgzNzR1VnVVXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASFTd19PR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAOAEAPAE0uyfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkdADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgkkKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=78ac70aeeae1da43c90efd248fb30a4ee630ffd5", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnJwgleAAAAABF7ZYgQEyVYDBnJwgleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=f21e2a522ddcaf0a67bc7d52f70288fdf7e6f3dd&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEPvKoYSxoomsDBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4zrgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFrenk5R1FpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBUUs4Mzc0dVZ1VV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhU3dfT0d3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMeAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=69611db1024ddb77e0754087ddbeae68a00633a1" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "2793012314322059080", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFEMj-1IPuvLHhJhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE0MTg4Nh8A8P2SArkCIXhqb2ZBZ2lHa184UEVLekNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFRQWhlSGt0VHVRXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASExZzc1OFE2PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAOAEAPAErMKfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAGlkdADYBQHgBQHwBfKMAfoFBAgAEACQBgGYBgC4BgDBBgkkKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=243f58d85b09468de2fe485662c950a86b5d90fb", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnJwgleAAAAABFIP3Xg5sXCJhnJwgleAAAAACCswp9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jyjAFiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAazCn0ewAQE.&s=99dd40ab6ae736c6aa7c96b5319e1723ea581e0d&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149414188, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 32, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 29000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFEMj-1IPuvLHhJhiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQrMKfR1ic8VtgAGjNunV4zrgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxNDE4OCwgMTUZH_D9kgK5AiF4am9mQWdpR2tfOFBFS3pDbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBUUFoZUhrdFR1UV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhMWc3NThRNj0BJG5QRmJJQVFvQUQVSFRxUURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCaZUFBLtgCAOACrZhI6gJOaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3ByaWNlR3Jhbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX01PREVMX0xFQUZfTkFNRRIA8gIeChpDVVNUT00RHQhBU1QBC_CQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBK_mBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBGGCIIgFAZgFAKAF_xEBFAHABQDJBWmzFPA_0gUJCQkMeAAA2AUB4AUB8AXyjAH6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=d9a3c817696f263b6e6d81f7251827fa54a47c37" + } + } + } + ] + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "45194178065897765", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2def02900a6cda", + "tag_id": 15394006, + "auction_id": "3805126675549039795", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QKSCKASBAAAAwDWAAUBCMmFp_AFELPZ2uvQ0aHnNBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIWNUM1hkZ2lua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCOXFZRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFjbUQzMExTME9VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0BBRHdQdy4umgKJASEtUTZrXzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56UXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0DgFlQUEu2AIA4AKtmEjqAk5odHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcHJpY2VHcmFuLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qASv5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0M9oEAggA4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAaWR0ANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=bbeaa584bea9afedf6dcab51b1616988441dfa22", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQnJwgleAAAAABGzrHYNjYbONBnJwgleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=b7e937b5acc3d8b910f6b08c3a40e04aa10818cd&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_priceGran.html&e=wqT_3QLuCOhuBAAAAwDWAAUBCMmFp_AFELPZ2uvQ0aHnNBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4zrgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk3OTkzKTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFjVDNYZGdpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQjlxWURrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBY21EMzBMUzBPVV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNAQUR3UHcuLpoCiQEhLVE2a186PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8JplQUEu2AIA4AKtmEjqAk5odHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcHJpY2VHcmFuLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTU9ERUxfTEVBRl9OQU1FEgDyAh4KGkNVU1RPTREdCEFTVAEL8N5JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEr-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAeAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgAAYeYo8D_QBvUv2gYWChABDy4BAFAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=279827127eba3204bc3a152b8abaf701260eb494" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_1/description.md b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/description.md new file mode 100644 index 00000000000..8fe815912e8 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_w_requireExactDuration.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_requireExactDuration.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: true + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_1/request.json b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/request.json new file mode 100644 index 00000000000..1e036c367c6 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/request.json @@ -0,0 +1,401 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 15, + "maxduration": 15 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_1/response.json b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/response.json new file mode 100644 index 00000000000..b91a5a3d523 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_1/response.json @@ -0,0 +1,330 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "4424969993715088689", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFELH6mcm82Km0PRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIWhUNEwzZ2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFjek5XT196NC1VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFTZy1SR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCADgBADwBNLsn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=3d8c006f4f85ecffd49c500554c3852b9079ff2b", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABExfSbJw6ZoPRlNxwleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=e2c6cedf67a96613ea8851673ebcfdd25a19435c&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCM2Op_AFELH6mcm82Km0PRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4lbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFoVDRMM2dpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBY3pOV09fejQtVV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhU2ctUkd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBeZUFBLtgCAOACrZhI6gJZaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3JlcXVpcmVFeGFjdER1cmEBLnwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7wkElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATC5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggB4AQA8ARhjSCIBQGYBQCgBf8RARQBwAUAyQVpvhTwP9IFCQkJDHgAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGCSUo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=de23f822f483b6e85615d4297d872262310c240d" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "2013100091803497646", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "2659371493620557151", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFEN_KtpiJif_zJBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIWR6eUJxQWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFWSHZpWGF0Q09zXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASEtQTVuX2c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCADgBADwBIvhn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx4AADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgklKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=eafba287adec58427d1679f43a84ebb19223c4e7", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABFfpQ2TSPznJBlNxwleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=b335b2c79378c1699d54cf9ffe097958bd989a0b&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCM2Op_AFEN_KtpiJif_zJBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4lbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFkenlCcUFpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVkh2aVhhdENPc18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhLUE1bl9nNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBeZUFBLtgCAOACrZhI6gJZaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3JlcXVpcmVFeGFjdER1cmEBLnwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7wkElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATC5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggB4AQA8ARhjSCIBQGYBQCgBf8RARQBwAUAyQVpvhTwP9IFCQkJDHgAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGCSUo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=66b9e769da1e1d68b202605fc178fc172046e9c5" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "5424637592449788792", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "3470330348822422583", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "4415549097692431196", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "1628359298176905427", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "1949183409076770477", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "4707958683377993236", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "2499032734231846767", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "1295788165766409083", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKcCKAcBAAAAwDWAAUBCM2Op_AFEPvWpeWKj-T9ERiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCITR6eVM5d2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFlS0tONGIwQS00XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFOZzkxRkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCADgBADwBMTnn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx0AADYBQHgBQHwBZk9-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=3cb170cdf53cd6a6bfec0676659daeb6170895e3", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQlNxwleAAAAABF7a6mseJD7ERlNxwleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=45f5cce314725120ec769afaacbb7aa92d32e674&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL4COh4BAAAAwDWAAUBCM2Op_AFEPvWpeWKj-T9ERiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4lbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiE0enlTOXdpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZUtLTjRiMEEtNF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhTmc5MUZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBeZUFBLtgCAOACrZhI6gJZaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3JlcXVpcmVFeGFjdER1cmEBLnwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7w7UlGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATC5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggB4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwP9AG9S_aBhYKEACJABUBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=5c9f03b9c5c6cc2bf070d8cdc6c9af4b06595879" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "702761892273189154", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKcCKAcBAAAAwDWAAUBCM2Op_AFEKLi_7T7xq3gCRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE4NDg2Nh8A8P2SArkCITdUeVNDd2lva184UEVQYmpuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFHSTh5N21BQUFzUU1FQmlQTXU1Z0FBTEVESkFYQTM4QzJIcnVFXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHFKUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFaQThESlE2PQEkblBGYklBUW9BRBVIVHNRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCADgBADwBPbjn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx0AADYBQHgBQHwBf0F-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=f459a78a1b20c9643b90d7491f22593d79cff253", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQlNxwleAAAAABEi8Z-2N7bACRlNxwleAAAAACD2459HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1j9BWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgB9uOfR7ABAQ..&s=83289d261bced5258930a1ce2464260a96565241&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418486, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 14.00001, + "cpm_publisher_currency": 14.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL4COh4BAAAAwDWAAUBCM2Op_AFEKLi_7T7xq3gCRiq5MnUovf28WEqNgmOWItPAQAsQBGOWItPAQAsQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ9uOfR1ic8VtgAGjNunV4lbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxODQ4NiwgMTUZH_D9kgK5AiE3VHlTQ3dpb2tfOFBFUGJqbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRR0k4eTdtQUFBc1FNRUJpUE11NWdBQUxFREpBWEEzOEMySHJ1RV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RxSlBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNEQUR3UHcuLpoCiQEhWkE4REpRNj0BJG5QRmJJQVFvQUQVSFRzUURvSlUwbE9Nem8wTnpNelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBeZUFBLtgCAOACrZhI6gJZaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3JlcXVpcmVFeGFjdER1cmEBLnwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7w7UlGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATC5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDczM9oEAggB4AQA8AT2459HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF_QX6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwP9AG9S_aBhYKEACJABUBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=16a432c0a05db78fa40fefc7967796ff2a2e8444" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "8192047453391406704", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFEPCMp9SW-P_XcRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIXhUdGdYZ2lHa184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFSR0FWSjZORXVNXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0BBRHdQdy4umgKJASFKUThlRDo9ASRuUEZiSUFRb0FEFUhUcVFEb0pVMGxPTXpvME56TXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwXmVBQS7YAgDgAq2YSOoCWWh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19yZXF1aXJlRXhhY3REdXJhAS7wny5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEwuYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MzPaBAIIAOAEAPAE39-fR4gFAZgFAKAF______8BBRQBwAUAyQVpYhTwP9IFCQkJDHgAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGCSUo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=8bf90e0756a9265ab6ac029e883e14803447a7fb", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABFwxolqwf-vcRlNxwleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=cf9ea0df7655a5c6150a527399cb2852c61ec14a&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCM2Op_AFEPCMp9SW-P_XcRiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4lbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiF4VHRnWGdpR2tfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBUkdBVko2TkV1TV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjek0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCZjBrcVFVCRNAQUR3UHcuLpoCiQEhSlE4ZUQ6PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEufC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBGGNIIgFAZgFAKAF_xEBFAHABQDJBWm-FPA_0gUJCQkMeAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=cefb5f476892ed335cd8b0fc20fabf7650b1d2e3" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "9041697983972949142", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFEJb5yqiVjaS9fRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIURUMkpEd2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFYeHdUOEhkUmVzXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFJZzhjRGc2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCADgBADwBMXdn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx4AADYBQHgBQHwBcLyF_oFBAgAEACQBgGYBgC4BgDBBgklKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=308ea3c3363b379ef62dbb6c7a91d1d91d9ee47a", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABGWvBJVaZB6fRlNxwleAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=70a33aa1a57d812d9da5c321e898197836ed16f8&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5CKB5BAAAAwDWAAUBCM2Op_AFEJb5yqiVjaS9fRiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXiVuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc2OTkxNDkpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIURUMkpEd2lsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFYeHdUOEhkUmVzXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGN6TS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJmMGtxUVUJE0RBRHdQdy4umgKJASFJZzhjRGc2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOek16UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEufC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvDeSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzMz2gQCCAHgBADwBMXdn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXC8hf6BQQIABAAkAYBmAYAuAYAwQYAAGHxKPA_0Ab1L9oGFgoQAQ8uAQBQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=ee15793b41a9d22ffad9bd46878a47821d6044fa" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "356000177781223639", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_2/description.md b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/description.md new file mode 100644 index 00000000000..8fe815912e8 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_w_requireExactDuration.html' +Test Spec File - 'test/spec/e2e/longform/basic_w_requireExactDuration.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: true + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_2/request.json b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/request.json new file mode 100644 index 00000000000..83877ff9ac0 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/request.json @@ -0,0 +1,141 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "minduration": 30, + "maxduration": 30 + } + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_requireExactDuration_2/response.json b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/response.json new file mode 100644 index 00000000000..e776170328e --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_requireExactDuration_2/response.json @@ -0,0 +1,188 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "198494455120718841", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKcCKAcBAAAAwDWAAUBCM2Op_AFEPnX6_r7tMzgAhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIXpUMDRwQWlta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhejg2NVNoMGVJXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZc2xxUVUJE0RBRHdQdy4umgKJASFKQTkzRFE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelEzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ32gQCCADgBADwBK_ln0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx0AADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=645b6e0a37eb3a315bc3208365bd4fc03e1ecd18", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQlNxwleAAAAABH561q_pzHBAhlNxwleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=35a21bf0bef1ca2c138e37a2e025ad523b5a1db2&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL4COh4BAAAAwDWAAUBCM2Op_AFEPnX6_r7tMzgAhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4xbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiF6VDA0cEFpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYXo4NjVTaDBlSV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME4tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWXNscVFVCRNEQUR3UHcuLpoCiQEhSkE5M0RRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRM1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBeZUFBLtgCAOACrZhI6gJZaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193X3JlcXVpcmVFeGFjdER1cmEBLnwuaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFjIWACBMRUFGX05BTUUBHQgeCho2HQAIQVNUAT7wkElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATC5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0N9oEAggB4AQA8ARhjSCIBQGYBQCgBf8RARQBwAUAyQVpvhTwP9IFCQkJDHQAANgFAeAFAfAF4Fj6BQQIABAAkAYBmAYAuAYAwQYJJCjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=cf3130989b2b4fe5271240d65055b85d1192b78a" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "998265386177420565", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFEJW6sbXGoqPtDRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIVdqM1Jid2lHa184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFmcXpCNjduMU9rXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGMwTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZc2xxUVUJE0BBRHdQdy4umgKJASFLZzlMRDo9ASRuUEZiSUFRb0FEFUhUcVFEb0pVMGxPTXpvME56UTNRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwXmVBQS7YAgDgAq2YSOoCWWh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19yZXF1aXJlRXhhY3REdXJhAS7wny5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEwuYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDfaBAIIAOAEAPAE39-fR4gFAZgFAKAF______8BBRQBwAUAyQVpYhTwP9IFCQkJDHgAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGCSUo8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=33f01ddfb15bc84d7bf134a168aeb9d9de76fa57", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABEVXaxmFI3aDRlNxwleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=023640de7c18a0d0e80b2456144b89a351455cda&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCM2Op_AFEJW6sbXGoqPtDRiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4xbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiFXajNSYndpR2tfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBZnF6QjY3bjFPa18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjME4tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWXNscVFVCRNAQUR3UHcuLpoCiQEhS2c5TEQ6PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOelEzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEufC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ32gQCCAHgBADwBGGNIIgFAZgFAKAF_xEBFAHABQDJBWm-FPA_0gUJCQkMeAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=515ab42a7fdcad8fcf34e4fb98b1e076a75006a9" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "8884527464400177295", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKcCKAcBAAAAwDWAAUBCM2Op_AFEI-RmcaB1Yumexiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCITVqcmtHUWlta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYb0paejlaR09NXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZc2xxUVUJE0BBRHdQdy4umgKJASFPdy1pRjo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56UTNRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQzwXmVBQS7YAgDgAq2YSOoCWWh0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5L2ludGVncmF0aW9uRXhhbXBsZXMvbG9uZ2Zvcm0vYmFzaWNfd19yZXF1aXJlRXhhY3REdXJhAS7wny5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEwuYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDfaBAIIAOAEAPAExOefR4gFAZgFAKAF______8BBRQBwAUAyQVpYhTwP9IFCQkJDHQAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYJJCjwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=dc7d874e52ac39980ec1070a7769632be56a2f00", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQlNxwleAAAAABGPSMYYqC5MexlNxwleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=9fd739e9f0a6054296f9bb5168c49a89a425795c&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL4COh4BAAAAwDWAAUBCM2Op_AFEI-RmcaB1Yumexiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4xbgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiE1anJrR1FpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQm5LY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWG9KWno5WkdPTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME4tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWXNscVFVCRNAQUR3UHcuLpoCiQEhT3ctaUY6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelEzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEufC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvDtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ32gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAIkAFQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=1f8ea8f07f781fe149beb0d65dd25ad725a12f3b" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "1279521442385130931", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCM2Op_AFELPr8f6Pv_HgERiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5MTQ5KTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIW9EeDJEQWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFkb01fcFZkVGVVXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMwTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZc2xxUVUJE0RBRHdQdy4umgKJASFKdzlKRHc2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOelEzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEu8J8uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ32gQCCADgBADwBMXdn0eIBQGYBQCgBf______AQUUAcAFAMkFaWIU8D_SBQkJCQx4AADYBQHgBQHwBcLyF_oFBAgAEACQBgGYBgC4BgDBBgklKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=4b14660ae659b3d301ec6c40f0f096bb88db145b", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQlNxwleAAAAABGzddz_-MXBERlNxwleAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=5f277bcab624f05c9d3a3a9c111961f3f33ccca2&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_w_requireExactDuration.html&e=wqT_3QL5CKB5BAAAAwDWAAUBCM2Op_AFELPr8f6Pv_HgERiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXjFuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc2OTkxNDkpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIW9EeDJEQWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCbktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFkb01fcFZkVGVVXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMwTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZc2xxUVUJE0RBRHdQdy4umgKJASFKdzlKRHc2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOelEzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8F5lQUEu2AIA4AKtmEjqAllodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dfcmVxdWlyZUV4YWN0RHVyYQEufC5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWMhYAIExFQUZfTkFNRQEdCB4KGjYdAAhBU1QBPvDeSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMLmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ32gQCCAHgBADwBMXdn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXC8hf6BQQIABAAkAYBmAYAuAYAwQYAAGHxKPA_0Ab1L9oGFgoQAQ8uAQBQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=7bb7b75e4769a1260eaed2c79752ee542b4d28ce" + } + } + } + ] + }, + { + "uuid": "25593f19ac7ed2", + "tag_id": 15394006, + "auction_id": "7664937561033023835", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/description.md b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/description.md new file mode 100644 index 00000000000..159ebbcc30b --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_wo_brandCategoryExclusion.html' +Test Spec File - 'test/spec/e2e/longform/basic_wo_brandCategoryExclusion.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: false + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/request.json b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/request.json new file mode 100644 index 00000000000..2d1fa3f16bf --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/request.json @@ -0,0 +1,386 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/response.json b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/response.json new file mode 100644 index 00000000000..bfef650e07a --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_1/response.json @@ -0,0 +1,654 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "6316075342634007031", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEPfztqL2oc3TVxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIV96eWNLZ2lua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFZYkYwSW1fZGU0XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0BBRHdQdy4umgKJASE5dzR0Xzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56VXdRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCADgBADwBIvhn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAaakRAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=bb81a081c756fd493253bf765c06ff46888f009a", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABH3uU1kDzWnVxk3yQleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=a3da30186f69a5ce2edcfc14fa3a31b92ee70060&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEPfztqL2oc3TVxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFfenljS2dpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWWJGMEltX2RlNF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNAQUR3UHcuLpoCiQEhOXc0dF86PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTDaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEUAcAFAMkFacEU8D_SBQkJCQx4AADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=62b9db151b3739399e0970c74fafc4bb61486510" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "8259815099516488747", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFEKuY2qihwrDQchiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIW1UeUFCd2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYNml4eGFGdE8wXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFOUTg3RkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAAGmpDQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=8a55db8e788616ef057647b49c0560296fdacb65", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABErjBYVEsKgchk3yQleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=75d46be63f76fd4062f354a56c692855da366148&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFEKuY2qihwrDQchiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFtVHlBQndpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWDZpeHhhRnRPMF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhTlE4N0ZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPDtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAIkDFQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=59e0ab1f626c2e4dc5c4f6e6837b77559cf502b4" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "7960926407704980889", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEJnboLK5jLm9bhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIUZEeFl4QWlta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhSUpVQVhXMC1JXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFTQThFR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATf359HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=8d00bc7576c3cc19fe8b3fb4aa42966583741dfa", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABGZLUiWY-R6bhk3yQleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=c813392cbb81d43466d5d949b9bebc2305e6fe7d&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEJnboLK5jLm9bhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiFGRHhZeEFpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYUlKVUFYVzAtSV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhU0E4RUd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=284760a6e2d4f226b639d29237e9c1aa25ca49a9" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "7561862402601574638", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEO7By9umucj4aBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCITREcWpId2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFTSVA1dzg5RGVRXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0BBRHdQdy4umgKJASFTUTlYRzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56VXdRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCADgBADwBNLsn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAaakRAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=917e8af2ed1c82091f487b6abd78de47b99e9e46", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABHu4HJryiHxaBk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=ff73768bfb14e9ae603064fc91e95b60c8d872e2&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEO7By9umucj4aBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiE0RHFqSHdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBU0lQNXc4OURlUV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNAQUR3UHcuLpoCiQEhU1E5WEc6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTDaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEUAcAFAMkFacEU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=84c66b632a2930d28092e00985ee154ba2e97288" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "6577796711489765634", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEIKC0sii6MGkWxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIVBUem53UWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFlaE5hMWl1Y3V3XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASE5dzR0X2c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=ea4a54786a8f3cf5177b3372ce97682da060c358", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABECgRQpQgdJWxk3yQleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=778fbf3014328ec0b01d6ebd7b306be32cf79950&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEIKC0sii6MGkWxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFQVHpud1FpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZWhOYTFpdWN1d18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhOXc0dF9nNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=28a3b583912b95528519f63a75c0fe2d06064e7b" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "2418275491761094586", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFELr_z7v0l9zHIRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIUF6MUJSZ2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFVNUE2dXpUVy1ZXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFTUTlYR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=c563626304ebb31fd6f1644cc2d4098133dec096", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABG6_3NHv3CPIRk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=88c9fbb2b9dc273865a5f9238543a29224908b26&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFELr_z7v0l9zHIRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFBejFCUmdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVTVBNnV6VFctWV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhU1E5WEd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=e76aeb8daad477f4428631fc89d277d4a4646ded" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "5990197965284733361", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFELHjwfj9qd2QUxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIURUeDF3d2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFmWXBYSEoxUGVNXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0BBRHdQdy4umgKJASFTUTlYRzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56VXdRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCADgBADwBNLsn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAaakRAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=e443347514ff5f6a52a2811f591f9a346061a756", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABGxcRDfT3UhUxk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=50348eb78116f7d35ca5ac6f6fa4c5548a6ceffc&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFELHjwfj9qd2QUxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFEVHgxd3dpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZllwWEhKMVBlTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNAQUR3UHcuLpoCiQEhU1E5WEc6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTDaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEUAcAFAMkFacEU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=a24f331ff55f96c5afe5134762f8d8e230b6287c" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "4399290132982250349", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEO32psKU4tqGPRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCITN6dDlwd2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFRWlZqbkpncmV3XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0BBRHdQdy4umgKJASFTUTlYRzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56VXdRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCADgBADwBNLsn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAaakRAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=0d9b0a06992ff427d281fae8d8b18d4e6838b944", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABFtu0lIEWsNPRk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=52a446d84f5e9a2baa068760c4406f4a567a911a&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEO32psKU4tqGPRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiEzenQ5cHdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBUVpWam5KZ3Jld18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNAQUR3UHcuLpoCiQEhU1E5WEc6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTDaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEUAcAFAMkFacEU8D_SBQkJCQx4AADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgklKPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=e6ae592b5fc3de0053b5acd46294b83549aa00c8" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "8677372908685012092", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEPzYku74lY62eBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIVVEeGp5d2lua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFVN29abmh2c09RXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASE5dzR0X2c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=522b764f2276ce75053a55a0198b79fb8d1d39d5", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABF8rMSNrzhseBk3yQleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=02b75d0ecc71c7897b9590be5e50b094158c8097&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEPzYku74lY62eBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFVRHhqeXdpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVTdvWm5odnNPUV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhOXc0dF9nNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=0ae5558a7b0cc87eaa0c6811522629963b41bac5" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "617065604518434488", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFELitu4PevJDICBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIUFqMVNSZ2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaUzdZYTg5Ny13XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFTUTlYR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9HYBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAAAAAAAAAAAAAAAAAAAAEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=f59bdb7b0f7020f75c6019f23686915b72d61779", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABG41m7g5UGQCBk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=912a721db8e85d4d64a8869d7cf9b56cd0c24907&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFELitu4PevJDICBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFBajFTUmdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWlM3WWE4OTctd18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhU1E5WEd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBGAHABQDJBQAFARTwP9IFCQkFC3wAAADYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgEhMAAA8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=9b4372ae0674305d9cd7152959910d1fa7d4daec" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "8957511111704921777", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFELGNpebanN6nfBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIXVqdHppQWlta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFUM1dNOVpkQU9JXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0BBRHdQdy4umgKJASFIZzhRRDo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56VXdRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCADgBADwBK_ln0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPC_0Ab1L9oGFgoQAAAAaakNAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=a8817d9dc3326ba1b59fe308f126ddaca5710a9c", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABGxRsms5XhPfBk3yQleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=a0ac94e902cbc609881fa9f39537bbc67ba046e7&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFELGNpebanN6nfBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiF1anR6aUFpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVDNXTTlaZEFPSV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNAQUR3UHcuLpoCiQEhSGc4UUQ6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NTDaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEUAcAFAMkFacEU8D_SBQkJCQx0AADYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGCSQo8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=75b3ad3e867323196da165cd655b3ae51c8b44d0" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "2680240375770812721", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFELGi6rO9jYiZJRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIWd6eTMtZ2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYcFdVTk9rai1jXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFOUTg3RkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAAGmpDQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=f8458c6a48fed591c269169a9744aba11cb90285", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABExkXrWayAyJRk3yQleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=e2dbd082b353a37db9f632efc2532913a0c48166&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFELGi6rO9jYiZJRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFnenkzLWdpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWHBXVU5Pa2otY18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhTlE4N0ZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPDtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAIkDFQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=5475ac640321ae51a06b5c05ac62519e97e90114" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "8439286287321689724", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFEPzciY2kxZePdRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIU1UeWZ6d2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFWalR1QThjek9FXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFOUTg3RkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAAGmpDQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=73e760427d2aec3d47824994cf35c35f1eeddcf8", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABF8bqJBKl4edRk3yQleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=dac1e836a6f2c4dc036c50d0b3128dfefb34915d&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFEPzciY2kxZePdRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFNVHlmendpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVmpUdUE4Y3pPRV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhTlE4N0ZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPDtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAIkDFQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=6c1fb35564d2ffd08fb4c5b290aadd6e1e3d83ec" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "5519278898732145414", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEIa29Pmn3ZrMTBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCITFEc0hwUWlta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFkQUZ3YVliRWVNXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFTQThFR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATf359HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=d01f411e7cc9126e912daca85136b2ca6f99a347", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABEGGz1_6mqYTBk3yQleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=81115280cee86ae0bc259627410fa5dbbc178646&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEIa29Pmn3ZrMTBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiExRHNIcFFpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBZEFGd2FZYkVlTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhU0E4RUd3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=90f21feeb2c798cd77b3cadbc961240238825f0d" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "6754624236211478320", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFELC-hPXI3s_eXRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIVJqc0hVUWlta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaRjJPd05MVnVvXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMxTU9BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZNGxxUVUJE0RBRHdQdy4umgKJASFOUTg3RkE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelV3UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc1MNoEAggA4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAAGmpDQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=34811f7e5c917550619274f5b75a0cd214119812", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABEwH6GO9D69XRk3yQleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=d811faa48963b18d33c0a1f9d1e64ff97640a415&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFELC-hPXI3s_eXRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4ybgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFSanNIVVFpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWkYyT3dOTFZ1b18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjMU1PQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTRscVFVCRNEQUR3UHcuLpoCiQEhTlE4N0ZBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpVd1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPDtSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzUw2gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPA_0Ab1L9oGFgoQAIkDFQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=c0a0a2d65dd091bd2ed81f95da1a9f7ff16ad70e" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/description.md b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/description.md new file mode 100644 index 00000000000..159ebbcc30b --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_wo_brandCategoryExclusion.html' +Test Spec File - 'test/spec/e2e/longform/basic_wo_brandCategoryExclusion.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: false + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/request.json b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/request.json new file mode 100644 index 00000000000..5a5ddce7d54 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/request.json @@ -0,0 +1,136 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/response.json b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/response.json new file mode 100644 index 00000000000..9273f8e0c7b --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_brandCategoryExclusion_2/response.json @@ -0,0 +1,224 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "4631210661889362034", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEPKQq-_0sdeiQBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIXF6eU1HUWlua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFVQk5fYTFxbHU0XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASFTd19PR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0M9oEAggA4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=0dae5294ed5bb48b7d3a156e5e587a26da27c7e1", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABFyyOpNj11FQBk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=9085e4dbb4849b0e6d3714d84a2754bbab578e16&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEPKQq-_0sdeiQBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4z7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFxenlNR1FpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVUJOX2ExcWx1NF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhU3dfT0d3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=aa5533d04e16ee398f8028ab3af03a48d7d8cc17" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "714778825826946473", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEKmbi7Ph8dn1CRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIU56dmJOZ2lua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFRbjlXUzRmY09jXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0BBRHdQdy4umgKJASEtUTZrXzo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56UXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0UwFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCADgBADwBIvhn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYAAAAAAADwv9AG9S_aBhYKEAAAaakRAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=8917b1722eed5b6d85c6d5a01eea7862089bee32", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABGpzWIWjmfrCRk3yQleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=9ec7e7de16b948b60d74b47f1917faf5d3b6dbf0&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEKmbi7Ph8dn1CRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4z7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFOenZiTmdpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBUW45V1M0ZmNPY18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNAQUR3UHcuLpoCiQEhLVE2a186PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8N5JRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAeAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAAAAADYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgAAYfQo8D_QBvUv2gYWChABDy4BAFAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=8198652a5ee16abf4595ab1bfc6b051f81f0579d" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "231404788116786844", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFEJydmpjcrYebAxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIUVqMFlVZ2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhLXFPTExmZ2VrXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASFTd19PR3c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0M9oEAggA4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=775dfc49086467337dee9a5e8d78b361931c6aaa", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABGcjgbDbR02Axk3yQleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=914256a92514df787ccb1eae7dea7578d23c8fba&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFEJydmpjcrYebAxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4z7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFFajBZVWdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYS1xT0xMZmdla18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhU3dfT0d3Nj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPCQSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBGGQIIgFAZgFAKAF_xEBFAHABQDJBWnBFPA_0gUJCQkMeAAA2AUB4AUB8AXZugb6BQQIABAAkAYBmAYAuAYAwQYJJSjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=f624619431372f9a248d0fa0dd8d09c4977bb544" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "7557072342526904599", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKfCKAfBAAAAwDWAAUBCLeSp_AFEJeS-7GaqIfwaBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIUFqdmVKQWlta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFSY2lLblVqeU9VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0BBRHdQdy4umgKJASFJQS1IRDo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56UXpRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0dQFlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCADgBADwBK_ln0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXgWPoFBAgAEACQBgGYBgC4BgDBBgAAAAAAAPC_0Ab1L9oGFgoQAAAAAAAAAAAAAAAAAAAAABAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=552663ed1246fd2a3cc5824164f57d32f18078ee", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQk3yQleAAAAABEXyT6mQR3gaBk3yQleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=e1c80e622aa60bf7683413f4371b0055d0d16f47&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL7COh7BAAAAwDWAAUBCLeSp_AFEJeS-7GaqIfwaBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4z7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFBanZlSkFpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBUmNpS25VanlPVV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNAQUR3UHcuLpoCiQEhSUEtSEQ6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlxodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX2JyYW5kQ2F0ZWdvcnlFeGNsdXNpb24uaHRtbPICEwoPQ1VTVE9NX01PREVMX0lEEgDyAhoKFkNVU1RPTQ0WQExFQUZfTkFNRRIA8gIeChpDMh0ACEFTVAEo8JBJRklFRBIAgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gEy-YEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDPaBAIIAeAEAPAEYZAgiAUBmAUAoAX_EQEYAcAFAMkFAAUBFPA_0gUJCQULeAAAANgFAeAFAfAF4Fj6BQQIABAAkAYBmAYAuAYAwQYBIDAAAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=ccf266d1b02551a2ad0af0871d4af43e4aee4bba" + } + } + } + ] + }, + { + "uuid": "2c52d7d1f2f703", + "tag_id": 15394006, + "auction_id": "5093465143102876632", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QKgCKAgBAAAAwDWAAUBCLeSp_AFENjX7JP78efXRhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIUJUeXRwUWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCcktjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYamVBMVdNcXUwXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwTS1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZY2xxUVUJE0RBRHdQdy4umgKJASEtUTZrX2c2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelF6UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9FMBZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATL5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0M9oEAggA4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAAAAAAAAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8L_QBvUv2gYWChAAAGmpEQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=6651c1436b699842aabb3ae53d96d07caf5b4938", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQk3yQleAAAAABHYK3uyj5-vRhk3yQleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=f62098bf5037b22ca4e5583289a1527fdfa87e43&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_brandCategoryExclusion.html&e=wqT_3QL8COh8BAAAAwDWAAUBCLeSp_AFENjX7JP78efXRhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4z7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3Njk5NjM5KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFCVHl0cFFpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQnJLY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWGplQTFXTXF1MF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME0tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWWNscVFVCRNEQUR3UHcuLpoCiQEhLVE2a19nNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRelFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJcaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19icmFuZENhdGVnb3J5RXhjbHVzaW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT00NFkBMRUFGX05BTUUSAPICHgoaQzIdAAhBU1QBKPDeSUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBMvmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQz2gQCCAHgBADwBIvhn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AXa1gL6BQQIABAAkAYBmAYAuAYAwQYAAGH0KPA_0Ab1L9oGFgoQAQ8uAQBQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=4b43aaab766ee7d2e4c900ec32cb3c8b7ccef1d0" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/description.md b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/description.md new file mode 100644 index 00000000000..c1781561af5 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_wo_requireExactDuration.html' +Test Spec File - 'test/spec/e2e/longform/basic_wo_requireExactDuration.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/request.json b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/request.json new file mode 100644 index 00000000000..aba76398093 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/request.json @@ -0,0 +1,387 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/response.json b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/response.json new file mode 100644 index 00000000000..c35a47781f7 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_1/response.json @@ -0,0 +1,366 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "8905202273088829598", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCLWXp_AFEJ7x1-ORyejKexiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIWlEeE84Z2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhV09TRWpDY09NXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0BBRHdQdy4umgKJASFQZzlaRjo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56YzNRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0DgFlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc3N9oEAggA4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAZWQU8D_SBQkJBQt4AAAA2AUB4AUB8AWZPfoFBAgAEACQBgGYBgC4BgDBBgEgMAAA8L_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=21195aa3e27f8eb88ba43d5da32e6b78c2aa03f8", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQm1ywleAAAAABGe-HUcSaKVexm1ywleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=3c05b8509dd5c7c4459886f4c69fdd9cd07caa66&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCLWXp_AFEJ7x1-ORyejKexiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiFpRHhPOGdpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYVdPU0VqQ2NPTV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjM04tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCYWtscVFVCRNAQUR3UHcuLpoCiQEhUGc5WkY6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTQUWPExFQUZfTkFNRRIA8gIeChoyMwDwwkxBU1RfTU9ESUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBNXmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0Nzc32gQCCAHgBADwBMTnn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAGXObNgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYFISwA8D_QBvUv2gYWChAJERkBUBAAGADgBgTyBgIIAIAHAYgHAKAHQA..&s=203ae79160a460b18f20165e5de53bb1f45e4933" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "2428831247136753876", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFENSR0sfppLzaIRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIXRUeV9FQWlta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFTek5nNXJvQi0wXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFVUThpSFE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAE39-fR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=af2d5096aa4f934e84b59ad16cd18dfe5b9bbc77", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABHUiPSYJvG0IRm1ywleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=440a389c7f556dac70c650bb1e593a10cbcdf2af&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFENSR0sfppLzaIRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiF0VHlfRUFpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBU3pOZzVyb0ItMF8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjM04tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCYWtscVFVCRNEQUR3UHcuLpoCiQEhVVE4aUhRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpjM1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc3N9oEAggB4AQA8ATf359HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlznDYBQHgBQHwBay8FPoFBAgAEACQBgGYBgC4BgDBBgUiLADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=9b00ed17c420f328d63b72519d2d578c5921d0d7" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "1625697369389546128", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEJD1gLbO5OjHFhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIXVqeHMtUWlua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFhcDVwSkxuSXVVXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFBQTlhQUE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=0e70f535a95c82238d685147f41e0bd2f86631c0", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABGQOsDmJKOPFhm1ywleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=144214d77cc4ced0893c9fe64132ad01c429c43c&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFEJD1gLbO5OjHFhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiF1anhzLVFpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYXA1cEpMbkl1VV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjM04tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCYWtscVFVCRNEQUR3UHcuLpoCiQEhQUE5YUFBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpjM1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc3N9oEAggB4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlznDYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgUiLADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=f6bc475b66c167036dcb9f10c7c5f176124829a6" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "5434800203981031918", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCLWXp_AFEO6TivzZv5K2Sxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCIW5Ud3I5QWlta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFXVVcwV1Y1LU9JXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFKdzh1RGc2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULeAAAANgFAeAFAfAF4Fj6BQQIABAAkAYBmAYAuAYAwQYBIDAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=c3ba85f0eb0293896e02066385f82b4450af2cfb", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQm1ywleAAAAABHuiYKf_UlsSxm1ywleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=9eb2d880fa9b524a6a0807eef0c65b7b1393f48a&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCLWXp_AFEO6TivzZv5K2Sxiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiFuVHdyOUFpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBV1VXMFdWNS1PSV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjM04tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCYWtscVFVCRNEQUR3UHcuLpoCiQEhSnc4dURnNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpjM1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc3N9oEAggB4AQA8ASv5Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlzmzYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGBSEsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=17038c2671b58d2fd6ea98dd3f3e1166ee664dd0" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "8071104954749355970", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEMKP7OWZ5pSBcBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIXBUeEJEQWlsa184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFRbWtta1pXNGVZXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFSZ19sR1E2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAE0uyfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=005579c0ff91586a887354409f637a63a1d69031", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABHCB7ucMVMCcBm1ywleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=edbfae73be0f41d672298d5c3ec9dd28a5307233&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6CKB6BAAAAwDWAAUBCLWXp_AFEMKP7OWZ5pSBcBiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDS7J9HWJzxW2AAaM26dXjWuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc3MDAyNzcpO3VmKCdyJywgMTQ5NDE5NjAyLCAxNRkf8P2SArkCIXBUeEJEQWlsa184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFRbWtta1pXNGVZXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFSZ19sR1E2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTQUWPExFQUZfTkFNRRIA8gIeChoyMwDwwkxBU1RfTU9ESUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBNXmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0Nzc32gQCCAHgBADwBNLsn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAGXOcNgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGBSIsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=0ac18b64a6c0d58a114085d8b565b4c98de56448" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "6893555531330982923", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEIuopuO2h7XVXxiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE0MTg4Nh8A8P2SArkCIVFqd1R0Z2lHa184UEVLekNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFFajRyM1ZBQUFxUU1FQkktSzkxUUFBS2tESkFZS1J6NEZQV2V3XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRGhwUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASEzUTZnOHc2PQEkblBGYklBUW9BRBVIVHFRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAErMKfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAF8owB-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=f9ddb1066825dfc556d108168ffc0d16cf567ae8", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABELlGlsO9SqXxm1ywleAAAAACCswp9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jyjAFiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAazCn0ewAQE.&s=db3a0d52f97edd94aa7e4213c437d8e4a5bd16ce&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149414188, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 13.00001, + "cpm_publisher_currency": 13.00001, + "publisher_currency_code": "$", + "brand_category_id": 32, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 29000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFEIuopuO2h7XVXxiq5MnUovf28WEqNgmOWItPAQAqQBGOWItPAQAqQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQrMKfR1ic8VtgAGjNunV41rgFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxNDE4OCwgMTUZH_D9kgK5AiFRandUdGdpR2tfOFBFS3pDbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRRWo0cjNWQUFBcVFNRUJJLUs5MVFBQUtrREpBWUtSejRGUFdld18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RocFBfRDdvRENWTkpUak02TkRjM04tQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCYWtscVFVCRNEQUR3UHcuLpoCiQEhM1E2Zzh3Nj0BJG5QRmJJQVFvQUQVSFRxUURvSlUwbE9Nem8wTnpjM1FNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc3N9oEAggB4AQA8ASswp9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlznDYBQHgBQHwBfKMAfoFBAgAEACQBgGYBgC4BgDBBgUiLADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=917c8192c7dc7e382c0bb7296ab0df261e69f572" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "5615186251901272031", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "6647218197537074925", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "4707051182303115567", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "4831890668873532085", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "7151522995196673389", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "4077353832159380438", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFENaHwKvS9urKOBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE3NjY5Nh8A8P2SArkCIWJqeHo1UWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFZd1VQNVZMNi1VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFLZzhBRUE2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NzfaBAIIAOAEAPAExd2fR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=e96d121a0a7d49e05c1d2b4fab2da60d0b544287", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABHWA3AltauVOBm1ywleAAAAACDF3Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jC8hdiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAcXdn0ewAQE.&s=8d90e3ce42fe47da19cb85f8fb2d78822c590464&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417669, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 4, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6CKB6BAAAAwDWAAUBCLWXp_AFENaHwKvS9urKOBiq5MnUovf28WEqNgkAAAECCCRAEQEHEAAAJEAZCQkI4D8hCQkIJEApEQkAMQkJsOA_MNbJqwc47UhA7UhIAlDF3Z9HWJzxW2AAaM26dXjWuAWAAQGKAQNVU0SSAQEG8FWYAQGgAQGoAQGwAQC4AQPAAQTIAQLQAQDYAQDgAQDwAQCKAjx1ZignYScsIDI1Mjk4ODUsIDE1Nzc3MDAyNzcpO3VmKCdyJywgMTQ5NDE3NjY5LCAxNRkf8P2SArkCIWJqeHo1UWlsa184UEVNWGRuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIenJXcWtBQUFrUU1FQjg2MXFwQUFBSkVESkFZd1VQNVZMNi1VXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBaUF9EN29EQ1ZOSlRqTTZORGMzTi1BRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJha2xxUVUJE0RBRHdQdy4umgKJASFLZzhBRUE2PQEkblBGYklBUW9BRBVIVGtRRG9KVTBsT016bzBOemMzUU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTQUWPExFQUZfTkFNRRIA8gIeChoyMwDwwkxBU1RfTU9ESUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBNXmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0Nzc32gQCCAHgBADwBMXdn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAGXOcNgFAeAFAfAFwvIX-gUECAAQAJAGAZgGALgGAMEGBSIsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=db30796cc71c3bee3aa8fc2890c75ad7186f9d73" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "2099457773367093540", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "7214207858308840891", + "nobid": true, + "ad_profile_id": 1182765 + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "4564285281969145467", + "nobid": true, + "ad_profile_id": 1182765 + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/description.md b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/description.md new file mode 100644 index 00000000000..c1781561af5 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/description.md @@ -0,0 +1,40 @@ +Test Page - 'integrationExamples/longform/basic_wo_requireExactDuration.html' +Test Spec File - 'test/spec/e2e/longform/basic_wo_requireExactDuration.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'sample-code', + sizes: [640, 480], + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + requireExactDuration: false + } + }, + bids: [ + { + bidder: 'appnexus', + params: { + placementId: 15394006 + } + } + ] +}]; +``` + +SetConfig to use with AdUnit: +``` +pbjs.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + }, + adpod: { + brandCategoryExclusion: true + } +}); +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/request.json b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/request.json new file mode 100644 index 00000000000..f2f20700ffe --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/request.json @@ -0,0 +1,137 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + }, + { + "sizes": [ + { + "width": 640, + "height": 480 + } + ], + "primary_size": { + "width": 640, + "height": 480 + }, + "ad_types": [ + "video" + ], + "id": 15394006, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 7, + "require_asset_url": true, + "video": { + "maxduration": 30 + } + } + ], + "user": {}, + "brand_category_uniqueness": true + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/response.json b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/response.json new file mode 100644 index 00000000000..5f2118095d4 --- /dev/null +++ b/test/fake-server/fixtures/longform/longform_wo_requireExactDuration_2/response.json @@ -0,0 +1,224 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "2704229116537156015", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEK_j3NPcwdbDJRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE3OTUxNh8A8P2SArkCIXpUczJvQWlta184UEVOX2ZuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFURVBwVy1oVE9ZXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwT2VBRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZMGxxUVUJE0BBRHdQdy4umgKJASFVQV9qSDo9ASRuUEZiSUFRb0FEFUhUdVFEb0pVMGxPTXpvME56UTVRTUlZUxF4DFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQz0DgFlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWyAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0OdoEAggA4AQA8ATf359HiAUBmAUAoAX___________8BwAUAyQUAZWQU8D_SBQkJBQt8AAAA2AUB4AUB8AWsvBT6BQQIABAAkAYBmAYAuAYAwQYBITAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=64565aadf65d370e9730e9ce82c93c9bd2fcfc14", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABGvMXfKDVqHJRm1ywleAAAAACDf359HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1isvBRiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAd_fn0ewAQE.&s=3b1f10f67b3253e38770fff694edbe6052795602&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149417951, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 33, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFEK_j3NPcwdbDJRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ39-fR1ic8VtgAGjNunV4t7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxNzk1MSwgMTUZH_D9kgK5AiF6VHMyb0FpbWtfOFBFTl9mbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBVEVQcFctaFRPWV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME9lQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTBscVFVCRNAQUR3UHcuLpoCiQEhVUFfakg6PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelE1UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8ItlQUEu2AIA4AKtmEjqAlpodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OS9pbnRlZ3JhdGlvbkV4YW1wbGVzL2xvbmdmb3JtL2Jhc2ljX3dvX3JlcXVpcmVFeGFjdER1cmF0aW9uLmh0bWzyAhMKD0NVU1RPTV9NT0RFTF9JRBIA8gIaChZDVVNUT01fTQUWPExFQUZfTkFNRRIA8gIeChoyMwDwwkxBU1RfTU9ESUZJRUQSAIADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIEDTIwMi41OS4yMzEuNDeoBNXmBLIEEggBEAIYgAUg4AMoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzQ52gQCCAHgBADwBN_fn0eIBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAGXOcNgFAeAFAfAFrLwU-gUECAAQAJAGAZgGALgGAMEGBSIsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=5316c3262f36e4d89735b1ba252c64651a84f479" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "7987581685263122854", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEKaDmaSQ5-Xsbhiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE5NjAyNh8A8P2SArkCIU16MXpZd2lua184UEVOTHNuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFYLVkxZU5tY3VRXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwT2VBRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZMGxxUVUJE0RBRHdQdy4umgKJASFVUTgySFE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelE1UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDnaBAIIAOAEAPAE0uyfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAF2boG-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=17f2a3f5e78c188cc6ca23e677ced305198a8a05", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABGmQYYEOZfZbhm1ywleAAAAACDS7J9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jZugZiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAdLsn0ewAQE.&s=28e8f96efdfb9bc1e33e4d087ff5ed992e4692b1&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149419602, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 24, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFEKaDmaSQ5-Xsbhiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQ0uyfR1ic8VtgAGjNunV4t7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxOTYwMiwgMTUZH_D9kgK5AiFNejF6WXdpbmtfOFBFTkxzbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWC1ZMWVObWN1UV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME9lQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTBscVFVCRNEQUR3UHcuLpoCiQEhVVE4MkhRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRNVFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0OdoEAggB4AQA8ATS7J9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlznDYBQHgBQHwBdm6BvoFBAgAEACQBgGYBgC4BgDBBgUiLADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=89d4586d9597cd2f9a4a918d1e6985aee45ade01" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "653115326806257319", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCLWXp_AFEKfdmd3enZWICRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4NjcxNh8A8P2SArkCITlEd0hNZ2lta184UEVLX2xuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFjTnlESmJxeS13XzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwT2VBRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZMGxxUVUJE0RBRHdQdy4umgKJASFKZ192RFE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelE1UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDnaBAIIAOAEAPAEr-WfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULeAAAANgFAeAFAfAF4Fj6BQQIABAAkAYBmAYAuAYAwQYBIDAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=1928a9daadbd431792adace7620880dda961eefb", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQm1ywleAAAAABGnbqbr7VQQCRm1ywleAAAAACCv5Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1jgWGICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBr-WfR7ABAQ..&s=7617d08e0c16fe1dea8ec80cd6bf73ec0a736b41&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418671, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 30, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCLWXp_AFEKfdmd3enZWICRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQr-WfR1ic8VtgAGjNunV4t7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODY3MSwgMTUZH_D9kgK5AiE5RHdITWdpbWtfOFBFS19sbjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBY055REpicXktd18yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME9lQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTBscVFVCRNEQUR3UHcuLpoCiQEhSmdfdkRRNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRNVFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0OdoEAggB4AQA8ASv5Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlzmzYBQHgBQHwBeBY-gUECAAQAJAGAZgGALgGAMEGBSEsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=0d1d3f42fa225995a2f57ab84877dce3d24e9901" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "866435845408148233", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKeCKAeBAAAAwDWAAUBCLWXp_AFEImW35H52YyDDBiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4MTIzNh8A8P2SArkCIXJEenNfZ2lua184UEVJdmhuMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFjMmZTZ1BpMi1BXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHA1UF9EN29EQ1ZOSlRqTTZORGMwT2VBRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZMGxxUVUJE0RBRHdQdy4umgKJASFfdzRiQUE2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelE1UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDnaBAIIAOAEAPAEi-GfR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULfAAAANgFAeAFAfAF2tYC-gUECAAQAJAGAZgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=83f65f38b4fd56344b3aceb70df7bac1b9b5f229", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=aAAAAAMArgAFAQm1ywleAAAAABEJyzeSzzIGDBm1ywleAAAAACCL4Z9HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1ja1gJiAklOaAFwAXgAgAEBiAEBkAGABZgB4AOgAQCoAYvhn0ewAQE.&s=9130c13cca7a1d3eb05c2b96585ccfdc2faa6844&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418123, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 12, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 15000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL6COh6BAAAAwDWAAUBCLWXp_AFEImW35H52YyDDBiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQi-GfR1ic8VtgAGjNunV4t7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODEyMywgMTUZH_D9kgK5AiFyRHpzX2dpbmtfOFBFSXZobjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBYzJmU2dQaTItQV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwNVBfRDdvRENWTkpUak02TkRjME9lQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTBscVFVCRNEQUR3UHcuLpoCiQEhX3c0YkFBNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRNVFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0OdoEAggB4AQA8ASL4Z9HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlznDYBQHgBQHwBdrWAvoFBAgAEACQBgGYBgC4BgDBBgUiLADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGBPIGAggAgAcBiAcAoAdA&s=1f88d8b0a467d528291f90a54fd810b8fdac4488" + } + } + } + ] + }, + { + "uuid": "2022b6b1fcf477", + "tag_id": 15394006, + "auction_id": "1540903203561034860", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QKdCKAdBAAAAwDWAAUBCLWXp_AFEOyokYzL6ZixFRiq5MnUovf28WEqNgkAAAkCABEJBwgAABkJCQjgPyEJCQgAACkRCQAxCQnwaeA_MNbJqwc47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEDwAEAyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTsBHTByJywgMTQ5NDE4OTQ4Nh8A8P2SArkCIXdUekVId2lta184UEVNVG5uMGNZQUNDYzhWc3dBRGdBUUFSSTdVaFExc21yQjFnQVlJSUNhQUJ3QUhnQWdBSElBb2dCd3FjRGtBRUFtQUVBb0FFQnFBRURzQUVBdVFIdEJLRDJBQUF1UU1FQjdRU2c5Z0FBTGtESkFaeE00NUxjRXVNXzJRRUFBQUFBQUFEd1AtQUJBUFVCQUFBQUFKZ0NBS0FDQUxVQ0FBQUFBTDBDQUFBQUFPQUNBT2dDQVBnQ0FJQURBWmdEQWFnRHBwUF9EN29EQ1ZOSlRqTTZORGMwT2VBRHdoaUlCQUNRQkFDWUJBSEJCQUFBQQ1yCHlRUQ0KJEFBQU5nRUFQRUUBCwkBMEQ0QkFDSUJZMGxxUVUJE0RBRHdQdy4umgKJASFQUThhRmc2PQEkblBGYklBUW9BRBVIVHVRRG9KVTBsT016bzBOelE1UU1JWVMReAxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M9A4BZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1sgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQNMjAyLjU5LjIzMS40N6gE1eYEsgQSCAEQAhiABSDgAygBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3NDnaBAIIAOAEAPAExOefR4gFAZgFAKAF____________AcAFAMkFAGVkFPA_0gUJCQULeAAAANgFAeAFAfAFmT36BQQIABAAkAYBmAYAuAYAwQYBIDAAAPC_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=a4de0e4084ce04a5cb2d347c07fde867aa9ff5c1", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "video", + "notify_url": "https://sin3-ib.adnxs.com/vast_track/v2?info=ZwAAAAMArgAFAQm1ywleAAAAABFsVISxTGNiFRm1ywleAAAAACDE559HKAAw7Ug47UhA0-hISLuv1AFQ1smrB1iZPWICSU5oAXABeACAAQGIAQGQAYAFmAHgA6ABAKgBxOefR7ABAQ..&s=cf600d825cec85f83c06119e5e383f8548b469a2&event_type=1", + "usersync_url": "https%3A%2F%2Facdn.adnxs.com%2Fdmp%2Fasync_usersync.html", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 149418948, + "media_type_id": 4, + "media_subtype_id": 64, + "cpm": 15.00001, + "cpm_publisher_currency": 15.00001, + "publisher_currency_code": "$", + "brand_category_id": 1, + "client_initiated_ad_counting": true, + "rtb": { + "video": { + "player_width": 640, + "player_height": 480, + "duration_ms": 30000, + "playback_methods": [ + "auto_play_sound_on" + ], + "frameworks": [ + "vpaid_1_0", + "vpaid_2_0" + ], + "asset_url": "https://sin3-ib.adnxs.com/ab?ro=1&an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2FintegrationExamples%2Flongform%2Fbasic_wo_requireExactDuration.html&e=wqT_3QL5COh5BAAAAwDWAAUBCLWXp_AFEOyokYzL6ZixFRiq5MnUovf28WEqNgmOWItPAQAuQBGOWItPAQAuQBkAAAECCOA_IREbACkRCQAxARm4AADgPzDWyasHOO1IQO1ISAJQxOefR1ic8VtgAGjNunV4t7gFgAEBigEDVVNEkgEBBvBVmAEBoAEBqAEBsAEAuAEDwAEEyAEC0AEA2AEA4AEA8AEAigI8dWYoJ2EnLCAyNTI5ODg1LCAxNTc3NzAwMjc3KTt1ZigncicsIDE0OTQxODk0OCwgMTUZH_D9kgK5AiF3VHpFSHdpbWtfOFBFTVRubjBjWUFDQ2M4VnN3QURnQVFBUkk3VWhRMXNtckIxZ0FZSUlDYUFCd0FIZ0FnQUhJQW9nQndxY0RrQUVBbUFFQW9BRUJxQUVEc0FFQXVRSHRCS0QyQUFBdVFNRUI3UVNnOWdBQUxrREpBWnhNNDVMY0V1TV8yUUVBQUFBQUFBRHdQLUFCQVBVQkFBQUFBSmdDQUtBQ0FMVUNBQUFBQUwwQ0FBQUFBT0FDQU9nQ0FQZ0NBSUFEQVpnREFhZ0RwcFBfRDdvRENWTkpUak02TkRjME9lQUR3aGlJQkFDUUJBQ1lCQUhCQkFBQUENcgh5UVENCiRBQUFOZ0VBUEVFAQsJATBENEJBQ0lCWTBscVFVCRNEQUR3UHcuLpoCiQEhUFE4YUZnNj0BJG5QRmJJQVFvQUQVSFR1UURvSlUwbE9Nem8wTnpRNVFNSVlTEXgMUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPCLZUFBLtgCAOACrZhI6gJaaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkvaW50ZWdyYXRpb25FeGFtcGxlcy9sb25nZm9ybS9iYXNpY193b19yZXF1aXJlRXhhY3REdXJhdGlvbi5odG1s8gITCg9DVVNUT01fTU9ERUxfSUQSAPICGgoWQ1VTVE9NX00FFjxMRUFGX05BTUUSAPICHgoaMjMA8MJMQVNUX01PRElGSUVEEgCAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA0yMDIuNTkuMjMxLjQ3qATV5gSyBBIIARACGIAFIOADKAEoAjAAOAO4BADABADIBADSBA45MzI1I1NJTjM6NDc0OdoEAggB4AQA8ATE559HiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAAABlzmzYBQHgBQHwBZk9-gUECAAQAJAGAZgGALgGAMEGBSEsAPA_0Ab1L9oGFgoQCREZAVAQABgA4AYE8gYCCACABwGIBwCgB0A.&s=17c466ea45d5d4beff02aa2b0eb87bc6c4d5aff3" + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/modules/description.md b/test/fake-server/fixtures/modules/description.md new file mode 100644 index 00000000000..db13453b8aa --- /dev/null +++ b/test/fake-server/fixtures/modules/description.md @@ -0,0 +1,68 @@ +Test Pages: + - 'test/pages/bidderSettings.html' + - 'test/pages/consent_mgt_gdpr.html' + - 'test/pages/currency.html' + - 'test/pages/priceGranularity.html' + - 'test/pages/sizeConfig.html' + - 'test/pages/userSync.html' +Test Spec Files: + - 'test/spec/e2e/modules/e2e_bidderSettings.spec.js' + - 'test/spec/e2e/modules/e2e_consent_mgt_gdpr.spec.js' + - 'test/spec/e2e/modules/e2e_currency.spec.js' + - 'test/spec/e2e/modules/e2e_priceGranularity.spec.js' + - 'test/spec/e2e/modules/e2e_sizeConfig.spec.js' + - 'test/spec/e2e/modules/e2e_userSync.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'div-gpt-ad-1460505748561-0', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + // Replace this object to test a new Adapter! + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13144370 + } + }] + +}, { + code: '/19968336/prebid_native_example_2', + sizes: [ + [1, 1] + ], + mediaTypes: { + native: { + title: { + required: true + }, + body: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + }, + icon: { + required: false + }, + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232354, + allowSmallerSizes: true + } + }] +}]; +``` + +Refer to individual test pages to see the proper setConfigs for each test. diff --git a/test/fake-server/fixtures/modules/request.json b/test/fake-server/fixtures/modules/request.json new file mode 100644 index 00000000000..35dd6e2d499 --- /dev/null +++ b/test/fake-server/fixtures/modules/request.json @@ -0,0 +1,74 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 300, + "height": 250 + }, + { + "width": 300, + "height": 600 + } + ], + "primary_size": { + "width": 300, + "height": 250 + }, + "ad_types": [ + "banner" + ], + "id": 13144370, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 1 + }, + { + "sizes": [ + { + "width": 1, + "height": 1 + } + ], + "ad_types": [ + "native" + ], + "id": 13232354, + "allow_smaller_sizes": true, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "native": { + "layouts": [ + { + "title": { + "required": true + }, + "description": { + "required": true + }, + "main_image": { + "required": true + }, + "sponsored_by": { + "required": true + }, + "icon": { + "required": false + } + } + ] + }, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/modules/response.json b/test/fake-server/fixtures/modules/response.json new file mode 100644 index 00000000000..9b708fa1534 --- /dev/null +++ b/test/fake-server/fixtures/modules/response.json @@ -0,0 +1,106 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13144370, + "auction_id": "4842409943576641356", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmodules%2Fcurrency.html%3Fpbjs_debug%3Dtrue&e=wqT_3QK7CKA7BAAAAwDWAAUBCNvV-_AFEMz-0f3_xeyZQxjCs_b6q5D9_0oqNgkAAAkCABEJBywAABkAAACA61HgPyEREgApEQkAMREb8GkwsqKiBjjtSEDtSEgAUABYnPFbYABotc95eACAAQGKAQCSAQNVU0SYAawCoAHYBKgBAbABALgBAcABAMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3OTA4NDUwNyk7AR0scicsIDk4NDkzNTgxNh4A8NCSArUCIVpqeldtZ2l1c0s0S0VJM0oteTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlNSUdhQUJ3RG5qd0U0QUJUSWdCOEJPUUFRQ1lBUUNnQVFHb0FRT3dBUUM1QVNtTGlJTUFBT0Ffd1FFcGk0aURBQURnUDhrQmxiMDhGYV9INERfWkFRQUFBQUFBQVBBXzRBRUE5UUVBQUFBQW1BSUFvQUlBdFFJQUFBQUF2UUlBQUFBQTRBSUE2QUlBLUFJQWdBTUJtQU1CcUFPdQHEiHVnTUpVMGxPTXpvME56TTE0QU80R1lnRUFKQUVBSmdFQWNFCV0FAQhESkIFCAkBGDJBUUE4UVEJDQEBLFBnRUFJZ0ZfeVNwQhEXNFBBX5oCiQEhblE4cUxBNjkBJG5QRmJJQVFvQUQRZBBEZ1B6bzKRABBRTGdaUx1NAFURDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJLDTpIdGVzdC5sb2NhbGhvc3Q6OTk5OQUUWC9wYWdlcy9tb2R1bGVzL2N1cnJlbmN5BUbwQD9wYmpzX2RlYnVnPXRydWWAAwCIAwGQAwCYAxegAwGqAwDAA6wCyAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzDbDwXpgEAKIECzEwLjc1Ljc0LjY5qATikAGyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggA4AQB8ASNyfsuiAUBmAUAoAX_____BQMYAcAFAMkFAAUBFPA_0gUJCQULfAAAANgFAeAFAfAFmfQh-gUECAAQAJAGAJgGALgGAMEGASEwAADwv9AG9S_aBhYKEAkRGQFQEAAYAOAGAfIGAggAgAcBiAcAoAcB&s=16a5ea7c8d5eb050a368495961803753dd6086c2", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "banner", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 98493581, + "media_type_id": 1, + "media_subtype_id": 1, + "cpm": 0.5, + "cpm_publisher_currency": 0.5, + "publisher_currency_code": "$", + "brand_category_id": 53, + "client_initiated_ad_counting": true, + "rtb": { + "banner": { + "content": "
", + "width": 300, + "height": 600 + }, + "trackers": [ + { + "impression_urls": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmodules%2Fcurrency.html%3Fpbjs_debug%3Dtrue&e=wqT_3QLDCKBDBAAAAwDWAAUBCNvV-_AFEMz-0f3_xeyZQxjCs_b6q5D9_0oqNgkAAAECCOA_EQEHNAAA4D8ZAAAAgOtR4D8hERIAKREJADERG6gwsqKiBjjtSEDtSEgCUI3J-y5YnPFbYABotc95eJ64BYABAYoBA1VTRJIBAQbwUpgBrAKgAdgEqAEBsAEAuAEBwAEEyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc5MDg0NTA3KTt1ZigncicsIDk4NDkzNTgxNh4A8NCSArUCIVpqeldtZ2l1c0s0S0VJM0oteTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFzcUtpQmxnQVlNSUdhQUJ3RG5qd0U0QUJUSWdCOEJPUUFRQ1lBUUNnQVFHb0FRT3dBUUM1QVNtTGlJTUFBT0Ffd1FFcGk0aURBQURnUDhrQmxiMDhGYV9INERfWkFRQUFBQUFBQVBBXzRBRUE5UUVBQUFBQW1BSUFvQUlBdFFJQUFBQUF2UUlBQUFBQTRBSUE2QUlBLUFJQWdBTUJtQU1CcUFPdQHEiHVnTUpVMGxPTXpvME56TTE0QU80R1lnRUFKQUVBSmdFQWNFCV0FAQhESkIFCAkBGDJBUUE4UVEJDQEBLFBnRUFJZ0ZfeVNwQhEXNFBBX5oCiQEhblE4cUxBNjkBJG5QRmJJQVFvQUQRZBBEZ1B6bzKRABBRTGdaUx1NAFURDAxBQUFXHQwAWR0MAGEdDABjHQzwQGVBQS7CAi9odHRwOi8vcHJlYmlkLm9yZy9kZXYtZG9jcy9nZXR0aW5nLXN0YXJ0ZWQuaHRtbNgCAOACrZhI6gJLDTpIdGVzdC5sb2NhbGhvc3Q6OTk5OQUUWC9wYWdlcy9tb2R1bGVzL2N1cnJlbmN5BUbwQD9wYmpzX2RlYnVnPXRydWWAAwCIAwGQAwCYAxegAwGqAwDAA6wCyAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzDbDwXpgEAKIECzEwLjc1Ljc0LjY5qATikAGyBBIIBBAEGKwCIPoBKAEoAjAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggB4AQB8ASNyfsuiAUBmAUAoAX_____BQMYAcAFAMkFAAUBFPA_0gUJCQULfAAAANgFAeAFAfAFmfQh-gUECAAQAJAGAJgGALgGAMEGASEwAADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGAfIGAggAgAcBiAcAoAcB&s=9c378bb4ca21a7509f69955fb4e6fe72035190c6" + ], + "video_events": {} + } + ] + } + } + ] + }, + { + "tag_id": 13232354, + "auction_id": "8100967561168057198", + "nobid": false, + "no_ad_url": "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmodules%2Fcurrency.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKECKAEBAAAAwDWAAUBCNvV-_AFEO7mieO34pq2cBjCs_b6q5D9_0oqNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMOLRpwY47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc5MDg0NTA3KTsBHSxyJywgOTc0OTQyMDQ2HgDwmpICtQIhMVR6c3lRajgtTHdLRUx6SnZpNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUTR0R25CbGdBWU1JR2FBQndBSGdBZ0FGTWlBSHdFNUFCQUpnQkFLQUJBYWdCQTdBQkFMa0I4NjFxcEFBQUpFREJBZk90YXFRQUFDUkF5UUc5QzZTMEtFampQOWtCQUFBQUFBQUE4RF9nQVFEMUFRAQ8sQ1lBZ0NnQWdDMUFnBRAAOQkI8EBEZ0FnRG9BZ0Q0QWdDQUF3R1lBd0dvQV96NHZBcTZBd2xUU1U0ek9qUTNNelhnQTdnWmlBUUFrQVFBbUFRQndRUQFNCQEITWtFCQkBARhEWUJBRHhCAQsNASwtQVFBaUFYX0pLa0YNEzxBOEQ4LpoCiQEhZUE4dE1BNjkBJG5QRmJJQVFvQUQVWFhrUURvSlUwbE9Nem8wTnpNMVFMZ1pTUQ1PDFBBX1URDAxBQUFXHQwAWR0MAGEdDABjHQygZUFBLtgCAOACrZhI6gJLaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkFFPDXL3BhZ2VzL21vZHVsZXMvY3VycmVuY3kuaHRtbD9wYmpzX2RlYnVnPXRydWWAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBAsxMC43NS43NC42OagE4pABsgQOCAAQARgAIAAoADAAOAK4BADABADIBADSBA45MzI1I1NJTjM6NDczNdoEAggA4AQB8AS8yb4uiAUBmAUAoAX___________8BwAUAyQUAAAAAAADwP9IFCQkAaVZ0ANgFAeAFAfAFmfQh-gUECAAQAJAGAZgGALgGAMEGCSQo8L_QBvUv2gYWChAJERkBUBAAGADgBgzyBgIIAIAHAYgHAKAHQQ..&s=428486554947609aac96ed5569d9bb2dd2be5502", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "native", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97494204, + "media_type_id": 12, + "media_subtype_id": 65, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 53, + "client_initiated_ad_counting": true, + "viewability": { + "config": "" + }, + "rtb": { + "native": { + "title": "This is a Prebid Native Creative", + "desc": "This is a Prebid Native Creative. There are many like it, but this one is mine.", + "sponsored": "Prebid.org", + "icon": { + "url": "http://vcdn.adnxs.com/p/creative-image/1a/3e/e9/5b/1a3ee95b-06cd-4260-98c7-0258627c9197.png", + "width": 127, + "height": 83, + "prevent_crop": false + }, + "main_img": { + "url": "http://vcdn.adnxs.com/p/creative-image/f8/7f/0f/13/f87f0f13-230c-4f05-8087-db9216e393de.jpg", + "width": 989, + "height": 742, + "prevent_crop": false + }, + "link": { + "url": "http://prebid.org/dev-docs/show-native-ads.html", + "click_trackers": [ + "http://sin3-ib.adnxs.com/click?AAAAAAAAJEAAAAAAAAAkQAAAAAAAACRAAAAAAAAAJEAAAAAAAAAkQG5zYnwTa2xwwpldv4L0_0rb6h5eAAAAAOLoyQBtJAAAbSQAAAIAAAC8pM8FnPgWAAAAAABVU0QAVVNEAAEAAQBNXQAAAAABAQQCAAAAALoAYBc26wAAAAA./bcr=AAAAAAAA8D8=/cnd=%21eA8tMAj8-LwKELzJvi4YnPFbIAQoADEAAAAAAAAkQDoJU0lOMzo0NzM1QLgZSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA./cca=OTMyNSNTSU4zOjQ3MzU=/bn=89118/" + ] + }, + "impression_trackers": [ + "http://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmodules%2Fcurrency.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKMCKAMBAAAAwDWAAUBCNvV-_AFEO7mieO34pq2cBjCs_b6q5D9_0oqNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMOLRpwY47UhA7UhIAlC8yb4uWJzxW2AAaM26dXieuAWAAQGKAQNVU0SSAQEG8FKYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1NzkwODQ1MDcpO3VmKCdyJywgOTc0OTQyMDQsIC4eAPCakgK1AiExVHpzeVFqOC1Md0tFTHpKdmk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRNHRHbkJsZ0FZTUlHYUFCd0FIZ0FnQUZNaUFId0U1QUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRRzlDNlMwS0VqalA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BX3o0dkFxNkF3bFRTVTR6T2pRM016WGdBN2daaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVhfSktrRg0TPEE4RDgumgKJASFlQTh0TUE2OQEkblBGYklBUW9BRBVYWGtRRG9KVTBsT016bzBOek0xUUxnWlNRDU8MUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDKBlQUEu2AIA4AKtmEjqAktodHRwOi8vdGVzdC5sb2NhbGhvc3Q6OTk5OQUU8NcvcGFnZXMvbW9kdWxlcy9jdXJyZW5jeS5odG1sP3BianNfZGVidWc9dHJ1ZYADAIgDAZADAJgDF6ADAaoDAMAD4KgByAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzL3ByZWJpZJgEAKIECzEwLjc1Ljc0LjY5qATikAGyBA4IABABGAAgACgAMAA4ArgEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM12gQCCAHgBAHwBLzJvi6IBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQBpXnQA2AUB4AUB8AWZ9CH6BQQIABAAkAYBmAYAuAYAwQYJJCjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGDPIGAggAgAcBiAcAoAdB&s=d6c58ebc137658c5dd258579c2575ad499e7a7b4" + ], + "id": 97494204 + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/description.md b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/description.md new file mode 100644 index 00000000000..c5b114e8bb3 --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/description.md @@ -0,0 +1,43 @@ +Test Page - 'test/pages/multiple_bidders.html' +Test Spec File - 'test/spec/e2e/multi-bidder/e2e_multiple_bidders.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'div-banner-native-1', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232392, + } + }] +}, +{ + code: 'div-banner-native-2', + mediaTypes: { + native: { + title: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + } + } + }, + bids: [{ + bidder: 'adasta', + params: { + placementId: 13232392, + } + }] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/request.json b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/request.json new file mode 100644 index 00000000000..c4c862adc20 --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/request.json @@ -0,0 +1,43 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 1, + "height": 1 + } + ], + "ad_types": [ + "native" + ], + "id": 13232392, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "native": { + "layouts": [ + { + "title": { + "required": true + }, + "main_image": { + "required": true + }, + "sponsored_by": { + "required": true + } + } + ] + }, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/response.json b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/response.json new file mode 100644 index 00000000000..56894e97e05 --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-adasta/response.json @@ -0,0 +1,59 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13232392, + "auction_id": "6287559286677633407", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmultiple_bidders.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKICKAIBAAAAwDWAAUBCM3FpfEFEP_yg9W7u_mgVxi7_-bKzp3kuD8qNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQnwaSRAMIjSpwY47UhA7UhIAFAAWJzxW2AAaM26dXgAgAEBigEAkgEDVVNEmAEBoAEBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc5NzcwNTczKTsBHSxyJywgOTc1MjA0MzQ2HgDw0JICtQIhQWp4NUh3aUgtYndLRUxLV3dDNFlBQ0NjOFZzd0FEZ0FRQVJJN1VoUWlOS25CbGdBWUtzR2FBQndBbmlLQVlBQkhvZ0JpZ0dRQVFDWUFRQ2dBUUdvQVFPd0FRQzVBZk90YXFRQUFDUkF3UUh6cldxa0FBQWtRTWtCb2FZc1BwVDM0VF9aQVFBQUFBQUFBUEFfNEFFQTlRRUFBQUFBbUFJQW9BSUF0UUlBQUFBQXZRSUFBQUFBNEFJQTZBSUEtQUlBZ0FNQm1BTUJxQU9IAcSIdWdNSlUwbE9Nem8wT0RRMDRBUDRHWWdFQUpBRUFKZ0VBY0UJXQUBCERKQgUICQEYMkFRQThRUQkNAQEsUGdFQUlnRjdDV3BCERc0UEFfmgKJASFDZy1TX2c2OQEkblBGYklBUW9BRBVkDGtRRG8ykQAQUVBnWlMdTQBVEQwMQUFBVx0MAFkdDABhHQwAYx0MoGVBQS7YAgDgAq2YSOoCS2h0dHA6Ly90ZXN0LmxvY2FsaG9zdDo5OTk5BRTw3i9wYWdlcy9tdWx0aXBsZV9iaWRkZXJzLmh0bWw_cGJqc19kZWJ1Zz10cnVlgAMAiAMBkAMAmAMXoAMBqgMAwAPgqAHIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMvcHJlYmlkmAQAogQOMTAzLjc5LjEwMC4xODCoBOZCsgQQCAQQARgAIAAoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0ODQ02gQCCADgBAHwBLKWwC6IBQGYBQCgBf___________wHABQDJBQAAAAAAAPA_0gUJCQAAAAABDnDYBQHgBQHwBZn0IfoFBAgAEACQBgGYBgC4BgDBBgEhMAAA8L_QBvUv2gYWChAJERkBUBAAGADgBgzyBgIIAIAHAYgHAKAHQQ..&s=8b14b952b73092945ef66436be991786b53f7a68", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "native", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 97520434, + "media_type_id": 12, + "media_subtype_id": 65, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 53, + "client_initiated_ad_counting": true, + "viewability": { + "config": "" + }, + "rtb": { + "native": { + "title": "This is a Prebid Native Creative", + "sponsored": "Prebid.org", + "main_img": { + "url": "https://vcdn.adnxs.com/p/creative-image/f8/7f/0f/13/f87f0f13-230c-4f05-8087-db9216e393de.jpg", + "width": 989, + "height": 742, + "prevent_crop": false + }, + "link": { + "url": "http://prebid.org/dev-docs/show-multi-format-ads.html", + "click_trackers": [ + "https://sin3-ib.adnxs.com/click?AAAAAAAAJEAAAAAAAAAkQAAAAAAAACRAAAAAAAAAJEAAAAAAAAAkQH_5oLrb5UFXu79Z6eyQcT_NYileAAAAAAjpyQBtJAAAbSQAAAIAAAAyC9AFnPgWAAAAAABVU0QAVVNEAAEAAQBNXQAAAAABAQQCAAAAALoAnRbC8wAAAAA./bcr=AAAAAAAA8D8=/cnd=%21Cg-S_giH-bwKELKWwC4YnPFbIAQoADEAAAAAAAAkQDoJU0lOMzo0ODQ0QPgZSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA./cca=OTMyNSNTSU4zOjQ4NDQ=/bn=89112/" + ] + }, + "impression_trackers": [ + "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmultiple_bidders.html%3Fpbjs_debug%3Dtrue&e=wqT_3QKQCKAQBAAAAwDWAAUBCM3FpfEFEP_yg9W7u_mgVxi7_-bKzp3kuD8qNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIjSpwY47UhA7UhIAlCylsAuWJzxW2AAaM26dXiYuAWAAQGKAQNVU0SSAQEG8FKYAQGgAQGoAQGwAQC4AQHAAQTIAQLQAQDYAQDgAQDwAQCKAjt1ZignYScsIDI1Mjk4ODUsIDE1Nzk3NzA1NzMpO3VmKCdyJywgOTc1MjA0MzQsIC4eAPDQkgK1AiFBang1SHdpSC1id0tFTEtXd0M0WUFDQ2M4VnN3QURnQVFBUkk3VWhRaU5LbkJsZ0FZS3NHYUFCd0FuaUtBWUFCSG9nQmlnR1FBUUNZQVFDZ0FRR29BUU93QVFDNUFmT3RhcVFBQUNSQXdRSHpyV3FrQUFBa1FNa0JvYVlzUHBUMzRUX1pBUUFBQUFBQUFQQV80QUVBOVFFQUFBQUFtQUlBb0FJQXRRSUFBQUFBdlFJQUFBQUE0QUlBNkFJQS1BSUFnQU1CbUFNQnFBT0gBxIh1Z01KVTBsT016bzBPRFEwNEFQNEdZZ0VBSkFFQUpnRUFjRQldBQEIREpCBQgJARgyQVFBOFFRCQ0BASxQZ0VBSWdGN0NXcEIRFzRQQV-aAokBIUNnLVNfZzY5ASRuUEZiSUFRb0FEFWQMa1FEbzKRABBRUGdaUx1NAFURDAxBQUFXHQwAWR0MAGEdDABjHQygZUFBLtgCAOACrZhI6gJLaHR0cDovL3Rlc3QubG9jYWxob3N0Ojk5OTkFFPDeL3BhZ2VzL211bHRpcGxlX2JpZGRlcnMuaHRtbD9wYmpzX2RlYnVnPXRydWWAAwCIAwGQAwCYAxegAwGqAwDAA-CoAcgDANgDAOADAOgDAPgDAYAEAJIEDS91dC92My9wcmViaWSYBACiBA4xMDMuNzkuMTAwLjE4MKgE5kKyBBAIBBABGAAgACgBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ4NDTaBAIIAeAEAfAEspbALogFAZgFAKAF____________AcAFAMkFAAAAAAAA8D_SBQkJAAAAAAEOcNgFAeAFAfAFmfQh-gUECAAQAJAGAZgGALgGAMEGASEwAADwP9AG9S_aBhYKEAkRGQFQEAAYAOAGDPIGAggAgAcBiAcAoAdB&s=2061bd85ce022a41bc16ebb20c193aabbbc07809" + ], + "id": 97520434 + } + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/description.md b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/description.md new file mode 100644 index 00000000000..c5b114e8bb3 --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/description.md @@ -0,0 +1,43 @@ +Test Page - 'test/pages/multiple_bidders.html' +Test Spec File - 'test/spec/e2e/multi-bidder/e2e_multiple_bidders.spec.js' + +Ad Unit that generates given 'Request' - 'Response' pairs. + +```(javascript) +[{ + code: 'div-banner-native-1', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bids: [{ + bidder: 'appnexus', + params: { + placementId: 13232392, + } + }] +}, +{ + code: 'div-banner-native-2', + mediaTypes: { + native: { + title: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + } + } + }, + bids: [{ + bidder: 'adasta', + params: { + placementId: 13232392, + } + }] +}]; +``` \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/request.json b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/request.json new file mode 100644 index 00000000000..8399bed631c --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/request.json @@ -0,0 +1,36 @@ +{ + "httpRequest": { + "method": "POST", + "path": "/", + "body": { + "tags": [ + { + "sizes": [ + { + "width": 300, + "height": 250 + }, + { + "width": 300, + "height": 600 + } + ], + "primary_size": { + "width": 300, + "height": 250 + }, + "ad_types": [ + "banner" + ], + "id": 13232392, + "allow_smaller_sizes": false, + "use_pmt_rule": false, + "prebid": true, + "disable_psa": true, + "hb_source": 1 + } + ], + "user": {} + } + } +} \ No newline at end of file diff --git a/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/response.json b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/response.json new file mode 100644 index 00000000000..54ad643b82d --- /dev/null +++ b/test/fake-server/fixtures/multi-bidder/multi-bidder-appnexus/response.json @@ -0,0 +1,49 @@ +{ + "httpResponse": { + "body": { + "version": "3.0.0", + "tags": [ + { + "tag_id": 13232392, + "auction_id": "6917498423334366136", + "nobid": false, + "no_ad_url": "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmultiple_bidders.html%3Fpbjs_debug%3Dtrue&e=wqT_3QLBCKBBBAAAAwDWAAUBCNGcpvEFELjXrYmmhfn_Xxi7_-bKzp3kuD8qNgkAAAkCABEJBwgAABkJCQgkQCEJCQgAACkRCQAxCQn0gQEkQDCI0qcGOO1IQO1ISABQAFic8VtgAGjNunV4AIABAYoBAJIBA1VTRJgBrAKgAfoBqAEBsAEAuAEBwAEAyAEC0AEA2AEA4AEA8AEAigI7dWYoJ2EnLCAyNTI5ODg1LCAxNTc5NzgxNzEzKTt1ZigncicsIDk2ODQ2MDM1LCAxNTc5NzgxNzEzKTuSArUCITZEb2NyZ2lILWJ3S0VOT0JseTRZQUNDYzhWc3dBRGdBUUFSSTdVaFFpTktuQmxnQVlLc0dhQUJ3R25oaWdBR1lBWWdCWXBBQkFKZ0JBS0FCQWFnQkE3QUJBTGtCODYxcXBBQUFKRURCQWZPdGFxUUFBQ1JBeVFHQ1VBT2x6Q0xkUDlrQkFBQUFBQUFBOERfZ0FRRDFBUUFBQUFDWUFnQ2dBZ0MxQWdBQUFBQzlBZ0FBQUFEZ0FnRG9BZ0Q0QWdDQUF3R1lBd0dvQTRmNXZBcTZBd2xUU1U0ek9qUTNNem5nQV9nWmlBUUFrQVFBbUFRQndRUQFNCQEITWtFCQkBARhEWUJBRHhCAQsNASwtQVFBaUFXREpha0YNE0BBOEQ4LpoCiQEhOEE1YjlRaTI5ASRuUEZiSUFRb0FEFVhYa1FEb0pVMGxPTXpvME56TTVRUGdaU1ENTwxQQV9VEQwMQUFBVx0MAFkdDABhHQwAYx0M8EZlQUEuwgI1aHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc2hvdy1tdWx0aS1mb3JtYXQtYWRzLmh0bWzYAgDgAq2YSOoCSw1ASHRlc3QubG9jYWxob3N0Ojk5OTkFFBgvcGFnZXMvBUYocGxlX2JpZGRlcnMFRvBAP3BianNfZGVidWc9dHJ1ZYADAIgDAZADAJgDF6ADAaoDAMADrALIAwDYAwDgAwDoAwD4AwGABACSBA0vdXQvdjMNtvBhmAQAogQOMTAzLjc5LjEwMC4xODCoBJ9EsgQSCAQQARisAiD6ASgBKAIwADgDuAQAwAQAyAQA0gQOOTMyNSNTSU4zOjQ3MznaBAIIAOAEAfAE04GXLogFAZgFAKAF______8BAxQBwAUAyQVpiBTwP9IFCQkJDHAAANgFAeAFAfAFAfoFBAgAEACQBgCYBgC4BgDBBgkjKPC_0Ab1L9oGFgoQCREZAVAQABgA4AYB8gYCCACABwGIBwCgBwE.&s=8d42ac30ca2d2a8a63215f5aba2a43bd23af0023", + "timeout_ms": 0, + "ad_profile_id": 1182765, + "rtb_video_fallback": false, + "ads": [ + { + "content_source": "rtb", + "ad_type": "banner", + "buyer_member_id": 9325, + "advertiser_id": 2529885, + "creative_id": 96846035, + "media_type_id": 1, + "media_subtype_id": 1, + "cpm": 10, + "cpm_publisher_currency": 10, + "publisher_currency_code": "$", + "brand_category_id": 0, + "client_initiated_ad_counting": true, + "rtb": { + "banner": { + "content": "
", + "width": 300, + "height": 250 + }, + "trackers": [ + { + "impression_urls": [ + "https://sin3-ib.adnxs.com/it?an_audit=0&referrer=http%3A%2F%2Ftest.localhost%3A9999%2Ftest%2Fpages%2Fmultiple_bidders.html%3Fpbjs_debug%3Dtrue&e=wqT_3QLJCKBJBAAAAwDWAAUBCNGcpvEFELjXrYmmhfn_Xxi7_-bKzp3kuD8qNgkAAAECCCRAEQEHEAAAJEAZEQkAIREJACkRCQAxEQmoMIjSpwY47UhA7UhIAlDTgZcuWJzxW2AAaM26dXicuAWAAQGKAQNVU0SSAQEG8FKYAawCoAH6AagBAbABALgBAcABBMgBAtABANgBAOABAPABAIoCO3VmKCdhJywgMjUyOTg4NSwgMTU3OTc4MTcxMyk7dWYoJ3InLCA5Njg0NjAzNTYeAPCakgK1AiE2RG9jcmdpSC1id0tFTk9CbHk0WUFDQ2M4VnN3QURnQVFBUkk3VWhRaU5LbkJsZ0FZS3NHYUFCd0duaGlnQUdZQVlnQllwQUJBSmdCQUtBQkFhZ0JBN0FCQUxrQjg2MXFwQUFBSkVEQkFmT3RhcVFBQUNSQXlRR0NVQU9sekNMZFA5a0JBQUFBQUFBQThEX2dBUUQxQVEBDyxDWUFnQ2dBZ0MxQWcFEAA5CQjwQERnQWdEb0FnRDRBZ0NBQXdHWUF3R29BNGY1dkFxNkF3bFRTVTR6T2pRM016bmdBX2daaUFRQWtBUUFtQVFCd1FRAU0JAQhNa0UJCQEBGERZQkFEeEIBCw0BLC1BUUFpQVdESmFrRg0TPEE4RDgumgKJASE4QTViOVE2OQEkblBGYklBUW9BRBVYWGtRRG9KVTBsT016bzBOek01UVBnWlNRDU8MUEFfVREMDEFBQVcdDABZHQwAYR0MAGMdDPBGZUFBLsICNWh0dHA6Ly9wcmViaWQub3JnL2Rldi1kb2NzL3Nob3ctbXVsdGktZm9ybWF0LWFkcy5odG1s2AIA4AKtmEjqAksNQEh0ZXN0LmxvY2FsaG9zdDo5OTk5BRQYL3BhZ2VzLwVGKHBsZV9iaWRkZXJzBUbwQD9wYmpzX2RlYnVnPXRydWWAAwCIAwGQAwCYAxegAwGqAwDAA6wCyAMA2AMA4AMA6AMA-AMBgAQAkgQNL3V0L3YzDbbwYZgEAKIEDjEwMy43OS4xMDAuMTgwqASfRLIEEggEEAEYrAIg-gEoASgCMAA4A7gEAMAEAMgEANIEDjkzMjUjU0lOMzo0NzM52gQCCAHgBAHwBNOBly6IBQGYBQCgBf______AQMUAcAFAMkFaZAU8D_SBQkJCQxwAADYBQHgBQHwBQH6BQQIABAAkAYAmAYAuAYAwQYJIyjwP9AG9S_aBhYKEAkRGQFQEAAYAOAGAfIGAggAgAcBiAcAoAcB&s=6c6fb8a005b60bc5535b528c16ed74cd66c08dd0" + ], + "video_events": {} + } + ] + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/test/fake-server/index.js b/test/fake-server/index.js new file mode 100644 index 00000000000..752648c6746 --- /dev/null +++ b/test/fake-server/index.js @@ -0,0 +1,37 @@ +/* eslint-disable no-console */ + +const express = require('express'); +const morgan = require('morgan'); +const bodyParser = require('body-parser'); +const argv = require('yargs').argv; +const fakeResponder = require('./fake-responder.js'); + +const PORT = argv.port || '3000'; + +// Initialize express app +const app = express(); + +// Middlewares +app.use(bodyParser.urlencoded({ extended: false })); +app.use(bodyParser.json()); +app.use(bodyParser.text({ type: 'text/plain' })); +app.use(morgan('dev')); // used to log incoming requests + +// Allow Cross Origin request from 'test.localhost:9999' +app.use(function(req, res, next) { + res.header('Access-Control-Allow-Origin', req.headers.origin); + res.header('Access-Control-Allow-Credentials', true); + next(); +}); + +app.post('/', fakeResponder, (req, res) => { + res.send(); +}); + +app.use((req, res) => { + res.status(404).send('Not Found'); +}); + +app.listen(PORT, () => { + console.log(`fake-server listening on http://localhost:${PORT}`); +}); diff --git a/test/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 17538c8b33d..00000000000 --- a/test/mock-server/expectations/request-response-pairs/banner/index.js +++ /dev/null @@ -1,96 +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 - }], - '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/index.js b/test/mock-server/index.js deleted file mode 100644 index 30ead952fcc..00000000000 --- a/test/mock-server/index.js +++ /dev/null @@ -1,36 +0,0 @@ -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 6e2d03487cf..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'].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/mocks/adloaderStub.js b/test/mocks/adloaderStub.js index 41e258d902d..b52ca5e9280 100644 --- a/test/mocks/adloaderStub.js +++ b/test/mocks/adloaderStub.js @@ -1,5 +1,5 @@ -import * as adloader from 'src/adloader'; +import * as adloader from 'src/adloader.js'; // this export is for adloader's tests against actual implementation export let loadExternalScript = adloader.loadExternalScript; diff --git a/test/mocks/videoCacheStub.js b/test/mocks/videoCacheStub.js index 39f5d67b6a9..7ce899cae35 100644 --- a/test/mocks/videoCacheStub.js +++ b/test/mocks/videoCacheStub.js @@ -1,4 +1,4 @@ -import * as videoCache from 'src/videoCache'; +import * as videoCache from 'src/videoCache.js'; /** * Function which can be called from unit tests to stub out the video cache. diff --git a/test/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 new file mode 100644 index 00000000000..015ad3ca45f --- /dev/null +++ b/test/pages/bidderSettings.html @@ -0,0 +1,127 @@ + + + + + + + + + + + + + +

Prebid.js Test

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

Prebid.js Test

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

Prebid.js Test

+
Div-1
+
+ +
+ + diff --git a/test/pages/video.html b/test/pages/instream.html similarity index 76% rename from test/pages/video.html rename to test/pages/instream.html index 3fabeb14b94..c1e2358b754 100644 --- a/test/pages/video.html +++ b/test/pages/instream.html @@ -38,7 +38,7 @@ { bidder: 'appnexus', params: { - placementId: '9333431', + placementId: '13232361', video: { skipppable: false, playback_methods: ['auto_play_sound_off'] @@ -49,9 +49,22 @@ }; 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, + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache' + } + }); pbjs.requestBids({ - timeout : 700, bidsBackHandler : function(bids) { var videoUrl = pbjs.adServers.dfp.buildVideoUrl({ adUnit: videoAdUnit, @@ -64,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; } - }; + } + }; @@ -101,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 new file mode 100644 index 00000000000..7eae83f673a --- /dev/null +++ b/test/pages/priceGranularity.html @@ -0,0 +1,133 @@ + + + + + + + + + + + + + +

Prebid.js Test

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

Prebid.js Test

+
Div-1
+
+ +
+ + + \ No newline at end of file diff --git a/test/pages/userSync.html b/test/pages/userSync.html new file mode 100644 index 00000000000..3d848906ae3 --- /dev/null +++ b/test/pages/userSync.html @@ -0,0 +1,123 @@ + + + + + + + + + + + + + +

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 2ede81538c1..4afa430f81e 100644 --- a/test/spec/AnalyticsAdapter_spec.js +++ b/test/spec/AnalyticsAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; -import events from 'src/events'; +import events from 'src/events.js'; import CONSTANTS from 'src/constants.json'; -import { server } from 'test/mocks/xhr'; +import { server } from 'test/mocks/xhr.js'; const REQUEST_BIDS = CONSTANTS.EVENTS.REQUEST_BIDS; const BID_REQUESTED = CONSTANTS.EVENTS.BID_REQUESTED; diff --git a/test/spec/adloader_spec.js b/test/spec/adloader_spec.js index 31ebeb23900..0c46cd2f171 100644 --- a/test/spec/adloader_spec.js +++ b/test/spec/adloader_spec.js @@ -1,5 +1,5 @@ -import * as utils from 'src/utils'; -import * as adLoader from 'test/mocks/adloaderStub'; +import * as utils from 'src/utils.js'; +import * as adLoader from 'test/mocks/adloaderStub.js'; describe('adLoader', function () { let utilsinsertElementStub; diff --git a/test/spec/aliasBidder_spec.js b/test/spec/aliasBidder_spec.js index 61a654dcb90..771d7fcdd46 100644 --- a/test/spec/aliasBidder_spec.js +++ b/test/spec/aliasBidder_spec.js @@ -1,4 +1,4 @@ -import { pbjsTestOnly } from 'test/helpers/pbjs-test-only'; +import { pbjsTestOnly } from 'test/helpers/pbjs-test-only.js'; describe('Publisher API _ Alias Bidder', function () { var assert = require('chai').assert; diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index 2693daa62b3..35a29727614 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -1,14 +1,19 @@ -import { getKeyValueTargetingPairs, auctionCallbacks, AUCTION_COMPLETED } from 'src/auction'; +import { + getKeyValueTargetingPairs, + auctionCallbacks, + AUCTION_COMPLETED, + adjustBids, + getMediaTypeGranularity, +} from 'src/auction.js'; import CONSTANTS from 'src/constants.json'; -import { adjustBids, getMediaTypeGranularity } from 'src/auction'; -import * as auctionModule from 'src/auction'; -import { registerBidder } from 'src/adapters/bidderFactory'; -import { createBid } from 'src/bidfactory'; -import { config } from 'src/config'; -import * as store from 'src/videoCache'; -import * as ajaxLib from 'src/ajax'; -import find from 'core-js/library/fn/array/find'; -import { server } from 'test/mocks/xhr'; +import * as auctionModule from 'src/auction.js'; +import { registerBidder } from 'src/adapters/bidderFactory.js'; +import { createBid } from 'src/bidfactory.js'; +import { config } from 'src/config.js'; +import * as store from 'src/videoCache.js'; +import * as ajaxLib from 'src/ajax.js'; +import find from 'core-js-pure/features/array/find.js'; +import { server } from 'test/mocks/xhr.js'; var assert = require('assert'); @@ -982,6 +987,103 @@ describe('auctionmanager.js', function () { }); }); + describe('addBidRequests', function () { + let createAuctionStub; + let adUnits; + let adUnitCodes; + let spec; + let spec1; + let auction; + let ajaxStub; + let logMessageStub; + let logInfoStub; + let logWarnStub; + let logErrorStub; + + let bids = TEST_BIDS; + let bids1 = [mockBid({ bidderCode: BIDDER_CODE1 })]; + + before(function () { + logMessageStub = sinon.stub(utils, 'logMessage'); + logInfoStub = sinon.stub(utils, 'logInfo'); + logWarnStub = sinon.stub(utils, 'logWarn'); + logErrorStub = sinon.stub(utils, 'logError'); + let bidRequests = [ + mockBidRequest(bids[0]), + mockBidRequest(bids1[0], { adUnitCode: ADUNIT_CODE1 }) + ]; + let makeRequestsStub = sinon.stub(adapterManager, 'makeBidRequests'); + makeRequestsStub.returns(bidRequests); + + ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockAjaxBuilder); + }); + + after(function () { + logMessageStub.restore(); + logInfoStub.restore(); + logWarnStub.restore(); + logErrorStub.restore(); + ajaxStub.restore(); + adapterManager.makeBidRequests.restore(); + }); + + beforeEach(function () { + config.setConfig({ + debugging: { + enabled: true, + bidRequests: [{ + bidderCode: BIDDER_CODE, + adUnitCode: ADUNIT_CODE, + storedAuctionResponse: '11111' + }] + } + }); + + adUnits = [{ + code: ADUNIT_CODE, + bids: [ + {bidder: BIDDER_CODE, params: {placementId: 'id'}}, + ] + }, { + code: ADUNIT_CODE1, + bids: [ + {bidder: BIDDER_CODE1, params: {placementId: 'id'}}, + ] + }]; + adUnitCodes = adUnits.map(({ code }) => code); + auction = auctionModule.newAuction({adUnits, adUnitCodes, callback: function() {}, cbTimeout: 3000}); + createAuctionStub = sinon.stub(auctionModule, 'newAuction'); + createAuctionStub.returns(auction); + + spec = mockBidder(BIDDER_CODE, bids); + spec1 = mockBidder(BIDDER_CODE1, bids1); + + registerBidder(spec); + registerBidder(spec1); + }); + + afterEach(function () { + logMessageStub.resetHistory(); + logInfoStub.resetHistory(); + logWarnStub.resetHistory(); + logErrorStub.resetHistory(); + auctionModule.newAuction.restore(); + config.resetConfig(); + }); + + it('should override bidRequest properties when config debugging has a matching bidRequest defined', function () { + auction.callBids(); + const auctionBidRequests = auction.getBidRequests(); + assert.equal(auctionBidRequests.length > 0, true); + assert.equal(Array.isArray(auctionBidRequests[0].bids), true); + + const bid = find(auctionBidRequests[0].bids, bid => bid.adUnitCode === ADUNIT_CODE); + assert.equal(typeof bid !== 'undefined', true); + assert.equal(bid.hasOwnProperty('storedAuctionResponse'), true); + assert.equal(bid.storedAuctionResponse, '11111'); + }); + }); + describe('getMediaTypeGranularity', function () { it('video', function () { let bidReq = { diff --git a/test/spec/config_spec.js b/test/spec/config_spec.js index 990add9b134..be5b4bbb78b 100644 --- a/test/spec/config_spec.js +++ b/test/spec/config_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; import { assert } from 'chai'; -import { newConfig } from 'src/config'; +import { newConfig } from 'src/config.js'; const utils = require('src/utils'); @@ -33,7 +33,7 @@ describe('config API', function () { expect(getConfig()).to.be.a('object'); }); - it('sets and gets arbitrary configuarion properties', function () { + it('sets and gets arbitrary configuration properties', function () { setConfig({ baz: 'qux' }); expect(getConfig('baz')).to.equal('qux'); }); @@ -178,6 +178,23 @@ describe('config API', function () { expect(getConfig('customPriceBucket')).to.equal(goodConfig); }); + it('sets deviceAccess', function () { + // When the deviceAccess flag config option is not set, cookies may be read and set + expect(getConfig('deviceAccess')).to.be.equal(true); + + // When the deviceAccess flag config option is set to false, no cookies are read or set + setConfig({ + 'deviceAccess': false + }); + expect(getConfig('deviceAccess')).to.be.equal(false); + + // When the deviceAccess flag config option is set to true, cookies may be read and set + setConfig({ + 'deviceAccess': true + }); + expect(getConfig('deviceAccess')).to.be.equal(true); + }); + it('should log error for invalid priceGranularity', function () { setConfig({ priceGranularity: '' }); const error = 'Prebid Error: no value passed to `setPriceGranularity()`'; diff --git a/test/spec/cpmBucketManager_spec.js b/test/spec/cpmBucketManager_spec.js index 0d83687bf2e..0b8635a4e3b 100644 --- a/test/spec/cpmBucketManager_spec.js +++ b/test/spec/cpmBucketManager_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import {getPriceBucketString, isValidPriceConfig} from 'src/cpmBucketManager'; +import {getPriceBucketString, isValidPriceConfig} from 'src/cpmBucketManager.js'; let cpmFixtures = require('test/fixtures/cpmInputsOutputs.json'); describe('cpmBucketManager', function () { diff --git a/test/spec/debugging_spec.js b/test/spec/debugging_spec.js index ba9702b0324..bf49a579cbd 100644 --- a/test/spec/debugging_spec.js +++ b/test/spec/debugging_spec.js @@ -1,8 +1,8 @@ import { expect } from 'chai'; -import { sessionLoader, addBidResponseHook, getConfig, disableOverrides, boundHook } from 'src/debugging'; -import { addBidResponse } from 'src/auction'; -import { config } from 'src/config'; +import { sessionLoader, addBidResponseHook, addBidderRequestsHook, getConfig, disableOverrides, addBidResponseBound, addBidderRequestsBound } from 'src/debugging.js'; +import { addBidResponse, addBidderRequests } from 'src/auction.js'; +import { config } from 'src/config.js'; describe('bid overrides', function () { let sandbox; @@ -31,14 +31,16 @@ describe('bid overrides', function () { enabled: true }); - expect(addBidResponse.getHooks().some(hook => hook.hook === boundHook)).to.equal(true); + expect(addBidResponse.getHooks().some(hook => hook.hook === addBidResponseBound)).to.equal(true); + expect(addBidderRequests.getHooks().some(hook => hook.hook === addBidderRequestsBound)).to.equal(true); }); it('should happen when configuration found in sessionStorage', function () { sessionLoader({ getItem: () => ('{"enabled": true}') }); - expect(addBidResponse.getHooks().some(hook => hook.hook === boundHook)).to.equal(true); + expect(addBidResponse.getHooks().some(hook => hook.hook === addBidResponseBound)).to.equal(true); + expect(addBidderRequests.getHooks().some(hook => hook.hook === addBidderRequestsBound)).to.equal(true); }); it('should not throw if sessionStorage is inaccessible', function () { @@ -52,7 +54,7 @@ describe('bid overrides', function () { }); }); - describe('hook', function () { + describe('bidResponse hook', function () { let mockBids; let bids; @@ -84,7 +86,7 @@ describe('bid overrides', function () { let next = (adUnitCode, bid) => { bids.push(bid); }; - addBidResponseHook.bind(overrides)(next, bid.adUnitCode, bid) + addBidResponseHook.bind(overrides)(next, bid.adUnitCode, bid); }); } @@ -141,4 +143,51 @@ describe('bid overrides', function () { expect(bids[1].cpm).to.equal(2); }); }); + + describe('bidRequests hook', function () { + let mockBidRequests; + let bidderRequests; + + beforeEach(function () { + let baseBidderRequest = { + 'bidderCode': 'rubicon', + 'bids': [{ + 'width': 970, + 'height': 250, + 'statusMessage': 'Bid available', + 'mediaType': 'banner', + 'source': 'client', + 'currency': 'USD', + 'cpm': 0.5, + 'ttl': 300, + 'netRevenue': false, + 'adUnitCode': '/19968336/header-bid-tag-0' + }] + }; + mockBidRequests = []; + mockBidRequests.push(baseBidderRequest); + mockBidRequests.push(Object.assign({}, baseBidderRequest, { + bidderCode: 'appnexus' + })); + + bidderRequests = []; + }); + + function run(overrides) { + let next = (b) => { + bidderRequests = b; + }; + addBidderRequestsHook.bind(overrides)(next, mockBidRequests); + } + + it('should allow us to exclude bidders', function () { + run({ + enabled: true, + bidders: ['appnexus'] + }); + + expect(bidderRequests.length).to.equal(1); + expect(bidderRequests[0].bidderCode).to.equal('appnexus'); + }); + }); }); 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 new file mode 100644 index 00000000000..b712f90bf63 --- /dev/null +++ b/test/spec/e2e/instream/basic_instream_video_ad.spec.js @@ -0,0 +1,48 @@ +const expect = require('chai').expect; +const { host, protocol, waitForElement } = require('../../../helpers/testing-utils'); + +const TEST_PAGE_URL = `${protocol}://${host}:9999/test/pages/instream.html?pbjs_debug=true`; +const ALERT_BOX_CSS_SELECTOR = 'div[id="event-window"] > p[id="statusText"]'; + +const EXPECTED_TARGETING_KEYS = { + hb_format: 'video', + hb_source: 'client', + hb_size: '640x480', + hb_pb: '10.00', + hb_bidder: 'appnexus', + hb_format_appnexus: 'video', + hb_source_appnexus: 'client', + hb_size_appnexus: '640x480', + hb_pb_appnexus: '10.00', + hb_bidder_appnexus: 'appnexus' +}; + +describe('Prebid.js Instream Video Ad Test', function () { + this.retries(3); + before(function loadTestPage() { + browser.url(TEST_PAGE_URL); + browser.pause(5000); + try { + 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 + loadTestPage(); + } + }); + + it('should load the targeting keys with correct values', function () { + const result = browser.execute(function () { + return window.top.pbjs.getAdserverTargeting('video1'); + }); + + 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 06413fb809a..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/library/fn/array/includes'); +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 82310738246..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/library/fn/array/includes'); +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 696b7fa3359..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/library/fn/array/includes'); +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 224ff1cbc34..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/library/fn/array/includes'); +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 95237366d0e..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/library/fn/array/includes'); +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 6b628067138..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/library/fn/array/includes'); +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 new file mode 100644 index 00000000000..2c0ba484654 --- /dev/null +++ b/test/spec/e2e/modules/e2e_bidderSettings.spec.js @@ -0,0 +1,61 @@ +const expect = require('chai').expect; +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"]'; + +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 Bidder Settings Ad Unit Test', function () { + this.retries(3); + before(function loadTestPage() { + browser.url(TEST_PAGE_URL); + browser.pause(3000); + try { + 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 + loadTestPage(); + } + }); + + it('should load the targeting keys with correct values', function () { + const result = browser.execute(function () { + return window.pbjs.getAdserverTargeting('/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'); + 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 () { + 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 new file mode 100644 index 00000000000..4e0e7da49ea --- /dev/null +++ b/test/spec/e2e/modules/e2e_consent_mgt_gdpr.spec.js @@ -0,0 +1,61 @@ +const expect = require('chai').expect; +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"]'; + +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 GDPR Ad Unit Test', function () { + this.retries(3); + before(function loadTestPage() { + browser.url(TEST_PAGE_URL); + browser.pause(3000); + try { + 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 + loadTestPage(); + } + }); + + it('should load the targeting keys with correct values', function () { + const result = browser.execute(function () { + return window.pbjs.getAdserverTargeting('/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'); + 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 () { + 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 new file mode 100644 index 00000000000..8d8da5c5d45 --- /dev/null +++ b/test/spec/e2e/modules/e2e_currency.spec.js @@ -0,0 +1,61 @@ +const expect = require('chai').expect; +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"]'; + +const EXPECTED_TARGETING_KEYS = { + hb_source: 'client', + hb_source_appnexus: 'client', + 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_native_brand_appn: 'Prebid.org', + hb_bidder: 'appnexus', + hb_format_appnexus: 'native', + hb_size_appnexus: '0x0' +} + +describe('Prebid.js Currency Ad Unit Test', function () { + this.retries(3); + before(function loadTestPage() { + browser.url(TEST_PAGE_URL); + browser.pause(5000); + try { + 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 + loadTestPage(); + } + }); + + it('should load the targeting keys with correct values', function () { + const result = browser.execute(function () { + return window.pbjs.getAdserverTargeting('/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'); + 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 () { + 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 new file mode 100644 index 00000000000..157961d69ea --- /dev/null +++ b/test/spec/e2e/modules/e2e_priceGranularity.spec.js @@ -0,0 +1,61 @@ +const expect = require('chai').expect; +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"]'; + +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 Price Granularity Ad Unit Test', function () { + this.retries(3); + before(function loadTestPage() { + browser.url(TEST_PAGE_URL); + browser.pause(3000); + try { + 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 + loadTestPage(); + } + }); + + it('should load the targeting keys with correct values', function () { + const result = browser.execute(function () { + return window.pbjs.getAdserverTargeting('/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'); + 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 () { + 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 new file mode 100644 index 00000000000..a37e6d49122 --- /dev/null +++ b/test/spec/e2e/modules/e2e_sizeConfig.spec.js @@ -0,0 +1,61 @@ +const expect = require('chai').expect; +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"]'; + +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 Size Config Ad Unit Test', function () { + this.retries(3); + before(function loadTestPage() { + browser.url(TEST_PAGE_URL); + browser.pause(3000); + try { + 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 + loadTestPage(); + } + }); + + it('should load the targeting keys with correct values', function () { + const result = browser.execute(function () { + return window.pbjs.getAdserverTargeting('/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'); + 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 () { + 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 new file mode 100644 index 00000000000..d945bfd3278 --- /dev/null +++ b/test/spec/e2e/modules/e2e_userSync.spec.js @@ -0,0 +1,61 @@ +const expect = require('chai').expect; +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"]'; + +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 User Sync Ad Unit Test', function () { + this.retries(3); + before(function loadTestPage() { + browser.url(TEST_PAGE_URL); + browser.pause(3000); + try { + 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 + loadTestPage(); + } + }); + + it('should load the targeting keys with correct values', function () { + const result = browser.execute(function () { + return window.pbjs.getAdserverTargeting('/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'); + 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 () { + 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/native/basic_native_ad.spec.js b/test/spec/e2e/native/basic_native_ad.spec.js index ed09228b532..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 @@ -40,7 +42,7 @@ describe('Prebid.js Native Ad Unit Test', function () { 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/fixtures.js b/test/spec/integration/faker/fixtures.js index 643b531ad42..a11bd126d61 100644 --- a/test/spec/integration/faker/fixtures.js +++ b/test/spec/integration/faker/fixtures.js @@ -1,5 +1,5 @@ import faker from 'faker'; -import { makeSlot } from './googletag'; +import { makeSlot } from './googletag.js'; export function makeAdSlot(overrides = {}) { return Object.assign(makeSlot( diff --git a/test/spec/integration/faker/googletag.js b/test/spec/integration/faker/googletag.js index b043b5321cb..a0ce04402f7 100644 --- a/test/spec/integration/faker/googletag.js +++ b/test/spec/integration/faker/googletag.js @@ -1,5 +1,5 @@ import faker from 'faker'; -import { randomFive } from './fixtures'; +import { randomFive } from './fixtures.js'; var Slot = function Slot({ code, divId }) { code = code || `ad-slot-code-${randomFive()}`; diff --git a/test/spec/modules/1ad4goodBidAdapter_spec.js b/test/spec/modules/1ad4goodBidAdapter_spec.js index 316a5c13233..b9cd86a4cf7 100644 --- a/test/spec/modules/1ad4goodBidAdapter_spec.js +++ b/test/spec/modules/1ad4goodBidAdapter_spec.js @@ -1,9 +1,9 @@ import { expect } from 'chai'; -import { spec } from 'modules/1ad4goodBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; -import * as bidderFactory from 'src/adapters/bidderFactory'; -import { deepClone } from 'src/utils'; -import { config } from 'src/config'; +import { spec } from 'modules/1ad4goodBidAdapter.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://hb.1ad4good.org/prebid'; diff --git a/test/spec/modules/33acrossBidAdapter_spec.js b/test/spec/modules/33acrossBidAdapter_spec.js index b18181eae40..3721cef18d9 100644 --- a/test/spec/modules/33acrossBidAdapter_spec.js +++ b/test/spec/modules/33acrossBidAdapter_spec.js @@ -1,9 +1,9 @@ import { expect } from 'chai'; -import * as utils from 'src/utils'; -import { config } from 'src/config'; +import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; -import { spec } from 'modules/33acrossBidAdapter'; +import { spec } from 'modules/33acrossBidAdapter.js'; describe('33acrossBidAdapter:', function () { const BIDDER_CODE = '33across'; @@ -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: { @@ -75,7 +74,7 @@ describe('33acrossBidAdapter:', function () { return this; }; - this.withViewabiliuty = viewability => { + this.withViewability = viewability => { Object.assign(ttxRequest.imp[0].banner, { ext: { ttx: { viewability } @@ -92,17 +91,71 @@ 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; }; + this.withPageUrl = pageUrl => { + Object.assign(ttxRequest.site, { + page: pageUrl + }); + + 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; } @@ -267,7 +320,7 @@ describe('33acrossBidAdapter:', function () { context('when element is fully in view', function() { it('returns 100', function() { const ttxRequest = new TtxRequestBuilder() - .withViewabiliuty({amount: 100}) + .withViewability({amount: 100}) .build(); const serverRequest = new ServerRequestBuilder() .withData(ttxRequest) @@ -282,7 +335,7 @@ describe('33acrossBidAdapter:', function () { context('when element is out of view', function() { it('returns 0', function() { const ttxRequest = new TtxRequestBuilder() - .withViewabiliuty({amount: 0}) + .withViewability({amount: 0}) .build(); const serverRequest = new ServerRequestBuilder() .withData(ttxRequest) @@ -297,7 +350,7 @@ describe('33acrossBidAdapter:', function () { context('when element is partially in view', function() { it('returns percentage', function() { const ttxRequest = new TtxRequestBuilder() - .withViewabiliuty({amount: 75}) + .withViewability({amount: 75}) .build(); const serverRequest = new ServerRequestBuilder() .withData(ttxRequest) @@ -312,8 +365,8 @@ 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: {} }]) - .withViewabiliuty({amount: 25}) + .withSizes([{ w: 800, h: 2400 }]) + .withViewability({amount: 25}) .build(); const serverRequest = new ServerRequestBuilder() .withData(ttxRequest) @@ -329,7 +382,7 @@ describe('33acrossBidAdapter:', function () { context('when nested iframes', function() { it('returns \'nm\'', function() { const ttxRequest = new TtxRequestBuilder() - .withViewabiliuty({amount: spec.NON_MEASURABLE}) + .withViewability({amount: spec.NON_MEASURABLE}) .build(); const serverRequest = new ServerRequestBuilder() .withData(ttxRequest) @@ -349,7 +402,7 @@ describe('33acrossBidAdapter:', function () { context('when tab is inactive', function() { it('returns 0', function() { const ttxRequest = new TtxRequestBuilder() - .withViewabiliuty({amount: 0}) + .withViewability({amount: 0}) .build(); const serverRequest = new ServerRequestBuilder() .withData(ttxRequest) @@ -445,6 +498,242 @@ describe('33acrossBidAdapter:', function () { expect(builtServerRequests).to.deep.equal([serverRequest]); }); }); + + 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 = { + refererInfo: { + referer: 'http://foo.com/bar' + } + }; + + const ttxRequest = new TtxRequestBuilder() + .withPageUrl('http://foo.com/bar') + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + + const builtServerRequests = spec.buildRequests(bidRequests, bidderRequest); + + expect(builtServerRequests).to.deep.equal([serverRequest]); + }); + }); + + context('when referer value is not available', function() { + it('returns corresponding server requests without site.page set', function() { + const bidderRequest = { + refererInfo: {} + }; + + const ttxRequest = new TtxRequestBuilder() + .build(); + const serverRequest = new ServerRequestBuilder() + .withData(ttxRequest) + .build(); + + const builtServerRequests = spec.buildRequests(bidRequests, bidderRequest); + + 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() { @@ -646,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` } ] @@ -666,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` } ]; @@ -686,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` } ]; @@ -706,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); @@ -725,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); @@ -744,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&gdpr=0` + 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=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/7xbidBidAdapter_spec.js b/test/spec/modules/7xbidBidAdapter_spec.js new file mode 100644 index 00000000000..bed2c604349 --- /dev/null +++ b/test/spec/modules/7xbidBidAdapter_spec.js @@ -0,0 +1,160 @@ +import {expect} from 'chai'; +import {spec, _getUrlVars} from 'modules/7xbidBidAdapter.js'; +import * as utils from 'src/utils.js'; + +const BASE_URI = '//bidder.7xbid.com/api/v1/prebid/banner' +const NATIVE_BASE_URI = '//bidder.7xbid.com/api/v1/prebid/native' + +describe('7xbid adapter', function() { + let bidRequests; + let nativeBidRequests; + + beforeEach(function() { + bidRequests = [ + { + bidder: '7xbid', + params: { + placementId: 1425292, + currency: 'USD' + } + } + ] + + nativeBidRequests = [ + { + bidder: '7xbid', + params: { + placementId: 1429695, + currency: 'USD' + }, + nativeParams: { + title: { + required: true, + len: 80 + }, + image: { + required: true, + sizes: [150, 50] + }, + sponsoredBy: { + required: true + } + } + } + ] + }) + describe('isBidRequestValid', function () { + it('valid bid case', function () { + let validBid = { + bidder: '7xbid', + params: { + placementId: 1425292, + currency: 'USD' + } + } + let isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(true); + }); + + it('invalid bid case: placementId is not passed', function() { + let validBid = { + bidder: '7xbid', + params: { + } + } + let isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(false); + }) + + it('invalid bid case: currency is not support', function() { + let validBid = { + bidder: '7xbid', + params: { + placementId: 1108295, + currency: 'AUD' + } + } + let isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(false); + }) + }) + + describe('buildRequests', function () { + it('sends bid request to ENDPOINT via GET', function () { + const request = spec.buildRequests(bidRequests)[0]; + expect(request.url).to.equal(BASE_URI); + expect(request.method).to.equal('GET'); + }); + + it('sends native bid request to ENDPOINT via GET', function () { + const request = spec.buildRequests(nativeBidRequests)[0]; + expect(request.url).to.equal(NATIVE_BASE_URI); + expect(request.method).to.equal('GET'); + }); + + it('buildRequests function should not modify original bidRequests object', function () { + let originalBidRequests = utils.deepClone(bidRequests); + let request = spec.buildRequests(bidRequests); + 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); + expect(nativeBidRequests).to.deep.equal(originalBidRequests); + }); + + it('Request params check', function() { + let request = spec.buildRequests(bidRequests)[0]; + const data = _getUrlVars(request.data) + expect(parseInt(data.placementid)).to.exist.and.to.equal(bidRequests[0].params.placementId); + expect(data.cur).to.exist.and.to.equal(bidRequests[0].params.currency); + }) + + it('Native request params check', function() { + let request = spec.buildRequests(nativeBidRequests)[0]; + const data = _getUrlVars(request.data) + expect(parseInt(data.placementid)).to.exist.and.to.equal(nativeBidRequests[0].params.placementId); + expect(data.cur).to.exist.and.to.equal(nativeBidRequests[0].params.currency); + }) + }) + + describe('interpretResponse', function () { + let response = { + 1425292: + { + 'creativeId': '', + 'cur': 'USD', + 'price': 0.0920, + 'width': 300, + 'height': 250, + 'requestid': '2e42361a6172bf', + 'adm': '' + } + } + + it('should get correct bid response', function () { + let expectedResponse = [ + { + 'requestId': '2e42361a6172bf', + 'cpm': 0.0920, + 'width': 300, + 'height': 250, + 'netRevenue': true, + 'currency': 'USD', + 'creativeId': '', + 'ttl': 700, + 'ad': '' + } + ]; + let request = spec.buildRequests(bidRequests)[0]; + let result = spec.interpretResponse({body: response}, request); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + expect(result[0].cpm).to.not.equal(null); + expect(result[0].creativeId).to.not.equal(null); + expect(result[0].ad).to.not.equal(null); + expect(result[0].currency).to.equal('USD'); + expect(result[0].netRevenue).to.equal(true); + }); + }) +}) diff --git a/test/spec/modules/aardvarkBidAdapter_spec.js b/test/spec/modules/aardvarkBidAdapter_spec.js index b8d147644f9..9671f961407 100644 --- a/test/spec/modules/aardvarkBidAdapter_spec.js +++ b/test/spec/modules/aardvarkBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import * as utils from 'src/utils'; -import { spec, resetUserSync } from 'modules/aardvarkBidAdapter'; +import * as utils from 'src/utils.js'; +import { spec, resetUserSync } from 'modules/aardvarkBidAdapter.js'; describe('aardvarkAdapterTest', function () { describe('forming valid bidRequests', function () { @@ -229,6 +229,54 @@ describe('aardvarkAdapterTest', function () { }); }); + describe('CCPA conformity', function () { + const bidRequests = [{ + bidder: 'aardvark', + params: { + ai: 'xiby', + sc: 'TdAx', + }, + adUnitCode: 'aaa', + transactionId: '1b8389fe-615c-482d-9f1a-177fb8f7d5b0', + sizes: [300, 250], + bidId: '1abgs362e0x48a8', + bidderRequestId: '70deaff71c281d', + auctionId: '5c66da22-426a-4bac-b153-77360bef5337' + }]; + + it('should transmit us_privacy data', function () { + const usp = '1NY-'; + const bidderRequest = { + gdprConsent: { + consentString: 'awefasdfwefasdfasd', + gdprApplies: true + }, + refererInfo: { + referer: 'http://example.com' + }, + uspConsent: usp + }; + const requests = spec.buildRequests(bidRequests, bidderRequest); + expect(requests.length).to.equal(1); + expect(requests[0].data.gdpr).to.equal(true); + expect(requests[0].data.consent).to.equal('awefasdfwefasdfasd'); + expect(requests[0].data.us_privacy).to.equal(usp); + }); + + it('should not send us_privacy', function () { + const bidderRequest = { + refererInfo: { + referer: 'http://example.com' + } + }; + const requests = spec.buildRequests(bidRequests, bidderRequest); + expect(requests.length).to.equal(1); + expect(requests[0].data.gdpr).to.be.undefined; + expect(requests[0].data.consent).to.be.undefined; + expect(requests[0].data.us_privacy).to.be.undefined; + }); + }); + describe('interpretResponse', function () { it('should handle bid responses', function () { const serverResponse = { @@ -343,6 +391,15 @@ describe('aardvarkAdapterTest', function () { expect(syncs[0].type).to.equal('iframe'); expect(syncs[0].url).to.equal('https://sync.rtk.io/cs?g=1&c=BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA'); }); + + it('should produce sync url with ccpa params', function () { + resetUserSync(); + + const syncs = spec.getUserSyncs(syncOptions, null, {}, '1YYN'); + expect(syncs.length).to.equal(1); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.equal('https://sync.rtk.io/cs?us_privacy=1YYN'); + }); }); describe('reading window.top properties', function () { diff --git a/test/spec/modules/ablidaBidAdapter_spec.js b/test/spec/modules/ablidaBidAdapter_spec.js index 8e0424aee23..0238c14fe5c 100644 --- a/test/spec/modules/ablidaBidAdapter_spec.js +++ b/test/spec/modules/ablidaBidAdapter_spec.js @@ -1,6 +1,6 @@ import {assert, expect} from 'chai'; -import {spec} from 'modules/ablidaBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; +import {spec} from 'modules/ablidaBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; const ENDPOINT_URL = 'https://bidder.ablida.net/prebid'; @@ -67,7 +67,8 @@ describe('ablidaBidAdapter', function () { bidId: '2b8c4de0116e54', jaySupported: true, device: 'desktop', - referer: 'www.example.com' + referer: 'www.example.com', + adapterVersion: 2 } }; let serverResponse = { @@ -80,7 +81,8 @@ describe('ablidaBidAdapter', function () { currency: 'EUR', netRevenue: true, ttl: 3000, - ad: '' + ad: '', + nurl: 'https://example.com/some-tracker' }] }; it('should get the correct bid response', function () { @@ -93,10 +95,25 @@ describe('ablidaBidAdapter', function () { currency: 'EUR', netRevenue: true, ttl: 3000, - ad: '' + ad: '', + nurl: 'https://example.com/some-tracker' }]; let result = spec.interpretResponse(serverResponse, bidRequest[0]); expect(Object.keys(result)).to.deep.equal(Object.keys(expectedResponse)); }); }); + + describe('onBidWon', function() { + it('Should not ajax call if bid does not contain nurl', function() { + const result = spec.onBidWon({}); + expect(result).to.equal(false) + }) + + it('Should ajax call if bid nurl', function() { + const result = spec.onBidWon({ + nurl: 'https://example.com/some-tracker' + }); + expect(result).to.equal(true) + }) + }) }); 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/adagioAnalyticsAdapter_spec.js b/test/spec/modules/adagioAnalyticsAdapter_spec.js index e643dd8a1a7..aee85412104 100644 --- a/test/spec/modules/adagioAnalyticsAdapter_spec.js +++ b/test/spec/modules/adagioAnalyticsAdapter_spec.js @@ -1,6 +1,6 @@ -import adagioAnalyticsAdapter from 'modules/adagioAnalyticsAdapter'; +import adagioAnalyticsAdapter from 'modules/adagioAnalyticsAdapter.js'; import { expect } from 'chai'; -import * as utils from 'src/utils'; +import * as utils from 'src/utils.js'; let adapterManager = require('src/adapterManager').default; let events = require('src/events'); diff --git a/test/spec/modules/adagioBidAdapter_spec.js b/test/spec/modules/adagioBidAdapter_spec.js index 3ba1a24eaaf..97265121ce0 100644 --- a/test/spec/modules/adagioBidAdapter_spec.js +++ b/test/spec/modules/adagioBidAdapter_spec.js @@ -1,13 +1,13 @@ import { expect } from 'chai'; -import { getAdagioScript, spec } from 'modules/adagioBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; -import * as utils from 'src/utils'; +import { adagioScriptFromLocalStorageCb, _features, 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.1.0'; + const VERSION = '2.2.2'; beforeEach(function() { localStorage.removeItem('adagioScript'); @@ -51,7 +51,7 @@ describe('adagioAdapter', () => { sandbox.restore(); }); - let bid = { + const bid = { 'bidder': 'adagio', 'params': { organizationId: '0', @@ -67,7 +67,7 @@ describe('adagioAdapter', () => { 'auctionId': 'lel4fhp239i9km', }; - let bidWithMediaTypes = { + const bidWithMediaTypes = { 'bidder': 'adagio', 'params': { organizationId: '0', @@ -108,28 +108,41 @@ describe('adagioAdapter', () => { }); it('should return false when organization params is not passed', () => { - let bidTest = Object.assign({}, bid); + const bidTest = utils.deepClone(bid); delete bidTest.params.organizationId; expect(spec.isBidRequestValid(bidTest)).to.equal(false); }); it('should return false when site params is not passed', () => { - let bidTest = Object.assign({}, bid); + const bidTest = utils.deepClone(bid); delete bidTest.params.site; expect(spec.isBidRequestValid(bidTest)).to.equal(false); }); it('should return false when placement params is not passed', () => { - let bidTest = Object.assign({}, bid); + const bidTest = utils.deepClone(bid); delete bidTest.params.placement; expect(spec.isBidRequestValid(bidTest)).to.equal(false); }); - it('should return false when adUnit element id params is not passed', () => { - let bidTest = Object.assign({}, bid); + it('should add autodetected adUnitElementId and environment params', () => { + const bidTest = utils.deepClone(bid); delete bidTest.params.adUnitElementId; - expect(spec.isBidRequestValid(bidTest)).to.equal(false); - }); + delete bidTest.params.environment; + sandbox.stub(utils, 'getGptSlotInfoForAdUnitCode').returns({divId: 'banner-atf'}); + sandbox.stub(_features, 'getDevice').returns(4); + spec.isBidRequestValid(bidTest) + expect(bidTest.params.adUnitElementId).to.equal('banner-atf'); + expect(bidTest.params.environment).to.equal('mobile'); + }) + + it('should add autodetected tablet environment params', () => { + const bidTest = utils.deepClone(bid); + delete bidTest.params.environment; + sandbox.stub(_features, 'getDevice').returns(5); + spec.isBidRequestValid(bidTest) + expect(bidTest.params.environment).to.equal('tablet'); + }) it('should return false if not in the window.top', () => { sandbox.stub(utils, 'getWindowTop').throws(); @@ -301,7 +314,29 @@ describe('adagioAdapter', () => { 'gdprConsent': { consentString: consentString, gdprApplies: true, - allowAuctionWithoutConsent: true + allowAuctionWithoutConsent: true, + apiVersion: 1, + }, + 'refererInfo': { + 'numIframes': 0, + 'reachedTop': true, + 'referer': 'http://test.io/index.html?pbjs_debug=true' + } + }; + + 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, @@ -380,6 +415,7 @@ describe('adagioAdapter', () => { 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', () => { @@ -432,6 +468,17 @@ describe('adagioAdapter', () => { 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); + }); + + 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); }); it('GDPR consent is not applied', () => { @@ -442,6 +489,18 @@ describe('adagioAdapter', () => { 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('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', () => { @@ -455,6 +514,20 @@ describe('adagioAdapter', () => { 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); }); it('GDPR consent bidderRequest does not have gdprConsent', () => { @@ -479,6 +552,40 @@ describe('adagioAdapter', () => { }); 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 + }] + } + }); + + const requests = spec.buildRequests([bidRequest], bidderRequest); + const request = requests[0]; + + 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('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('interpretResponse', () => { @@ -644,7 +751,7 @@ describe('adagioAdapter', () => { }); }); - describe('getAdagioScript', () => { + describe('adagioScriptFromLocalStorageCb', () => { 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'; @@ -658,7 +765,7 @@ describe('adagioAdapter', () => { utilsMock.expects('logWarn').withExactArgs('No hash found in Adagio script').never(); utilsMock.expects('logWarn').withExactArgs('Invalid Adagio script found').never(); - getAdagioScript(); + adagioScriptFromLocalStorageCb(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)); expect(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)).to.equals('// hash: ' + VALID_HASH + '\n' + VALID_SCRIPT_CONTENT); utilsMock.verify(); @@ -671,7 +778,7 @@ describe('adagioAdapter', () => { utilsMock.expects('logWarn').withExactArgs('No hash found in Adagio script').never(); utilsMock.expects('logWarn').withExactArgs('Invalid Adagio script found').once(); - getAdagioScript(); + adagioScriptFromLocalStorageCb(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)); expect(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)).to.be.null; utilsMock.verify(); @@ -684,7 +791,7 @@ describe('adagioAdapter', () => { utilsMock.expects('logWarn').withExactArgs('No hash found in Adagio script').never(); utilsMock.expects('logWarn').withExactArgs('Invalid Adagio script found').once(); - getAdagioScript(); + adagioScriptFromLocalStorageCb(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)); expect(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)).to.be.null; utilsMock.verify(); @@ -697,7 +804,7 @@ describe('adagioAdapter', () => { utilsMock.expects('logWarn').withExactArgs('No hash found in Adagio script').once(); utilsMock.expects('logWarn').withExactArgs('Invalid Adagio script found').never(); - getAdagioScript(); + adagioScriptFromLocalStorageCb(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)); expect(localStorage.getItem(ADAGIO_LOCALSTORAGE_KEY)).to.be.null; utilsMock.verify(); diff --git a/test/spec/modules/adbutlerBidAdapter_spec.js b/test/spec/modules/adbutlerBidAdapter_spec.js index 4f62d6206b4..a9b56ade79e 100644 --- a/test/spec/modules/adbutlerBidAdapter_spec.js +++ b/test/spec/modules/adbutlerBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from 'modules/adbutlerBidAdapter'; +import {spec} from 'modules/adbutlerBidAdapter.js'; describe('AdButler adapter', function () { let bidRequests; diff --git a/test/spec/modules/adfinityBidAdapter_spec.js b/test/spec/modules/adfinityBidAdapter_spec.js index bc2d806a1c3..479a2303dd5 100644 --- a/test/spec/modules/adfinityBidAdapter_spec.js +++ b/test/spec/modules/adfinityBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from '../../../modules/adfinityBidAdapter'; +import {spec} from '../../../modules/adfinityBidAdapter.js'; describe('AdfinityAdapter', function () { let bid = { diff --git a/test/spec/modules/adformBidAdapter_spec.js b/test/spec/modules/adformBidAdapter_spec.js index bb3e99173f7..360979659de 100644 --- a/test/spec/modules/adformBidAdapter_spec.js +++ b/test/spec/modules/adformBidAdapter_spec.js @@ -1,8 +1,8 @@ import {assert, expect} from 'chai'; -import * as url from 'src/url'; -import {spec} from 'modules/adformBidAdapter'; -import { BANNER, VIDEO } from 'src/mediaTypes'; -import { config } from 'src/config'; +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; @@ -130,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); }); @@ -164,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-'); + }); }); }); @@ -248,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 () { @@ -303,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 b0ce0f59a88..05788183e29 100644 --- a/test/spec/modules/adformOpenRTBBidAdapter_spec.js +++ b/test/spec/modules/adformOpenRTBBidAdapter_spec.js @@ -1,9 +1,9 @@ // jshint esversion: 6, es3: false, node: true import {assert, expect} from 'chai'; -import * as url from 'src/url'; -import {spec} from 'modules/adformOpenRTBBidAdapter'; -import { NATIVE } from 'src/mediaTypes'; -import { config } from 'src/config'; +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; @@ -44,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' } }; @@ -61,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' } @@ -71,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); }); @@ -145,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/adgenerationBidAdapter_spec.js b/test/spec/modules/adgenerationBidAdapter_spec.js index 6483272df21..927e7910723 100644 --- a/test/spec/modules/adgenerationBidAdapter_spec.js +++ b/test/spec/modules/adgenerationBidAdapter_spec.js @@ -1,8 +1,8 @@ import {expect} from 'chai'; -import {spec} from 'modules/adgenerationBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; -import {NATIVE} from 'src/mediaTypes'; -import {config} from 'src/config'; +import {spec} from 'modules/adgenerationBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; +import {NATIVE} from 'src/mediaTypes.js'; +import {config} from 'src/config.js'; import prebid from '../../../package.json'; describe('AdgenerationAdapter', function () { diff --git a/test/spec/modules/adglareBidAdapter_spec.js b/test/spec/modules/adglareBidAdapter_spec.js new file mode 100644 index 00000000000..d0dbe891f9d --- /dev/null +++ b/test/spec/modules/adglareBidAdapter_spec.js @@ -0,0 +1,138 @@ +import {expect} from 'chai'; +import {spec} from 'modules/adglareBidAdapter.js'; + +describe('AdGlare Adapter Tests', function () { + let bidRequests; + + beforeEach(function () { + bidRequests = [ + { + bidder: 'adglare', + params: { + domain: 'try.engine.adglare.net', + zID: '475579334', + type: 'banner' + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + }, + }, + bidId: '23acc48ad47af5', + auctionId: '0fb4905b-9456-4152-86be-c6f6d259ba99', + bidderRequestId: '1c56ad30b9b8ca8', + transactionId: '92489f71-1bf2-49a0-adf9-000cea934729' + } + ]; + }); + + describe('implementation', function () { + describe('for requests', function () { + it('should accept valid bid', function () { + let validBid = { + bidder: 'adglare', + params: { + domain: 'try.engine.adglare.net', + zID: '475579334', + type: 'banner' + } + }, + isValid = spec.isBidRequestValid(validBid); + + expect(isValid).to.equal(true); + }); + + it('should reject invalid bid', function () { + let invalidBid = { + bidder: 'adglare', + params: { + domain: 'somedomain.com', + zID: 'not an integer', + type: 'unsupported' + } + }, + isValid = spec.isBidRequestValid(invalidBid); + + expect(isValid).to.equal(false); + }); + + it('should build a valid endpoint URL', function () { + let bidRequests = [ + { + bidder: 'adglare', + params: { + domain: 'try.engine.adglare.net', + zID: '475579334', + type: 'banner' + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + }, + }, + bidId: '23acc48ad47af5', + auctionId: '0fb4905b-9456-4152-86be-c6f6d259ba99', + bidderRequestId: '1c56ad30b9b8ca8', + transactionId: '92489f71-1bf2-49a0-adf9-000cea934729' + } + ], + bidderRequest = { + bidderCode: 'adglare', + auctionID: '0fb4905b-9456-4152-86be-c6f6d259ba99', + bidderRequestId: '1c56ad30b9b8ca8', + auctionStart: 1581497568252, + timeout: 5000, + refererInfo: { + referer: 'https://www.somedomain.com', + reachedTop: true, + numFrames: 0 + }, + start: 1581497568254 + }, + requests = spec.buildRequests(bidRequests, bidderRequest), + requestURL = requests[0].url; + + expect(requestURL).to.have.string('https://try.engine.adglare.net/?475579334'); + }); + }); + + describe('bid responses', function () { + it('should return complete bid response', function () { + let serverResponse = { + body: { + status: 'OK', + zID: 475579334, + cID: 501658124, + crID: 442123173, + cpm: 1.5, + ttl: 3600, + currency: 'USD', + width: 300, + height: 250, + adhtml: 'I am an ad.' + } + }, + bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + + expect(bids).to.be.lengthOf(1); + expect(bids[0].bidderCode).to.equal('adglare'); + expect(bids[0].cpm).to.equal(1.5); + expect(bids[0].width).to.equal(300); + expect(bids[0].height).to.equal(250); + expect(bids[0].currency).to.equal('USD'); + expect(bids[0].netRevenue).to.equal(true); + }); + + it('should return empty bid response', function () { + let serverResponse = { + body: { + status: 'NOADS' + } + }, + bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); + + expect(bids).to.be.lengthOf(0); + }); + }); + }); +}); diff --git a/test/spec/modules/adheseBidAdapter_spec.js b/test/spec/modules/adheseBidAdapter_spec.js index 32658e2bb27..def504b0424 100644 --- a/test/spec/modules/adheseBidAdapter_spec.js +++ b/test/spec/modules/adheseBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from 'modules/adheseBidAdapter'; +import {spec} from 'modules/adheseBidAdapter.js'; const BID_ID = 456; const TTL = 360; @@ -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; }; @@ -100,6 +101,12 @@ describe('AdheseAdapter', function () { expect(req.url).to.contain('/xfaHR0cDovL3ByZWJpZC5vcmcvZGV2LWRvY3Mvc3ViamVjdHM_X2Q9MQ'); }); + it('should include id5 id as /x5 param', function () { + let req = spec.buildRequests([ bidWithParams({}, {'id5id': 'ID5-1234567890'}) ], bidderRequest); + + expect(req.url).to.contain('/x5ID5-1234567890'); + }); + it('should include bids', function () { let bid = minimalBid(); let req = spec.buildRequests([ bid ], bidderRequest); @@ -120,6 +127,7 @@ describe('AdheseAdapter', function () { origin: 'APPNEXUS', originInstance: '', ext: 'js', + slotID: '10', slotName: '_main_page_-leaderboard', adType: 'leaderboard', originData: { @@ -154,13 +162,18 @@ describe('AdheseAdapter', function () { netRevenue: NET_REVENUE, ttl: TTL, adhese: { + origin: 'APPNEXUS', + originInstance: '', originData: { + adType: 'leaderboard', seatbid: [ { bid: [ { crid: '60613369', dealid: null } ], seat: '958' } - ] + ], + slotId: '10', + slotName: '_main_page_-leaderboard' } } }]; @@ -195,7 +208,10 @@ 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); }); @@ -247,14 +263,20 @@ describe('AdheseAdapter', function () { requestId: BID_ID, ad: '', adhese: { + origin: '', + originInstance: '', originData: { adFormat: 'largeleaderboard', + adId: '742898', adType: 'largeleaderboard', adspaceId: '162363', libId: '90511', orderProperty: undefined, priority: undefined, - viewableImpressionCounter: undefined + viewableImpressionCounter: undefined, + slotId: '29306', + slotName: '_main_page_-leaderboard', + advertiserId: '2081' } }, cpm: 5.96, @@ -302,14 +324,20 @@ describe('AdheseAdapter', function () { requestId: BID_ID, vastXml: '', adhese: { + origin: '', + originInstance: '', originData: { adFormat: '', + adId: '742470', adType: 'preroll', adspaceId: '164196', libId: '89860', orderProperty: undefined, priority: undefined, - viewableImpressionCounter: undefined + viewableImpressionCounter: undefined, + slotId: '41711', + slotName: '_main_page_-leaderboard', + advertiserId: '2263', } }, cpm: 0, diff --git a/test/spec/modules/adkernelAdnAnalytics_spec.js b/test/spec/modules/adkernelAdnAnalytics_spec.js index 26fd13afd1f..e7ef831080c 100644 --- a/test/spec/modules/adkernelAdnAnalytics_spec.js +++ b/test/spec/modules/adkernelAdnAnalytics_spec.js @@ -1,6 +1,6 @@ -import analyticsAdapter, {ExpiringQueue, getUmtSource, storage} from 'modules/adkernelAdnAnalyticsAdapter'; +import analyticsAdapter, {ExpiringQueue, getUmtSource, storage} from 'modules/adkernelAdnAnalyticsAdapter.js'; import {expect} from 'chai'; -import adapterManager from 'src/adapterManager'; +import adapterManager from 'src/adapterManager.js'; import CONSTANTS from 'src/constants.json'; const events = require('../../../src/events'); diff --git a/test/spec/modules/adkernelAdnBidAdapter_spec.js b/test/spec/modules/adkernelAdnBidAdapter_spec.js index 98e3f6b3408..3d3e64aeec9 100644 --- a/test/spec/modules/adkernelAdnBidAdapter_spec.js +++ b/test/spec/modules/adkernelAdnBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from 'modules/adkernelAdnBidAdapter'; +import {spec} from 'modules/adkernelAdnBidAdapter.js'; describe('AdkernelAdn adapter', function () { const bid1_pub1 = { @@ -243,17 +243,18 @@ describe('AdkernelAdn adapter', function () { expect(tagRequest).to.not.have.property('user'); }); - it('shouldn\'t contain gdpr-related information for default request', function () { + it('shouldn\'t contain gdpr nor ccpa information for default request', function () { let [_, tagRequests] = buildRequest([bid1_pub1]); expect(tagRequests[0]).to.not.have.property('user'); }); - it('should contain gdpr-related information if consent is configured', function () { + it('should contain gdpr and ccpa information if consent is configured', function () { let [_, bidRequests] = buildRequest([bid1_pub1], - {gdprConsent: {gdprApplies: true, consentString: 'test-consent-string'}}); + {gdprConsent: {gdprApplies: true, consentString: 'test-consent-string'}, uspConsent: '1YNN'}); expect(bidRequests[0]).to.have.property('user'); expect(bidRequests[0].user).to.have.property('gdpr', 1); expect(bidRequests[0].user).to.have.property('consent', 'test-consent-string'); + expect(bidRequests[0].user).to.have.property('us_privacy', '1YNN'); }); it('should\'t contain consent string if gdpr isn\'t applied', function () { diff --git a/test/spec/modules/adkernelBidAdapter_spec.js b/test/spec/modules/adkernelBidAdapter_spec.js index 294aba72a6b..71637781f24 100644 --- a/test/spec/modules/adkernelBidAdapter_spec.js +++ b/test/spec/modules/adkernelBidAdapter_spec.js @@ -1,6 +1,8 @@ import {expect} from 'chai'; -import {spec} from 'modules/adkernelBidAdapter'; -import * as utils from 'src/utils'; +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 = { @@ -105,6 +107,57 @@ describe('Adkernel adapter', function () { bidId: 'Bid_01', bidderRequestId: 'req-001', auctionId: 'auc-001' + }, bid_native = { + bidder: 'adkernel', + params: {zoneId: 1, host: 'rtb.adkernel.com'}, + mediaTypes: { + native: { + title: { + required: true, + len: 80 + }, + body: { + required: true + }, + body2: { + required: true + }, + icon: { + required: true, + aspect_ratios: [{min_width: 50, min_height: 50}] + }, + image: { + required: true, + sizes: [300, 200] + }, + clickUrl: { + required: true + }, + rating: { + required: false + }, + price: { + required: false + }, + privacyLink: { + required: false + }, + cta: { + required: false + }, + sponsoredBy: { + required: false + }, + displayUrl: { + required: false + } + } + }, + adUnitCode: 'ad-unit-1', + transactionId: 'f82c64b8-c602-42a4-9791-4a268f6559ed', + bidId: 'Bid_01', + bidderRequestId: 'req-001', + auctionId: 'auc-001' }; const bidResponse1 = { @@ -123,22 +176,8 @@ describe('Adkernel adapter', function () { }], cur: 'USD', ext: { - adk_usersync: ['https://adk.sync.com/sync'] + adk_usersync: [{type: 1, url: 'https://adk.sync.com/sync'}] } - }, bidResponse2 = { - id: 'bid2', - seatbid: [{ - bid: [{ - id: '2', - impid: 'Bid_02', - crid: '100_002', - price: 1.31, - adm: '', - w: 300, - h: 250 - }] - }], - cur: 'USD' }, videoBidResponse = { id: '47ce4badcf7482', seatbid: [{ @@ -156,12 +195,42 @@ 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', + seatbid: [{ + bid: [{ + id: 'someid_01', + impid: 'Bid_01', + price: 2.25, + adid: '4', + adm: JSON.stringify({ + native: { + assets: [ + {id: 0, title: {text: 'Title'}}, + {id: 3, data: {value: 'Description'}}, + {id: 4, data: {value: 'Additional description'}}, + {id: 1, img: {url: 'http://rtb.com/thumbnail?i=pTuOlf5KHUo_0&imgt=icon', w: 50, h: 50}}, + {id: 2, img: {url: 'http://rtb.com/thumbnail?i=pTuOlf5KHUo_0', w: 300, h: 200}}, + {id: 5, data: {value: 'Sponsor.com'}}, + {id: 14, data: {value: 'displayurl.com'}} + ], + link: {url: 'http://rtb.com/click?i=pTuOlf5KHUo_0'}, + imptrackers: ['http://rtb.com/win?i=pTuOlf5KHUo_0&f=imp'] + } + }), + adomain: ['displayurl.com'], + cid: '1', + crid: '4' + }] + }], + bidid: 'pTuOlf5KHUo', + cur: 'USD' }; 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(); @@ -191,6 +260,10 @@ describe('Adkernel adapter', function () { it('empty request shouldn\'t generate exception', function () { expect(spec.isBidRequestValid(bid_with_wrong_zoneId)).to.be.equal(false); }); + + it('valid native requests should pass', () => { + expect(spec.isBidRequestValid(bid_native)).to.be.equal(true); + }) }); describe('banner request building', function () { @@ -238,7 +311,7 @@ describe('Adkernel adapter', function () { expect(bidRequest.device).to.have.property('dnt', 1); }); - it('shouldn\'t contain gdpr-related information for default request', function () { + it('shouldn\'t contain gdpr nor ccpa information for default request', function () { let [_, bidRequests] = buildRequest([bid1_zone1]); expect(bidRequests[0]).to.not.have.property('regs'); expect(bidRequests[0]).to.not.have.property('user'); @@ -247,10 +320,10 @@ describe('Adkernel adapter', function () { it('should contain gdpr-related information if consent is configured', function () { let [_, bidRequests] = buildRequest([bid1_zone1], buildBidderRequest('https://example.com/index.html', - {gdprConsent: {gdprApplies: true, consentString: 'test-consent-string', vendorData: {}}})); + {gdprConsent: {gdprApplies: true, consentString: 'test-consent-string', vendorData: {}}, uspConsent: '1YNN'})); let bidRequest = bidRequests[0]; expect(bidRequest).to.have.property('regs'); - expect(bidRequest.regs.ext).to.be.eql({'gdpr': 1}); + expect(bidRequest.regs.ext).to.be.eql({'gdpr': 1, 'us_privacy': '1YNN'}); expect(bidRequest).to.have.property('user'); expect(bidRequest.user.ext).to.be.eql({'consent': 'test-consent-string'}); }); @@ -270,7 +343,6 @@ describe('Adkernel adapter', function () { it('should forward default bidder timeout', function() { let [_, bidRequests] = buildRequest([bid1_zone1], DEFAULT_BIDDER_REQUEST); - let bidRequest = bidRequests[0]; expect(bidRequests[0]).to.have.property('tmax', 3000); }); }); @@ -332,6 +404,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]); @@ -343,7 +493,7 @@ describe('Adkernel adapter', function () { expect(resp).to.have.property('creativeId', '100_001'); expect(resp).to.have.property('currency'); expect(resp).to.have.property('ttl'); - expect(resp).to.have.property('mediaType', 'banner'); + expect(resp).to.have.property('mediaType', BANNER); expect(resp).to.have.property('ad'); expect(resp.ad).to.have.string(''); }); @@ -352,7 +502,7 @@ describe('Adkernel adapter', function () { let [pbRequests, _] = buildRequest([bid_video]); let resp = spec.interpretResponse({body: videoBidResponse}, pbRequests[0])[0]; expect(resp).to.have.property('requestId', 'Bid_Video'); - expect(resp.mediaType).to.equal('video'); + expect(resp.mediaType).to.equal(VIDEO); expect(resp.cpm).to.equal(0.00145); expect(resp.vastUrl).to.equal('https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl'); expect(resp.width).to.equal(640); @@ -373,12 +523,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'); }); }); @@ -388,4 +544,49 @@ describe('Adkernel adapter', function () { expect(spec.aliases).to.include.members(['headbidding', 'adsolut', 'oftmediahb', 'audiencemedia', 'waardex_ak', 'roqoon']); }); }); + + describe('native support', () => { + let _, bidRequests; + before(function () { + [_, bidRequests] = buildRequest([bid_native]); + }); + + it('native request building', () => { + expect(bidRequests[0].imp).to.have.length(1); + expect(bidRequests[0].imp[0]).to.have.property('native'); + expect(bidRequests[0].imp[0].native).to.have.property('request'); + let request = JSON.parse(bidRequests[0].imp[0].native.request); + expect(request).to.have.property('ver', '1.1'); + expect(request.assets).to.have.length(10); + expect(request.assets[0]).to.be.eql({id: 0, required: 1, title: {len: 80}}); + expect(request.assets[1]).to.be.eql({id: 3, required: 1, data: {type: 2}}); + expect(request.assets[2]).to.be.eql({id: 4, required: 1, data: {type: 10}}); + expect(request.assets[3]).to.be.eql({id: 1, required: 1, img: {wmin: 50, hmin: 50, type: 1}}); + expect(request.assets[4]).to.be.eql({id: 2, required: 1, img: {w: 300, h: 200, type: 3}}); + expect(request.assets[5]).to.be.eql({id: 11, required: 0, data: {type: 3}}); + expect(request.assets[6]).to.be.eql({id: 8, required: 0, data: {type: 6}}); + expect(request.assets[7]).to.be.eql({id: 10, required: 0, data: {type: 12}}); + expect(request.assets[8]).to.be.eql({id: 5, required: 0, data: {type: 1}}); + expect(request.assets[9]).to.be.eql({id: 14, required: 0, data: {type: 11}}); + }); + + it('native response processing', () => { + let [pbRequests, _] = buildRequest([bid_native]); + let resp = spec.interpretResponse({body: nativeResponse}, pbRequests[0])[0]; + expect(resp).to.have.property('requestId', 'Bid_01'); + expect(resp).to.have.property('cpm', 2.25); + expect(resp).to.have.property('currency', 'USD'); + expect(resp).to.have.property('mediaType', NATIVE); + expect(resp).to.have.property('native'); + expect(resp.native).to.have.property('clickUrl', 'http://rtb.com/click?i=pTuOlf5KHUo_0'); + expect(resp.native.impressionTrackers).to.be.eql(['http://rtb.com/win?i=pTuOlf5KHUo_0&f=imp']); + expect(resp.native).to.have.property('title', 'Title'); + expect(resp.native).to.have.property('body', 'Description'); + expect(resp.native).to.have.property('body2', 'Additional description'); + expect(resp.native.icon).to.be.eql({url: 'http://rtb.com/thumbnail?i=pTuOlf5KHUo_0&imgt=icon', width: 50, height: 50}); + expect(resp.native.image).to.be.eql({url: 'http://rtb.com/thumbnail?i=pTuOlf5KHUo_0', width: 300, height: 200}); + expect(resp.native).to.have.property('sponsoredBy', 'Sponsor.com'); + expect(resp.native).to.have.property('displayUrl', 'displayurl.com'); + }); + }); }); diff --git a/test/spec/modules/adliveBidAdapter_spec.js b/test/spec/modules/adliveBidAdapter_spec.js index 0048fc028b8..ddf8f82f20f 100644 --- a/test/spec/modules/adliveBidAdapter_spec.js +++ b/test/spec/modules/adliveBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/adliveBidAdapter'; +import { spec } from 'modules/adliveBidAdapter.js'; describe('adliveBidAdapterTests', function() { let bidRequestData = { diff --git a/test/spec/modules/admanBidAdapter_spec.js b/test/spec/modules/admanBidAdapter_spec.js new file mode 100644 index 00000000000..f3212dec2f5 --- /dev/null +++ b/test/spec/modules/admanBidAdapter_spec.js @@ -0,0 +1,231 @@ +import {expect} from 'chai'; +import {spec} from '../../../modules/admanBidAdapter.js'; + +describe('AdmanMediaBidAdapter', function () { + let bid = { + bidId: '23fhj33i987f', + bidder: 'adman', + params: { + placementId: 0, + traffic: 'banner' + } + }; + + 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]); + 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://pub.admanmedia.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'); + let placement = data['placements'][0]; + expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'sizes'); + expect(placement.placementId).to.equal(0); + expect(placement.bidId).to.equal('23fhj33i987f'); + expect(placement.traffic).to.equal('banner'); + }); + 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://pub.admanmedia.com/?c=o&m=sync'); + }); + }); +}); diff --git a/test/spec/modules/admediaBidAdapter_spec.js b/test/spec/modules/admediaBidAdapter_spec.js index 78228b85bff..5dc7b9a02a8 100644 --- a/test/spec/modules/admediaBidAdapter_spec.js +++ b/test/spec/modules/admediaBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/admediaBidAdapter'; +import { spec } from 'modules/admediaBidAdapter.js'; describe('admediaAdapterTests', function () { describe('bidRequestValidity', function () { diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js index dce3d9a42c7..6d2e3059dc8 100644 --- a/test/spec/modules/admixerBidAdapter_spec.js +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; -import {spec} from 'modules/admixerBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; +import {spec} from 'modules/admixerBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; const BIDDER_CODE = 'admixer'; const ENDPOINT_URL = 'https://inv-nets.admixer.net/prebid.1.0.aspx'; diff --git a/test/spec/modules/adnuntiusBidAdapter_spec.js b/test/spec/modules/adnuntiusBidAdapter_spec.js new file mode 100644 index 00000000000..54ff038c083 --- /dev/null +++ b/test/spec/modules/adnuntiusBidAdapter_spec.js @@ -0,0 +1,119 @@ +// 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/adnuntiusBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; + +describe('adnuntiusBidAdapter', function () { + const ENDPOINT_URL = 'https://delivery.adnuntius.com/i?tzo=-60&format=json'; + const adapter = newBidder(spec); + const bidRequests = [ + { + bidder: 'adnuntius', + params: { + auId: '8b6bc', + network: 'adnuntius', + }, + bidId: '123' + } + ]; + + const serverResponse = { + body: { + 'adUnits': [ + { + 'auId': '000000000008b6bc', + 'targetId': '', + 'html': '

hi!

', + 'matchedAdCount': 1, + 'responseId': 'adn-rsp-1460129238', + 'ads': [ + { + 'destinationUrlEsc': 'https%3A%2F%2Fdelivery.adnuntius.com%2Fc%2F52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN%3Fct%3D2501%26r%3Dhttp%253A%252F%252Fgoogle.com', + 'assets': { + 'image': { + 'cdnId': 'https://assets.adnuntius.com/oEmZa5uYjxENfA1R692FVn6qIveFpO8wUbpyF2xSOCc.jpg', + 'width': '980', + 'height': '120' + } + }, + 'clickUrl': 'https://delivery.adnuntius.com/c/52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + 'urls': { + 'destination': 'https://delivery.adnuntius.com/c/52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN?ct=2501&r=http%3A%2F%2Fgoogle.com' + }, + 'urlsEsc': { + 'destination': 'https%3A%2F%2Fdelivery.adnuntius.com%2Fc%2F52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN%3Fct%3D2501%26r%3Dhttp%253A%252F%252Fgoogle.com' + }, + 'destinationUrls': { + 'destination': 'http://google.com' + }, + 'cpm': { 'amount': 5.0, 'currency': 'NOK' }, + 'bid': { 'amount': 0.005, 'currency': 'NOK' }, + 'cost': { 'amount': 0.005, 'currency': 'NOK' }, + 'impressionTrackingUrls': [], + 'impressionTrackingUrlsEsc': [], + 'adId': 'adn-id-1347343135', + 'selectedColumn': '0', + 'selectedColumnPosition': '0', + 'renderedPixel': 'https://delivery.adnuntius.com/b/52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN.html', + 'renderedPixelEsc': 'https%3A%2F%2Fdelivery.adnuntius.com%2Fb%2F52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN.html', + 'visibleUrl': 'https://delivery.adnuntius.com/s?rt=52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + 'visibleUrlEsc': 'https%3A%2F%2Fdelivery.adnuntius.com%2Fs%3Frt%3D52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + 'viewUrl': 'https://delivery.adnuntius.com/v?rt=52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + 'viewUrlEsc': 'https%3A%2F%2Fdelivery.adnuntius.com%2Fv%3Frt%3D52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + 'rt': '52AHNuxCqxB_Y9ZP9ERWkMBPCOha4zuV3aKn5cog5jsAAAAQCtjQz9kbGWD4nuZy3q6HaHGLB4-k_fySWECIOOmHKY6iokgHNFH-U57ew_-1QHlKnFr2NT8y4QK1oU5HxnDLbYPz-GmQ3C2JyxLGpKmIb-P-3bm7HYPEreNjPdhjRG51A8NGuc4huUhns7nEUejHuOjOHE5sV1zfYxCRWRx9wPDN9EUCC7KN', + 'creativeWidth': '980', + 'creativeHeight': '120', + 'creativeId': 'wgkq587vgtpchsx1', + 'lineItemId': 'scyjdyv3mzgdsnpf', + 'layoutId': 'sw6gtws2rdj1kwby', + 'layoutName': 'Responsive image' + } + ] + } + ] + } + } + + 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(bidRequests[0])).to.equal(true); + }); + }); + + describe('buildRequests', function () { + it('Test requests', function () { + const request = spec.buildRequests(bidRequests); + expect(request.length).to.equal(1); + expect(request[0]).to.have.property('bid'); + const bid = request[0].bid[0] + expect(bid).to.have.property('bidId'); + expect(request[0]).to.have.property('url'); + expect(request[0].url).to.equal(ENDPOINT_URL); + expect(request[0]).to.have.property('data'); + expect(request[0].data).to.equal('{\"adUnits\":[{\"auId\":\"8b6bc\"}]}'); + }); + }); + + describe('interpretResponse', function () { + it('should return valid response when passed valid server response', function () { + const request = spec.buildRequests(bidRequests); + const interpretedResponse = spec.interpretResponse(serverResponse, request[0]); + const ad = serverResponse.body.adUnits[0].ads[0] + expect(interpretedResponse).to.have.lengthOf(1); + expect(interpretedResponse[0].cpm).to.equal(ad.cpm.amount); + expect(interpretedResponse[0].width).to.equal(Number(ad.creativeWidth)); + expect(interpretedResponse[0].height).to.equal(Number(ad.creativeHeight)); + expect(interpretedResponse[0].creativeId).to.equal(ad.creativeId); + expect(interpretedResponse[0].currency).to.equal(ad.cpm.currency); + expect(interpretedResponse[0].netRevenue).to.equal(false); + expect(interpretedResponse[0].ad).to.equal(serverResponse.body.adUnits[0].html); + expect(interpretedResponse[0].ttl).to.equal(360); + }); + }); +}); diff --git a/test/spec/modules/adoceanBidAdapter_spec.js b/test/spec/modules/adoceanBidAdapter_spec.js index 1fd009ce526..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'; -import { newBidder } from 'src/adapters/bidderFactory'; +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; @@ -95,7 +108,7 @@ describe('AdoceanAdapter', function () { it('sends bid request to url via GET', function () { const request = spec.buildRequests(bidRequests, bidderRequest)[0]; expect(request.method).to.equal('GET'); - expect(request.url).to.match(new RegExp(`^https://${bidRequests[0].params.emiter}/ad.json`)); + expect(request.url).to.match(new RegExp(`^https://${bidRequests[0].params.emiter}/_[0-9]*/ad.json`)); }); it('should attach id to url', function () { @@ -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/adomikAnalyticsAdapter_spec.js b/test/spec/modules/adomikAnalyticsAdapter_spec.js index 16480d746b7..1414b2402b9 100644 --- a/test/spec/modules/adomikAnalyticsAdapter_spec.js +++ b/test/spec/modules/adomikAnalyticsAdapter_spec.js @@ -1,4 +1,4 @@ -import adomikAnalytics from 'modules/adomikAnalyticsAdapter'; +import adomikAnalytics from 'modules/adomikAnalyticsAdapter.js'; import {expect} from 'chai'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; @@ -7,6 +7,13 @@ let constants = require('src/constants.json'); describe('Adomik Prebid Analytic', function () { let sendEventStub; let sendWonEventStub; + let clock; + before(function () { + clock = sinon.useFakeTimers(); + }); + after(function () { + clock.restore(); + }); describe('enableAnalytics', function () { beforeEach(function () { @@ -120,7 +127,6 @@ describe('Adomik Prebid Analytic', function () { expect(adomikAnalytics.currentContext.timeouted).to.equal(true); // Step 7: Send auction end event - var clock = sinon.useFakeTimers(); events.emit(constants.EVENTS.AUCTION_END, {}); setTimeout(function() { @@ -130,7 +136,6 @@ describe('Adomik Prebid Analytic', function () { }, 3000); clock.tick(5000); - clock.restore(); sinon.assert.callCount(adomikAnalytics.track, 6); }); diff --git a/test/spec/modules/adotBidAdapter_spec.js b/test/spec/modules/adotBidAdapter_spec.js new file mode 100644 index 00000000000..594fc4ac7b7 --- /dev/null +++ b/test/spec/modules/adotBidAdapter_spec.js @@ -0,0 +1,3118 @@ +import { expect } from 'chai'; +import { executeRenderer } from 'src/Renderer.js'; +import * as utils from 'src/utils.js'; +import { spec } from 'modules/adotBidAdapter.js'; + +const BIDDER_URL = 'https://dsp.adotmob.com/headerbidding/bidrequest'; + +describe('Adot Adapter', function () { + const examples = { + adUnit_banner: { + adUnitCode: 'ad_unit_banner', + bidder: 'adot', + bidderRequestId: 'bid_request_id', + bidId: 'bid_id', + params: {}, + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + } + }, + + adUnit_video_outstream: { + adUnitCode: 'ad_unit_video_outstream', + bidder: 'adot', + bidderRequestId: 'bid_request_id', + bidId: 'bid_id', + params: { + video: { + mimes: ['video/mp4'], + minDuration: 5, + maxDuration: 30, + protocols: [2, 3] + } + }, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [[300, 250]] + } + } + }, + + adUnit_video_instream: { + adUnitCode: 'ad_unit_video_instream', + bidder: 'adot', + bidderRequestId: 'bid_request_id', + bidId: 'bid_id', + params: { + video: { + instreamContext: 'pre-roll', + mimes: ['video/mp4'], + minDuration: 5, + maxDuration: 30, + protocols: [2, 3] + } + }, + mediaTypes: { + video: { + context: 'instream', + playerSize: [[300, 250]] + } + } + }, + + adUnitContext: { + refererInfo: { + referer: 'https://we-are-adot.com/test', + }, + gdprConsent: { + consentString: 'consent_string', + gdprApplies: true + } + }, + + adUnit_position: { + adUnitCode: 'ad_unit_position', + bidder: 'adot', + bidderRequestId: 'bid_request_id', + bidId: 'bid_id', + params: { + position: 1 + }, + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + } + }, + + adUnit_native: { + adUnitCode: 'ad_unit_native', + bidder: 'adot', + bidderRequestId: 'bid_request_id', + bidId: 'bid_id', + params: {}, + mediaTypes: { + native: { + title: {required: true, len: 140}, + icon: {required: true, sizes: [50, 50]}, + image: {required: false, sizes: [320, 200]}, + sponsoredBy: {required: false}, + body: {required: false}, + cta: {required: true} + } + } + }, + + serverRequest_banner: { + method: 'POST', + url: 'https://we-are-adot.com/bidrequest', + data: { + id: 'bid_request_id', + imp: [ + { + id: 'imp_id_banner_0_0', + banner: { + format: [{ + w: 300, + h: 200 + }] + }, + video: null + } + ], + site: { + page: 'https://we-are-adot.com/test', + domain: 'we-are-adot.com', + name: 'we-are-adot.com' + }, + device: { + ua: '', + language: 'en' + }, + user: null, + regs: null, + at: 1, + ext: { + adot: { + 'adapter_version': 'v1.0.0' + } + } + }, + _adot_internal: { + impressions: [ + { + impressionId: 'imp_id_banner_0_0', + adUnitCode: 'ad_unit_banner', + bidId: 'imp_id_banner' + } + ] + } + }, + + serverRequest_banner_twoImps: { + method: 'POST', + url: 'https://we-are-adot.com/bidrequest', + data: { + id: 'bid_request_id', + imp: [ + { + id: 'imp_id_banner_0_0', + banner: { + format: [{ + w: 300, + h: 200 + }] + }, + video: null + }, + { + id: 'imp_id_banner_2_0_0', + banner: { + format: [{ + w: 300, + h: 200 + }] + }, + video: null + } + ], + site: { + page: 'https://we-are-adot.com/test', + domain: 'we-are-adot.com', + name: 'we-are-adot.com' + }, + device: { + ua: '', + language: 'en' + }, + user: null, + regs: null, + at: 1, + ext: { + adot: { + 'adapter_version': 'v1.0.0' + } + } + }, + _adot_internal: { + impressions: [ + { + impressionId: 'imp_id_banner_0_0', + adUnitCode: 'ad_unit_banner', + bidId: 'imp_id_banner' + }, + { + impressionId: 'imp_id_banner_2_0_0', + adUnitCode: 'ad_unit_banner_2', + bidId: 'imp_id_banner_2' + } + ] + } + }, + + serverRequest_video_instream: { + method: 'POST', + url: 'https://we-are-adot.com/bidrequest', + data: { + id: 'bid_request_id', + imp: [ + { + id: 'imp_id_video_instream_0', + banner: null, + video: { + mimes: ['video/mp4'], + w: 300, + h: 200, + startdelay: 0, + minduration: 5, + maxduration: 35, + protocols: [2, 3] + } + } + ], + site: { + page: 'https://we-are-adot.com/test', + domain: 'we-are-adot.com', + name: 'we-are-adot.com' + }, + device: { + ua: '', + language: 'en' + }, + user: null, + regs: null, + at: 1, + ext: { + adot: { + 'adapter_version': 'v1.0.0' + } + } + }, + _adot_internal: { + impressions: [ + { + impressionId: 'imp_id_video_instream_0', + adUnitCode: 'ad_unit_video_instream', + bidId: 'imp_id_video_instream' + } + ] + } + }, + + serverRequest_video_outstream: { + method: 'POST', + url: 'https://we-are-adot.com/bidrequest', + data: { + id: 'bid_request_id', + imp: [ + { + id: 'imp_id_video_outstream_0', + banner: null, + video: { + mimes: ['video/mp4'], + w: 300, + h: 200, + startdelay: null, + minduration: 5, + maxduration: 35, + protocols: [2, 3] + } + } + ], + site: { + page: 'https://we-are-adot.com/test', + domain: 'we-are-adot.com', + name: 'we-are-adot.com' + }, + device: { + ua: '', + language: 'en' + }, + user: null, + regs: null, + at: 1, + ext: { + adot: { + 'adapter_version': 'v1.0.0' + } + } + }, + _adot_internal: { + impressions: [ + { + impressionId: 'imp_id_video_outstream_0', + adUnitCode: 'ad_unit_video_outstream', + bidId: 'imp_id_video_outstream' + } + ] + } + }, + + serverRequest_video_instream_outstream: { + method: 'POST', + url: 'https://we-are-adot.com/bidrequest', + data: { + id: 'bid_request_id', + imp: [ + { + id: 'imp_id_video_instream_0', + banner: null, + video: { + mimes: ['video/mp4'], + w: 300, + h: 200, + startdelay: 0, + minduration: 5, + maxduration: 35, + protocols: [2, 3] + } + }, + { + id: 'imp_id_video_outstream_0', + banner: null, + video: { + mimes: ['video/mp4'], + w: 300, + h: 200, + startdelay: null, + minduration: 5, + maxduration: 35, + protocols: [2, 3] + } + } + ], + site: { + page: 'https://we-are-adot.com/test', + domain: 'we-are-adot.com', + name: 'we-are-adot.com' + }, + device: { + ua: '', + language: 'en' + }, + user: null, + regs: null, + at: 1, + ext: { + adot: { + 'adapter_version': 'v1.0.0' + } + } + }, + _adot_internal: { + impressions: [ + { + impressionId: 'imp_id_video_instream_0', + adUnitCode: 'ad_unit_video_instream', + bidId: 'imp_id_video_instream' + }, + { + impressionId: 'imp_id_video_outstream_0', + adUnitCode: 'ad_unit_video_outstream', + bidId: 'imp_id_video_outstream' + } + ] + } + }, + + serverRequest_position: { + method: 'POST', + url: 'https://we-are-adot.com/bidrequest', + data: { + id: 'bid_request_id', + imp: [ + { + id: 'imp_id_banner', + banner: { + format: [{ + w: 300, + h: 200 + }], + position: 1 + }, + video: null + } + ], + site: { + page: 'https://we-are-adot.com/test', + domain: 'we-are-adot.com', + name: 'we-are-adot.com' + }, + device: { + ua: '', + language: 'en' + }, + user: null, + regs: null, + at: 1, + ext: { + adot: { + 'adapter_version': 'v1.0.0' + } + } + }, + _adot_internal: { + impressions: [ + { + impressionId: 'imp_id_banner', + adUnitCode: 'ad_unit_position' + } + ] + } + }, + + serverRequest_native: { + method: 'POST', + url: 'https://we-are-adot.com/bidrequest', + data: { + id: 'bid_request_id', + imp: [ + { + id: 'imp_id_native_0', + native: { + request: { + assets: [ + { + id: 1, + required: true, + title: { + len: 140 + } + }, + { + id: 2, + required: true, + img: { + type: 1, + wmin: 50, + hmin: 50 + } + }, + { + id: 3, + required: false, + img: { + type: 3, + wmin: 320, + hmin: 200 + } + }, + { + id: 4, + required: false, + data: { + type: 1 + } + }, + { + id: 5, + required: false, + data: { + type: 2 + } + }, + { + id: 6, + required: true, + data: { + type: 12 + } + } + ] + } + }, + video: null, + banner: null + } + ], + site: { + page: 'https://we-are-adot.com/test', + domain: 'we-are-adot.com', + name: 'we-are-adot.com' + }, + device: { + ua: '', + language: 'en' + }, + user: null, + regs: null, + at: 1, + ext: { + adot: { + 'adapter_version': 'v1.0.0' + } + } + }, + _adot_internal: { + impressions: [ + { + impressionId: 'imp_id_native_0', + adUnitCode: 'ad_unit_native', + bidId: 'imp_id_native' + } + ] + } + }, + + serverResponse_banner: { + body: { + cur: 'EUR', + seatbid: [ + { + bid: [ + { + impid: 'imp_id_banner_0_0', + crid: 'creative_id', + adm: 'creative_data_${AUCTION_PRICE}', + nurl: 'win_notice_url_${AUCTION_PRICE}', + price: 1.5, + h: 350, + w: 300, + ext: { + adot: { + media_type: 'banner' + } + } + } + ] + } + ] + } + }, + + serverResponse_banner_twoBids: { + body: { + cur: 'EUR', + seatbid: [ + { + bid: [ + { + impid: 'imp_id_banner_0_0', + crid: 'creative_id', + adm: 'creative_data_${AUCTION_PRICE}', + nurl: 'win_notice_url_${AUCTION_PRICE}', + price: 1.5, + h: 350, + w: 300, + ext: { + adot: { + media_type: 'banner' + } + } + }, + { + impid: 'imp_id_banner_2_0_0', + crid: 'creative_id_2', + adm: 'creative_data_2_${AUCTION_PRICE}', + nurl: 'win_notice_url_2_${AUCTION_PRICE}', + price: 2.5, + h: 400, + w: 350, + ext: { + adot: { + media_type: 'banner' + } + } + } + ] + } + ] + } + }, + + serverResponse_video_instream: { + body: { + cur: 'EUR', + seatbid: [ + { + bid: [ + { + impid: 'imp_id_video_instream_0', + crid: 'creative_id', + adm: 'creative_data_${AUCTION_PRICE}', + nurl: 'win_notice_url_${AUCTION_PRICE}', + price: 1.5, + ext: { + adot: { + media_type: 'video' + } + } + } + ] + } + ] + } + }, + + serverResponse_video_outstream: { + body: { + cur: 'EUR', + seatbid: [ + { + bid: [ + { + impid: 'imp_id_video_outstream_0', + crid: 'creative_id', + adm: 'creative_data_${AUCTION_PRICE}', + nurl: 'win_notice_url_${AUCTION_PRICE}', + price: 1.5, + ext: { + adot: { + media_type: 'video' + } + } + } + ] + } + ] + } + }, + + serverResponse_video_instream_outstream: { + body: { + cur: 'EUR', + seatbid: [ + { + bid: [ + { + impid: 'imp_id_video_instream_0', + crid: 'creative_id', + adm: 'creative_data_${AUCTION_PRICE}', + nurl: 'win_notice_url_${AUCTION_PRICE}', + price: 1.5, + ext: { + adot: { + media_type: 'video' + } + } + }, + { + impid: 'imp_id_video_outstream_0', + crid: 'creative_id', + adm: 'creative_data_${AUCTION_PRICE}', + nurl: 'win_notice_url_${AUCTION_PRICE}', + price: 1.5, + ext: { + adot: { + media_type: 'video' + } + } + } + ] + } + ] + } + }, + + serverResponse_native: { + body: { + cur: 'EUR', + seatbid: [ + { + bid: [ + { + impid: 'imp_id_native_0', + crid: 'creative_id', + adm: '{"native":{"assets":[{"id":1,"title":{"len":140,"text":"Hi everyone"}},{"id":2,"img":{"url":"https://adotmob.com","type":1,"w":50,"h":50}},{"id":3,"img":{"url":"https://adotmob.com","type":3,"w":320,"h":200}},{"id":4,"data":{"type":1,"value":"adotmob"}},{"id":5,"data":{"type":2,"value":"This is a test ad"}},{"id":6,"data":{"type":12,"value":"Click to buy"}}],"link":{"url":"https://adotmob.com?auction=${AUCTION_PRICE}"}}}', + nurl: 'win_notice_url_${AUCTION_PRICE}', + price: 1.5, + ext: { + adot: { + media_type: 'native' + } + } + } + ] + } + ] + } + } + }; + + describe('isBidRequestValid', function () { + describe('General', function () { + it('should return false when not given an ad unit', function () { + const adUnit = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an invalid ad unit', function () { + const adUnit = 'bad_bid'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit without bidder code', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.bidder = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with a bad bidder code', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.bidder = 'unknownBidder'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit without ad unit code', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.adUnitCode = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid ad unit code', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.adUnitCode = {}; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit without bid request identifier', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.bidderRequestId = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid bid request identifier', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.bidderRequestId = {}; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit without impression identifier', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.bidId = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid impression identifier', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.bidId = {}; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit without media types', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with empty media types', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes = {}; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with invalid media types', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes = 'bad_media_types'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + }); + + describe('Banner', function () { + it('should return true when given a valid ad unit', function () { + const adUnit = examples.adUnit_banner; + + expect(spec.isBidRequestValid(adUnit)).to.equal(true); + }); + + it('should return true when given a valid ad unit without bidder parameters', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.params = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(true); + }); + + it('should return false when given an ad unit without size', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid size', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = 'bad_banner_size'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an empty size', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = []; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid size value', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = ['bad_banner_size_value']; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with a size value with less than 2 dimensions', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = [[300]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with a size value with more than 2 dimensions', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = [[300, 250, 30]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with a negative width value', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = [[-300, 250]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with a negative height value', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = [[300, -250]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid width value', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = [[false, 250]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid height value', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = [[300, {}]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + }); + + describe('Video', function () { + it('should return true when given a valid outstream ad unit', function () { + const adUnit = examples.adUnit_video_outstream; + + expect(spec.isBidRequestValid(adUnit)).to.equal(true); + }); + + it('should return true when given a valid pre-roll instream ad unit', function () { + const adUnit = utils.deepClone(examples.adUnit_video_instream); + adUnit.params.video.instreamContext = 'pre-roll'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(true); + }); + + it('should return true when given a valid mid-roll instream ad unit', function () { + const adUnit = utils.deepClone(examples.adUnit_video_instream); + adUnit.params.video.instreamContext = 'mid-roll'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(true); + }); + + it('should return true when given a valid post-roll instream ad unit', function () { + const adUnit = utils.deepClone(examples.adUnit_video_instream); + adUnit.params.video.instreamContext = 'post-roll'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(true); + }); + + it('should return true when given an ad unit without size', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(true); + }); + + it('should return true when given an ad unit with an empty size', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = []; + + expect(spec.isBidRequestValid(adUnit)).to.equal(true); + }); + + it('should return true when given an ad unit without minimum duration parameter', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.minDuration = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(true); + }); + + it('should return true when given an ad unit without maximum duration parameter', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.maxDuration = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(true); + }); + + it('should return false when given an ad unit without bidder parameters', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with invalid bidder parameters', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params = 'bad_bidder_parameters'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit without video parameters', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with invalid video parameters', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video = 'bad_bidder_parameters'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit without mime types parameter', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.mimes = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid mime types parameter', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.mimes = 'bad_mime_types'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an empty mime types parameter', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.mimes = []; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid mime types parameter value', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.mimes = [200]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid minimum duration parameter', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.minDuration = 'bad_min_duration'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid maximum duration parameter', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.maxDuration = 'bad_max_duration'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit without protocols parameter', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.protocols = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid protocols parameter', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.protocols = 'bad_protocols'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an empty protocols parameter', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.protocols = []; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid protocols parameter value', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.protocols = ['bad_protocols_value']; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an instream ad unit without instream context', function () { + const adUnit = utils.deepClone(examples.adUnit_video_instream); + adUnit.params.video.instreamContext = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an instream ad unit with an invalid instream context', function () { + const adUnit = utils.deepClone(examples.adUnit_video_instream); + adUnit.params.video.instreamContext = 'bad_instream_context'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit without context', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.context = undefined; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid context', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.context = []; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an adpod ad unit', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.context = 'adpod'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an unknown context', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.context = 'invalid_context'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid size', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = 'bad_video_size'; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid size value', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = ['bad_video_size_value']; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with a size value with less than 2 dimensions', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = [[300]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with a size value with more than 2 dimensions', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = [[300, 250, 30]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with a negative width value', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = [[-300, 250]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with a negative height value', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = [[300, -250]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid width value', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = [[false, 250]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + + it('should return false when given an ad unit with an invalid height value', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = [[300, {}]]; + + expect(spec.isBidRequestValid(adUnit)).to.equal(false); + }); + }); + }); + + describe('buildRequests', function () { + describe('ServerRequest', function () { + it('should return a server request when given a valid ad unit and a valid ad unit context', function () { + const adUnits = [examples.adUnit_banner]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.length(1); + expect(serverRequests[0].method).to.exist.and.to.be.a('string').and.to.equal('POST'); + expect(serverRequests[0].url).to.exist.and.to.be.a('string').and.to.equal(BIDDER_URL); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0]._adot_internal).to.exist.and.to.be.an('object'); + expect(serverRequests[0]._adot_internal.impressions).to.exist.and.to.be.an('array').and.to.have.length(1); + expect(serverRequests[0]._adot_internal.impressions[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0]._adot_internal.impressions[0].impressionId).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0_0`); + expect(serverRequests[0]._adot_internal.impressions[0].adUnitCode).to.exist.and.to.be.a('string').and.to.equal(adUnits[0].adUnitCode); + }); + + it('should return a server request containing a position when given a valid ad unit and a valid ad unit context and a position in the bidder params', function () { + const adUnits = [examples.adUnit_position]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.length(1); + expect(serverRequests[0].method).to.exist.and.to.be.a('string').and.to.equal('POST'); + expect(serverRequests[0].url).to.exist.and.to.be.a('string').and.to.equal(BIDDER_URL); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0]._adot_internal).to.exist.and.to.be.an('object'); + expect(serverRequests[0]._adot_internal.impressions).to.exist.and.to.be.an('array').and.to.have.length(1); + expect(serverRequests[0]._adot_internal.impressions[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0]._adot_internal.impressions[0].impressionId).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0_0`); + expect(serverRequests[0]._adot_internal.impressions[0].adUnitCode).to.exist.and.to.be.a('string').and.to.equal(adUnits[0].adUnitCode); + expect(serverRequests[0].data.imp[0].banner.pos).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.position); + }); + + it('should return a server request when given two valid ad units and a valid ad unit context', function () { + const adUnits_1 = utils.deepClone(examples.adUnit_banner); + adUnits_1.bidId = 'bid_id_1'; + adUnits_1.adUnitCode = 'ad_unit_banner_1'; + + const adUnits_2 = utils.deepClone(examples.adUnit_banner); + adUnits_2.bidId = 'bid_id_2'; + adUnits_2.adUnitCode = 'ad_unit_banner_2'; + + const adUnits = [adUnits_1, adUnits_2]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.length(1); + expect(serverRequests[0].method).to.exist.and.to.be.a('string').and.to.equal('POST'); + expect(serverRequests[0].url).to.exist.and.to.be.a('string').and.to.equal(BIDDER_URL); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0]._adot_internal).to.exist.and.to.be.an('object'); + expect(serverRequests[0]._adot_internal.impressions).to.exist.and.to.be.an('array').and.to.have.length(2); + expect(serverRequests[0]._adot_internal.impressions[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0]._adot_internal.impressions[0].impressionId).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0_0`); + expect(serverRequests[0]._adot_internal.impressions[0].adUnitCode).to.exist.and.to.be.a('string').and.to.equal(adUnits[0].adUnitCode); + expect(serverRequests[0]._adot_internal.impressions[1]).to.exist.and.to.be.an('object'); + expect(serverRequests[0]._adot_internal.impressions[1].impressionId).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[1].bidId}_0_0`); + expect(serverRequests[0]._adot_internal.impressions[1].adUnitCode).to.exist.and.to.be.a('string').and.to.equal(adUnits[1].adUnitCode); + }); + + it('should return an empty server request list when given an empty ad unit list and a valid ad unit context', function () { + const adUnits = []; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.length(0); + }); + + it('should not return a server request when given no ad unit and a valid ad unit context', function () { + const serverRequests = spec.buildRequests(null, examples.adUnitContext); + + expect(serverRequests).to.equal(null); + }); + + it('should not return a server request when given a valid ad unit and no ad unit context', function () { + const adUnits = [examples.adUnit_banner]; + + const serverRequests = spec.buildRequests(adUnits, null); + + expect(serverRequests).to.be.an('array').and.to.have.length(1); + }); + + it('should not return a server request when given a valid ad unit and an invalid ad unit context', function () { + const adUnits = [examples.adUnit_banner]; + + const serverRequests = spec.buildRequests(adUnits, {}); + + expect(serverRequests).to.be.an('array').and.to.have.length(1); + }); + }); + + describe('BidRequest', function () { + it('should return a valid server request when given a valid ad unit', function () { + const adUnits = [examples.adUnit_banner]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.id).to.exist.and.to.be.a('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.at).to.exist.and.to.be.a('number').and.to.equal(1); + expect(serverRequests[0].data.ext).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.ext.adot).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.ext.adot.adapter_version).to.exist.and.to.be.a('string').and.to.equal('v1.0.0'); + }); + + it('should return one server request when given one valid ad unit', function () { + const adUnits = [examples.adUnit_banner]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.id).to.exist.and.to.be.a('string').and.to.equal(adUnits[0].bidderRequestId); + }); + + it('should return one server request when given two valid ad units with different impression identifiers', function () { + const adUnit_1 = utils.deepClone(examples.adUnit_banner); + adUnit_1.bidId = 'bid_id_1'; + + const adUnit_2 = utils.deepClone(examples.adUnit_banner); + adUnit_2.bidId = 'bid_id_2'; + + const adUnits = [adUnit_1, adUnit_2]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.id).to.exist.and.to.be.a('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.id).to.exist.and.to.be.a('string').and.to.equal(adUnits[1].bidderRequestId); + }); + + it('should return two server requests when given two valid ad units with different bid request identifiers', function () { + const adUnit_1 = utils.deepClone(examples.adUnit_banner); + adUnit_1.bidderRequestId = 'bidder_request_id_1'; + + const adUnit_2 = utils.deepClone(examples.adUnit_banner); + adUnit_2.bidderRequestId = 'bidder_request_id_2'; + + const adUnits = [adUnit_1, adUnit_2]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(2); + expect(serverRequests[0].data.id).to.exist.and.to.be.a('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[1].data.id).to.exist.and.to.be.a('string').and.to.equal(adUnits[1].bidderRequestId); + }); + }); + + describe('Impression', function () { + describe('Banner', function () { + it('should return a server request with one impression when given a valid ad unit', function () { + const adUnits = [examples.adUnit_banner]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0_0`); + expect(serverRequests[0].data.imp[0].banner).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].banner.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.banner.sizes[0][0]); + expect(serverRequests[0].data.imp[0].banner.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.banner.sizes[0][1]); + expect(serverRequests[0].data.imp[0].banner.format).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0].banner.format[0]).to.exist.and.to.be.an('object').and.to.deep.equal({ + w: adUnits[0].mediaTypes.banner.sizes[0][0], + h: adUnits[0].mediaTypes.banner.sizes[0][1] + }); + }); + + it('should return a server request with two impressions containing one banner formats when given a valid ad unit with two banner sizes', function () { + const adUnit = utils.deepClone(examples.adUnit_banner); + adUnit.mediaTypes.banner.sizes = [ + [300, 250], + [350, 300] + ]; + + const adUnits = [adUnit]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(2); + + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0_0`); + expect(serverRequests[0].data.imp[0].banner).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].banner.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.banner.sizes[0][0]); + expect(serverRequests[0].data.imp[0].banner.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.banner.sizes[0][1]); + expect(serverRequests[0].data.imp[0].banner.format).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0].banner.format[0]).to.exist.and.to.be.an('object').and.to.deep.equal({ + w: adUnits[0].mediaTypes.banner.sizes[0][0], + h: adUnits[0].mediaTypes.banner.sizes[0][1] + }); + + expect(serverRequests[0].data.imp[1]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[1].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0_1`); + expect(serverRequests[0].data.imp[1].banner).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[1].banner.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.banner.sizes[1][0]); + expect(serverRequests[0].data.imp[1].banner.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.banner.sizes[1][1]); + expect(serverRequests[0].data.imp[1].banner.format).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[1].banner.format[0]).to.exist.and.to.be.an('object').and.to.deep.equal({ + w: adUnits[0].mediaTypes.banner.sizes[1][0], + h: adUnits[0].mediaTypes.banner.sizes[1][1] + }); + }); + + it('should return a server request with two impressions when given two valid ad units with different impression identifiers', function () { + const adUnit_1 = utils.deepClone(examples.adUnit_banner); + adUnit_1.bidId = 'bid_id_1'; + + const adUnit_2 = utils.deepClone(examples.adUnit_banner); + adUnit_2.bidId = 'bid_id_2'; + + const adUnits = [adUnit_1, adUnit_2]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(2); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0_0`); + expect(serverRequests[0].data.imp[0].banner).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].banner.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.banner.sizes[0][0]); + expect(serverRequests[0].data.imp[0].banner.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.banner.sizes[0][1]); + expect(serverRequests[0].data.imp[0].banner.format).to.exist.and.to.be.an('array'); + expect(serverRequests[0].data.imp[0].banner.format[0]).to.exist.and.to.be.an('object').and.to.deep.equal({ + w: adUnits[0].mediaTypes.banner.sizes[0][0], + h: adUnits[0].mediaTypes.banner.sizes[0][1] + }); + expect(serverRequests[0].data.imp[1]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[1].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[1].bidId}_0_0`); + expect(serverRequests[0].data.imp[1].banner).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[1].banner.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.banner.sizes[0][0]); + expect(serverRequests[0].data.imp[1].banner.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.banner.sizes[0][1]); + expect(serverRequests[0].data.imp[1].banner.format).to.exist.and.to.be.an('array'); + expect(serverRequests[0].data.imp[1].banner.format[0]).to.exist.and.to.be.an('object').and.to.deep.equal({ + w: adUnits[1].mediaTypes.banner.sizes[0][0], + h: adUnits[1].mediaTypes.banner.sizes[0][1] + }); + }); + + it('should return a server request with one overriden impression when given two valid ad units with identical identifiers', function () { + const adUnit_1 = utils.deepClone(examples.adUnit_banner); + adUnit_1.mediaTypes.banner.sizes = [[300, 250]]; + + const adUnit_2 = utils.deepClone(examples.adUnit_banner); + adUnit_2.mediaTypes.banner.sizes = [[350, 300]]; + + const adUnits = [adUnit_1, adUnit_2]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[1].bidId}_0_0`); + expect(serverRequests[0].data.imp[0].banner).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].banner.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.banner.sizes[0][0]); + expect(serverRequests[0].data.imp[0].banner.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.banner.sizes[0][1]); + expect(serverRequests[0].data.imp[0].banner.format).to.exist.and.to.be.an('array'); + expect(serverRequests[0].data.imp[0].banner.format[0]).to.exist.and.to.be.an('object').and.to.deep.equal({ + w: adUnits[1].mediaTypes.banner.sizes[0][0], + h: adUnits[1].mediaTypes.banner.sizes[0][1] + }); + }); + + it('should return two server requests with one impression when given two valid ad units with different bid request identifiers', function () { + const adUnit_1 = utils.deepClone(examples.adUnit_banner); + adUnit_1.bidderRequestId = 'bidder_request_id_1'; + + const adUnit_2 = utils.deepClone(examples.adUnit_banner); + adUnit_2.bidderRequestId = 'bidder_request_id_2'; + + const adUnits = [adUnit_1, adUnit_2]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(2); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0_0`); + expect(serverRequests[0].data.imp[0].banner).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].banner.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.banner.sizes[0][0]); + expect(serverRequests[0].data.imp[0].banner.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.banner.sizes[0][1]); + expect(serverRequests[0].data.imp[0].banner.format).to.exist.and.to.be.an('array'); + expect(serverRequests[0].data.imp[0].banner.format[0]).to.exist.and.to.be.an('object').and.to.deep.equal({ + w: adUnits[0].mediaTypes.banner.sizes[0][0], + h: adUnits[0].mediaTypes.banner.sizes[0][1] + }); + expect(serverRequests[1].data).to.exist.and.to.be.an('object'); + expect(serverRequests[1].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[1].bidderRequestId); + expect(serverRequests[1].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[1].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[1].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[1].bidId}_0_0`); + expect(serverRequests[1].data.imp[0].banner).to.exist.and.to.be.an('object'); + expect(serverRequests[1].data.imp[0].banner.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.banner.sizes[0][0]); + expect(serverRequests[1].data.imp[0].banner.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.banner.sizes[0][1]); + expect(serverRequests[1].data.imp[0].banner.format).to.exist.and.to.be.an('array'); + expect(serverRequests[1].data.imp[0].banner.format[0]).to.exist.and.to.be.an('object').and.to.deep.equal({ + w: adUnits[1].mediaTypes.banner.sizes[0][0], + h: adUnits[1].mediaTypes.banner.sizes[0][1] + }); + }); + }); + + describe('Video', function () { + it('should return a server request with one impression when given a valid outstream ad unit', function () { + const adUnit = examples.adUnit_video_outstream; + + const adUnits = [adUnit]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.equal(null); + expect(serverRequests[0].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + }); + + it('should return a server request with one impression when given a valid pre-roll instream ad unit', function () { + const adUnit = utils.deepClone(examples.adUnit_video_instream); + adUnit.params.video.instreamContext = 'pre-roll'; + + const adUnits = [adUnit]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.exist.and.to.be.a('number').and.to.equal(0); + expect(serverRequests[0].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + }); + + it('should return a server request with one impression when given a valid mid-roll instream ad unit', function () { + const adUnit = utils.deepClone(examples.adUnit_video_instream); + adUnit.params.video.instreamContext = 'mid-roll'; + + const adUnits = [adUnit]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.exist.and.to.be.a('number').and.to.equal(-1); + expect(serverRequests[0].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + }); + + it('should return a server request with one impression when given a valid post-roll instream ad unit', function () { + const adUnit = utils.deepClone(examples.adUnit_video_instream); + adUnit.params.video.instreamContext = 'post-roll'; + + const adUnits = [adUnit]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.exist.and.to.be.a('number').and.to.equal(-2); + expect(serverRequests[0].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + }); + + it('should return a server request with one impression when given a valid ad unit without player size', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = undefined; + + const adUnits = [adUnit]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.equal(null); + expect(serverRequests[0].data.imp[0].video.w).to.equal(null); + expect(serverRequests[0].data.imp[0].video.h).to.equal(null); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + }); + + it('should return a server request with one impression when given a valid ad unit with an empty player size', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = []; + + const adUnits = [adUnit]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.equal(null); + expect(serverRequests[0].data.imp[0].video.w).to.equal(null); + expect(serverRequests[0].data.imp[0].video.h).to.equal(null); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + }); + + it('should return a server request with one impression when given a valid ad unit with multiple player sizes', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.mediaTypes.video.playerSize = [[350, 300], [400, 350]]; + + const adUnits = [adUnit]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.equal(null); + expect(serverRequests[0].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + }); + + it('should return a server request with one impression when given a valid ad unit without minimum duration', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.minDuration = undefined; + + const adUnits = [adUnit]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.equal(null); + expect(serverRequests[0].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[0].video.minduration).to.equal(null); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + }); + + it('should return a server request with one impression when given a valid ad unit without maximum duration', function () { + const adUnit = utils.deepClone(examples.adUnit_video_outstream); + adUnit.params.video.maxDuration = undefined; + + const adUnits = [adUnit]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.equal(null); + expect(serverRequests[0].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.equal(null); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + }); + + it('should return a server request with two impressions when given two valid ad units with different impression identifiers', function () { + const adUnit_1 = utils.deepClone(examples.adUnit_video_outstream); + adUnit_1.bidId = 'bid_id_1'; + + const adUnit_2 = utils.deepClone(examples.adUnit_video_outstream); + adUnit_2.bidId = 'bid_id_2'; + + const adUnits = [adUnit_1, adUnit_2]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(2); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.equal(null); + expect(serverRequests[0].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + expect(serverRequests[0].data.imp[1]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[1].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[1].bidId}_0`); + expect(serverRequests[0].data.imp[1].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[1].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[1].video.startdelay).to.equal(null); + expect(serverRequests[0].data.imp[1].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[1].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[1].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].params.video.minDuration); + expect(serverRequests[0].data.imp[1].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].params.video.maxDuration); + expect(serverRequests[0].data.imp[1].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[1].params.video.protocols); + }); + + it('should return a server request with one overridden impression when given two valid ad units with identical identifiers', function () { + const adUnit_1 = utils.deepClone(examples.adUnit_video_outstream); + adUnit_1.params.video.minDuration = 10; + + const adUnit_2 = utils.deepClone(examples.adUnit_video_outstream); + adUnit_2.params.video.minDuration = 15; + + const adUnits = [adUnit_1, adUnit_2]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[1].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.equal(null); + expect(serverRequests[0].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[1].params.video.protocols); + }); + + it('should return two server requests with one impression when given two valid ad units with different bid request identifiers', function () { + const adUnit_1 = utils.deepClone(examples.adUnit_video_outstream); + adUnit_1.bidderRequestId = 'bidder_request_id_1'; + + const adUnit_2 = utils.deepClone(examples.adUnit_video_outstream); + adUnit_2.bidderRequestId = 'bidder_request_id_2'; + + const adUnits = [adUnit_1, adUnit_2]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(2); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[0].data.imp[0].video.startdelay).to.equal(null); + expect(serverRequests[0].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[0].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[0].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.minDuration); + expect(serverRequests[0].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[0].params.video.maxDuration); + expect(serverRequests[0].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.protocols); + expect(serverRequests[1].data).to.exist.and.to.be.an('object'); + expect(serverRequests[1].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[1].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[1].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[1].bidId}_0`); + expect(serverRequests[1].data.imp[0].video).to.exist.and.to.be.an('object'); + expect(serverRequests[1].data.imp[0].video.mimes).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[0].params.video.mimes); + expect(serverRequests[1].data.imp[0].video.startdelay).to.equal(null); + expect(serverRequests[1].data.imp[0].video.w).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.video.playerSize[0][0]); + expect(serverRequests[1].data.imp[0].video.h).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].mediaTypes.video.playerSize[0][1]); + expect(serverRequests[1].data.imp[0].video.minduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].params.video.minDuration); + expect(serverRequests[1].data.imp[0].video.maxduration).to.exist.and.to.be.a('number').and.to.equal(adUnits[1].params.video.maxDuration); + expect(serverRequests[1].data.imp[0].video.protocols).to.exist.and.to.be.an('array').and.to.deep.equal(adUnits[1].params.video.protocols); + }); + }); + + describe('Native', function () { + it('should return a server request with one impression when given a valid ad unit', function () { + const adUnits = [examples.adUnit_native]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnit_native); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data.imp[0]).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].id).to.exist.and.to.be.a('string').and.to.equal(`${adUnits[0].bidId}_0`); + expect(serverRequests[0].data.imp[0].native).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.imp[0].native.request).to.exist.and.to.be.a('string').and.to.equal(JSON.stringify(examples.serverRequest_native.data.imp[0].native.request)) + }); + }); + }); + + describe('Site', function () { + it('should return a server request with site information when given a valid ad unit and a valid ad unit context', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = examples.adUnitContext; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.site).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.site.page).to.exist.and.to.be.an('string').and.to.equal(adUnitContext.refererInfo.referer); + expect(serverRequests[0].data.site.id).to.equal(undefined); + expect(serverRequests[0].data.site.domain).to.exist.and.to.be.an('string').and.to.equal('we-are-adot.com'); + expect(serverRequests[0].data.site.name).to.exist.and.to.be.an('string').and.to.equal('we-are-adot.com'); + }); + + it('should return a server request without site information when not given an ad unit context', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = undefined; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.site).to.equal(null); + }); + + it('should return a server request without site information when given an ad unit context without referer information', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.refererInfo = undefined; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.site).to.equal(null); + }); + + it('should return a server request without site information when given an ad unit context with invalid referer information', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.refererInfo = 'bad_referer_information'; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.site).to.equal(null); + }); + + it('should return a server request without site information when given an ad unit context without referer', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.refererInfo.referer = undefined; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.site).to.equal(null); + }); + + it('should return a server request without site information when given an ad unit context with an invalid referer', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.refererInfo.referer = {}; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.site).to.equal(null); + }); + + it('should return a server request without site information when given an ad unit context with a misformatted referer', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.refererInfo.referer = 'we-are-adot'; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.site).to.equal(null); + }); + }); + + describe('Device', function () { + it('should return a server request with device information when given a valid ad unit and a valid ad unit context', function () { + const adUnits = [examples.adUnit_banner]; + + const serverRequests = spec.buildRequests(adUnits, examples.adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.device).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.device.ua).to.exist.and.to.be.a('string'); + expect(serverRequests[0].data.device.language).to.exist.and.to.be.a('string'); + }); + }); + + describe('Regs', function () { + it('should return a server request with regulations information when given a valid ad unit and a valid ad unit context with GDPR applying', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = examples.adUnitContext; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.regs).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.regs.ext).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.regs.ext.gdpr).to.exist.and.to.be.a('boolean').and.to.equal(adUnitContext.gdprConsent.gdprApplies); + }); + + it('should return a server request with regulations information when given a valid ad unit and a valid ad unit context with GDPR not applying', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.gdprConsent.gdprApplies = false; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.regs).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.regs.ext).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.regs.ext.gdpr).to.exist.and.to.be.a('boolean').and.to.equal(adUnitContext.gdprConsent.gdprApplies); + }); + + it('should return a server request without regulations information when not given an ad unit context', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = undefined; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.regs).to.equal(null); + }); + + it('should return a server request without regulations information when given an ad unit context without GDPR information', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.gdprConsent = undefined; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.regs).to.equal(null); + }); + + it('should return a server request without regulations information when given an ad unit context with invalid GDPR information', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.gdprConsent = 'bad_gdpr_consent'; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.regs).to.equal(null); + }); + + it('should return a server request without regulations information when given an ad unit context with invalid GDPR application information', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.gdprConsent.gdprApplies = 'bad_gdpr_applies'; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.regs).to.equal(null); + }); + }); + + describe('User', function () { + it('should return a server request with user information when given a valid ad unit and a valid ad unit context', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = examples.adUnitContext; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.user).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.user.ext).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.user.ext.consent).to.exist.and.to.be.a('string').and.to.equal(adUnitContext.gdprConsent.consentString); + }); + + it('should return a server request without user information when not given an ad unit context', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = undefined; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.user).to.equal(null); + }); + + it('should return a server request without user information when given an ad unit context without GDPR information', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.gdprConsent = undefined; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.user).to.equal(null); + }); + + it('should return a server request without user information when given an ad unit context with invalid GDPR information', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.gdprConsent = 'bad_gdpr_consent'; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.user).to.equal(null); + }); + + it('should return a server request without user information when given an ad unit context with an invalid consent string', function () { + const adUnits = [examples.adUnit_banner]; + + const adUnitContext = utils.deepClone(examples.adUnitContext); + adUnitContext.gdprConsent.consentString = true; + + const serverRequests = spec.buildRequests(adUnits, adUnitContext); + + expect(serverRequests).to.be.an('array').and.to.have.lengthOf(1); + expect(serverRequests[0].data).to.exist.and.to.be.an('object'); + expect(serverRequests[0].data.id).to.exist.and.to.be.an('string').and.to.equal(adUnits[0].bidderRequestId); + expect(serverRequests[0].data.user).to.equal(null); + }); + }); + }); + + describe('interpretResponse', function () { + describe('General', function () { + it('should return an ad when given a valid server response with one bid with USD currency', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.cur = 'USD'; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(null); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].h); + expect(ads[0].width).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('banner'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return two ads when given a valid server response with two bids', function () { + const serverRequest = examples.serverRequest_banner_twoImps; + + const serverResponse = examples.serverResponse_banner_twoBids; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(2); + + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(null); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].h); + expect(ads[0].width).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('banner'); + expect(ads[0].renderer).to.equal(null); + expect(ads[1].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[1].bidId); + expect(ads[1].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[1].adm); + expect(ads[1].adUrl).to.equal(null); + expect(ads[1].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[1].crid); + expect(ads[1].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[1].price); + expect(ads[1].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[1].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[1].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[1].height).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[1].h); + expect(ads[1].width).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[1].w); + expect(ads[1].mediaType).to.exist.and.to.be.a('string').and.to.equal('banner'); + expect(ads[1].renderer).to.equal(null); + }); + + it('should return no ad when not given a server response', function () { + const ads = spec.interpretResponse(null); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when not given a server response body', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given an invalid server response body', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body = 'invalid_body'; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response without seat bids', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with invalid seat bids', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid = 'invalid_seat_bids'; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with an empty seat bids array', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid = []; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with an invalid seat bid', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid = 'invalid_bids'; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with an empty bids array', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid = []; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with an invalid bid', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid = ['invalid_bid']; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid without currency', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.cur = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid currency', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.cur = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid without impression identifier', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].impid = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid impression identifier', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].impid = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid without creative identifier', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].crid = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid creative identifier', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].crid = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid without ad markup and ad serving URL', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].adm = undefined; + serverResponse.body.seatbid[0].bid[0].nurl = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid ad markup', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].adm = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an ad markup without auction price macro', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].adm = 'creative_data'; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid ad serving URL', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].nurl = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an ad serving URL without auction price macro', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].nurl = 'win_notice_url'; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid without bid price', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].price = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid bid price', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].price = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid without extension', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].ext = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid extension', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].ext = 'bad_ext'; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid without adot extension', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].ext.adot = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid adot extension', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].ext.adot = 'bad_adot_ext'; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid without media type', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].ext.adot.media_type = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid media type', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].ext.adot.media_type = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an unknown media type', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].ext.adot.media_type = 'unknown_media_type'; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and no server request', function () { + const serverRequest = undefined; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and an invalid server request', function () { + const serverRequest = 'bad_server_request'; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request without bid request', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest.data = undefined; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request with an invalid bid request', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest.data = 'bad_bid_request'; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request without impression', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest.data.imp = undefined; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request with an invalid impression field', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest.data.imp = 'invalid_impressions'; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request without matching impression', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest.data.imp[0].id = 'unknown_imp_id'; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request without internal data', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest._adot_internal = undefined; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request with invalid internal data', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest._adot_internal = 'bad_internal_data'; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request without internal impression data', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest._adot_internal.impressions = undefined; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request with invalid internal impression data', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest._adot_internal.impressions = 'bad_internal_impression_data'; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request without matching internal impression', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest._adot_internal.impressions[0].impressionId = 'unknown_imp_id'; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request without internal impression ad unit code', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest._adot_internal.impressions[0].adUnitCode = undefined; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request with an invalid internal impression ad unit code', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest._adot_internal.impressions[0].adUnitCode = {}; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + }); + + describe('Banner', function () { + it('should return an ad when given a valid server response with one bid', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = examples.serverResponse_banner; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(null); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].h); + expect(ads[0].width).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('banner'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return an ad when given a valid server response with one bid without a win notice URL', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].nurl = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(null); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].h); + expect(ads[0].width).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('banner'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return an ad when given a valid server response with one bid using an ad serving URL', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].adm = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.equal(null); + expect(ads[0].adUrl).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].nurl); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].h); + expect(ads[0].width).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('banner'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return no ad when given a server response with a bid without height', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].h = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid height', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].h = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid without width', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].w = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid width', function () { + const serverRequest = examples.serverRequest_banner; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + serverResponse.body.seatbid[0].bid[0].w = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request without banner impression', function () { + const serverRequest = utils.deepClone(examples.serverRequest_banner); + serverRequest.data.imp[0].banner = undefined; + + const serverResponse = utils.deepClone(examples.serverResponse_banner); + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + }); + + describe('Video', function () { + it('should return an ad when given a valid server response with one bid on an instream impression', function () { + const serverRequest = examples.serverRequest_video_instream; + + const serverResponse = examples.serverResponse_video_instream; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(serverRequest.data.imp[0].video.h); + expect(ads[0].width).to.equal(serverRequest.data.imp[0].video.w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return an ad when given a valid server response with one bid on an outstream impression', function () { + const serverRequest = examples.serverRequest_video_outstream; + + const serverResponse = examples.serverResponse_video_outstream; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(serverRequest.data.imp[0].video.h); + expect(ads[0].width).to.equal(serverRequest.data.imp[0].video.w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[0].renderer).to.be.an('object'); + }); + + it('should return two ads when given a valid server response with two bids on both instream and outstream impressions', function () { + const serverRequest = examples.serverRequest_video_instream_outstream; + + const serverResponse = examples.serverResponse_video_instream_outstream; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(2); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(serverRequest.data.imp[0].video.h); + expect(ads[0].width).to.equal(serverRequest.data.imp[0].video.w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[0].renderer).to.equal(null); + expect(ads[1].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[1].bidId); + expect(ads[1].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[1].adm); + expect(ads[1].adUrl).to.equal(null); + expect(ads[1].vastXml).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[1].vastUrl).to.equal(null); + expect(ads[1].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[1].crid); + expect(ads[1].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[1].price); + expect(ads[1].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[1].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[1].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(serverRequest.data.imp[1].video.h); + expect(ads[0].width).to.equal(serverRequest.data.imp[1].video.w); + expect(ads[1].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[1].renderer).to.be.an('object'); + }); + + it('should return an ad when given a valid server response with one bid without a win notice URL', function () { + const serverRequest = examples.serverRequest_video_instream; + + const serverResponse = utils.deepClone(examples.serverResponse_video_instream); + serverResponse.body.seatbid[0].bid[0].nurl = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(serverRequest.data.imp[0].video.h); + expect(ads[0].width).to.equal(serverRequest.data.imp[0].video.w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return an ad when given a valid server response with one bid using an ad serving URL', function () { + const serverRequest = examples.serverRequest_video_instream; + + const serverResponse = utils.deepClone(examples.serverResponse_video_instream); + serverResponse.body.seatbid[0].bid[0].adm = undefined; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.equal(null); + expect(ads[0].adUrl).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].nurl); + expect(ads[0].vastXml).to.equal(null); + expect(ads[0].vastUrl).to.equal(serverResponse.body.seatbid[0].bid[0].nurl); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(serverRequest.data.imp[0].video.h); + expect(ads[0].width).to.equal(serverRequest.data.imp[0].video.w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return an ad when given a valid server response with a bid with a video height', function () { + const serverRequest = examples.serverRequest_video_instream; + + const serverResponse = utils.deepClone(examples.serverResponse_video_instream); + serverResponse.body.seatbid[0].bid[0].h = 500; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(serverRequest.data.imp[0].video.h); + expect(ads[0].width).to.equal(serverRequest.data.imp[0].video.w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return an ad when given a valid server response with a bid with a video width', function () { + const serverRequest = examples.serverRequest_video_instream; + + const serverResponse = utils.deepClone(examples.serverResponse_video_instream); + serverResponse.body.seatbid[0].bid[0].w = 500; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(serverRequest.data.imp[0].video.h); + expect(ads[0].width).to.equal(serverRequest.data.imp[0].video.w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return an ad when given a valid server response with a bid with a video width and height', function () { + const serverRequest = examples.serverRequest_video_instream; + + const serverResponse = utils.deepClone(examples.serverResponse_video_instream); + serverResponse.body.seatbid[0].bid[0].w = 500; + serverResponse.body.seatbid[0].bid[0].h = 400; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(serverResponse.body.seatbid[0].bid[0].h); + expect(ads[0].width).to.equal(serverResponse.body.seatbid[0].bid[0].w); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return an ad when given a valid server response and server request with a video impression without width', function () { + const serverRequest = utils.deepClone(examples.serverRequest_video_instream); + serverRequest.data.imp[0].video.w = null; + + const serverResponse = utils.deepClone(examples.serverResponse_video_instream); + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(null); + expect(ads[0].width).to.equal(null); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return an ad when given a valid server response and server request with a video impression without height', function () { + const serverRequest = utils.deepClone(examples.serverRequest_video_instream); + serverRequest.data.imp[0].video.h = null; + + const serverResponse = utils.deepClone(examples.serverResponse_video_instream); + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].ad).to.exist.and.to.be.a('string').and.to.have.string(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].adUrl).to.equal(null); + expect(ads[0].vastXml).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(ads[0].vastUrl).to.equal(null); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].height).to.equal(null); + expect(ads[0].width).to.equal(null); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('video'); + expect(ads[0].renderer).to.equal(null); + }); + + it('should return no ad when given a server response with a bid with an invalid height', function () { + const serverRequest = examples.serverRequest_video_instream; + + const serverResponse = utils.deepClone(examples.serverResponse_video_instream); + serverResponse.body.seatbid[0].bid[0].h = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a server response with a bid with an invalid width', function () { + const serverRequest = examples.serverRequest_video_instream; + + const serverResponse = utils.deepClone(examples.serverResponse_video_instream); + serverResponse.body.seatbid[0].bid[0].w = {}; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + it('should return no ad when given a valid server response and a server request without video impression', function () { + const serverRequest = utils.deepClone(examples.serverRequest_video_instream); + serverRequest.data.imp[0].video = undefined; + + const serverResponse = utils.deepClone(examples.serverResponse_video_instream); + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(0); + }); + + describe('Outstream renderer', function () { + function spyAdRenderingQueue(ad) { + const spy = sinon.spy(ad.renderer, 'push'); + + this.sinonSpies.push(spy); + } + + function executeAdRenderer(ad, onRendererExecution, done) { + executeRenderer(ad.renderer, ad); + + setTimeout(() => { + try { + onRendererExecution(); + } catch (err) { + done(err); + } + + done() + }, 100); + } + + before('Bind helper functions to the Mocha context', function () { + this.spyAdRenderingQueue = spyAdRenderingQueue.bind(this); + + window.VASTPlayer = function VASTPlayer() {}; + window.VASTPlayer.prototype.loadXml = function loadXml() { + return new Promise((resolve, reject) => resolve()) + }; + window.VASTPlayer.prototype.load = function load() { + return new Promise((resolve, reject) => resolve()) + }; + window.VASTPlayer.prototype.on = function on(event, callback) {}; + window.VASTPlayer.prototype.startAd = function startAd() {}; + }); + + beforeEach('Initialize the Sinon spies list', function () { + this.sinonSpies = []; + }); + + afterEach('Clear the registered Sinon spies', function () { + this.sinonSpies.forEach(spy => spy.restore()); + }); + + after('clear data', () => { + window.VASTPlayer = null; + }); + + it('should return an ad with valid renderer', function () { + const serverRequest = examples.serverRequest_video_outstream; + const serverResponse = examples.serverResponse_video_outstream; + + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].renderer).to.be.an('object'); + }); + + it('should append a command to the ad rendering queue when executing the renderer', function (done) { + const serverRequest = examples.serverRequest_video_outstream; + const serverResponse = examples.serverResponse_video_outstream; + + const [ad] = spec.interpretResponse(serverResponse, serverRequest); + + this.spyAdRenderingQueue(ad); + + executeAdRenderer(ad, () => { + expect(ad.renderer.push.calledOnce).to.equal(true); + expect(ad.renderer.push.firstCall.args[0]).to.exist.and.to.be.a('function'); + }, done); + }); + }); + }); + + describe('Native', function () { + it('should return an ad when given a valid server response with one bid', function () { + const serverRequest = examples.serverRequest_native; + const serverResponse = examples.serverResponse_native; + const native = JSON.parse(serverResponse.body.seatbid[0].bid[0].adm).native; + const {link, assets} = native; + const ads = spec.interpretResponse(serverResponse, serverRequest); + + expect(ads).to.be.an('array').and.to.have.length(1); + expect(ads[0].requestId).to.exist.and.to.be.a('string').and.to.equal(serverRequest._adot_internal.impressions[0].bidId); + expect(ads[0].creativeId).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(ads[0].cpm).to.exist.and.to.be.a('number').and.to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(ads[0].currency).to.exist.and.to.be.a('string').and.to.equal(serverResponse.body.cur); + expect(ads[0].netRevenue).to.exist.and.to.be.a('boolean').and.to.equal(true); + expect(ads[0].ttl).to.exist.and.to.be.a('number').and.to.equal(10); + expect(ads[0].mediaType).to.exist.and.to.be.a('string').and.to.equal('native'); + expect(ads[0].native).to.exist.and.to.be.an('object'); + expect(Object.keys(ads[0].native)).to.have.length(10); + expect(ads[0].native.title).to.equal(assets[0].title.text); + expect(ads[0].native.icon.url).to.equal(assets[1].img.url); + expect(ads[0].native.icon.width).to.equal(assets[1].img.w); + expect(ads[0].native.icon.height).to.equal(assets[1].img.h); + expect(ads[0].native.image.url).to.equal(assets[2].img.url); + expect(ads[0].native.image.width).to.equal(assets[2].img.w); + expect(ads[0].native.image.height).to.equal(assets[2].img.h); + expect(ads[0].native.sponsoredBy).to.equal(assets[3].data.value); + expect(ads[0].native.body).to.equal(assets[4].data.value); + expect(ads[0].native.cta).to.equal(assets[5].data.value); + expect(ads[0].native.clickUrl).to.equal(link.url); + }); + }); + }); +}); 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 6137d641cdf..5e4bcce1fe6 100644 --- a/test/spec/modules/adpod_spec.js +++ b/test/spec/modules/adpod_spec.js @@ -1,10 +1,10 @@ -import * as utils from 'src/utils'; -import { config } from 'src/config'; -import * as videoCache from 'src/videoCache'; -import * as auction from 'src/auction'; -import { ADPOD } from 'src/mediaTypes'; +import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; +import * as videoCache from 'src/videoCache.js'; +import * as auction from 'src/auction.js'; +import { ADPOD } from 'src/mediaTypes.js'; -import { callPrebidCacheHook, checkAdUnitSetupHook, checkVideoBidSetupHook, adpodSetConfig, sortByPricePerSecond } from 'modules/adpod'; +import { callPrebidCacheHook, checkAdUnitSetupHook, checkVideoBidSetupHook, adpodSetConfig, sortByPricePerSecond } from 'modules/adpod.js'; let expect = require('chai').expect; @@ -138,7 +138,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 300, durationRangeSec: [15, 30, 45], requireExactDuration: false @@ -220,7 +220,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 120, durationRangeSec: [15, 30], requireExactDuration: false @@ -282,7 +282,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 120, durationRangeSec: [15, 30], requireExactDuration: true @@ -376,7 +376,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 45, durationRangeSec: [15, 30], requireExactDuration: false @@ -465,7 +465,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 45, durationRangeSec: [15, 30], requireExactDuration: false @@ -525,7 +525,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 45, durationRangeSec: [15, 30], requireExactDuration: false @@ -602,7 +602,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 120, durationRangeSec: [15, 30, 45], requireExactDuration: false @@ -675,7 +675,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 120, durationRangeSec: [15, 30, 45], requireExactDuration: false @@ -748,7 +748,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 45, durationRangeSec: [15, 30], requireExactDuration: false @@ -826,7 +826,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 300, durationRangeSec: [15, 30, 45], requireExactDuration: false @@ -922,7 +922,7 @@ describe('adpod.js', function () { }, video: { context: 'adpod', - playerSize: [300, 250], + playerSize: [[300, 250]], durationRangeSec: [15, 30, 45], adPodDurationSec: 300 } @@ -941,7 +941,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 300], + playerSize: [[300, 300]], adPodDurationSec: 360, durationRangeSec: [15, 30, 45], requireExactDuration: true @@ -981,7 +981,7 @@ describe('adpod.js', function () { durationBucket: 15 }, meta: { - iabSubCatId: 'testCategory_123' + primaryCatId: 'testCategory_123' }, vastXml: 'test XML here' }; @@ -989,7 +989,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 400], + playerSize: [[300, 400]], durationRangeSec: [15, 45], requireExactDuration: false, adPodDurationSec: 300 @@ -1000,7 +1000,7 @@ describe('adpod.js', function () { mediaTypes: { video: { context: ADPOD, - playerSize: [300, 400], + playerSize: [[300, 400]], durationRangeSec: [15, 30, 45, 60], requireExactDuration: true, adPodDurationSec: 300 @@ -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/adponeBidAdapter_spec.js b/test/spec/modules/adponeBidAdapter_spec.js index 04cc169f4c8..737f1c284e1 100644 --- a/test/spec/modules/adponeBidAdapter_spec.js +++ b/test/spec/modules/adponeBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; -import { spec } from 'modules/adponeBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; -import * as utils from 'src/utils'; +import { spec } from 'modules/adponeBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; +import * as utils from 'src/utils.js'; const EMPTY_ARRAY = []; describe('adponeBidAdapter', function () { diff --git a/test/spec/modules/adprimeBidAdapter_spec.js b/test/spec/modules/adprimeBidAdapter_spec.js new file mode 100644 index 00000000000..3508a1175a6 --- /dev/null +++ b/test/spec/modules/adprimeBidAdapter_spec.js @@ -0,0 +1,270 @@ +import {expect} from 'chai'; +import {spec} from '../../../modules/adprimeBidAdapter.js'; +import { BANNER, VIDEO } from '../../../src/mediaTypes.js'; + +describe('AdprimebBidAdapter', function () { + const bid = { + bidId: '23fhj33i987f', + bidder: 'adprime', + 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://delta.adprime.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', 'keywords'); + 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; + }); + }); +}); 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 1787816fac2..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'; -import {newBidder} from 'src/adapters/bidderFactory'; - -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/aduptechBidAdapter_spec.js b/test/spec/modules/aduptechBidAdapter_spec.js index 153f6a2c5e9..1e39e0cfc8b 100644 --- a/test/spec/modules/aduptechBidAdapter_spec.js +++ b/test/spec/modules/aduptechBidAdapter_spec.js @@ -10,8 +10,8 @@ import { extractSizesFromBidRequest, extractTopWindowReferrerFromBidRequest, extractTopWindowUrlFromBidRequest -} from '../../../modules/aduptechBidAdapter'; -import { newBidder } from '../../../src/adapters/bidderFactory'; +} from '../../../modules/aduptechBidAdapter.js'; +import { newBidder } from '../../../src/adapters/bidderFactory.js'; describe('AduptechBidAdapter', () => { describe('extractGdprFromBidderRequest', () => { diff --git a/test/spec/modules/advangelistsBidAdapter_spec.js b/test/spec/modules/advangelistsBidAdapter_spec.js index fbdfc9f30ee..2b9615fb572 100755 --- a/test/spec/modules/advangelistsBidAdapter_spec.js +++ b/test/spec/modules/advangelistsBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/advangelistsBidAdapter'; -import { BANNER, VIDEO } from 'src/mediaTypes'; +import { spec } from 'modules/advangelistsBidAdapter.js'; +import { BANNER, VIDEO } from 'src/mediaTypes.js'; describe('advangelistsBidAdapter', function () { let bidRequests; diff --git a/test/spec/modules/advenueBidAdapter_spec.js b/test/spec/modules/advenueBidAdapter_spec.js index f00b9a9f680..2d7739361b4 100644 --- a/test/spec/modules/advenueBidAdapter_spec.js +++ b/test/spec/modules/advenueBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from '../../../modules/advenueBidAdapter'; +import {spec} from '../../../modules/advenueBidAdapter.js'; describe('AdvenueAdapter', function () { let bid = { diff --git a/test/spec/modules/advertlyBidAdapter_spec.js b/test/spec/modules/advertlyBidAdapter_spec.js index 8705a254377..7825f11948a 100755 --- a/test/spec/modules/advertlyBidAdapter_spec.js +++ b/test/spec/modules/advertlyBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/advertlyBidAdapter'; +import { spec } from 'modules/advertlyBidAdapter.js'; const ENDPOINT = 'https://api.advertly.com/www/admin/plugins/Prebid/getAd.php'; diff --git a/test/spec/modules/adxcgAnalyticsAdapter_spec.js b/test/spec/modules/adxcgAnalyticsAdapter_spec.js index 2c495370a57..a796e7e966d 100644 --- a/test/spec/modules/adxcgAnalyticsAdapter_spec.js +++ b/test/spec/modules/adxcgAnalyticsAdapter_spec.js @@ -1,7 +1,7 @@ -import adxcgAnalyticsAdapter from 'modules/adxcgAnalyticsAdapter'; +import adxcgAnalyticsAdapter from 'modules/adxcgAnalyticsAdapter.js'; import { expect } from 'chai'; import adapterManager from 'src/adapterManager.js'; -import { server } from 'test/mocks/xhr'; +import { server } from 'test/mocks/xhr.js'; let events = require('src/events'); let constants = require('src/constants.json'); diff --git a/test/spec/modules/adxcgBidAdapter_spec.js b/test/spec/modules/adxcgBidAdapter_spec.js index 3e73479259c..306914960c3 100644 --- a/test/spec/modules/adxcgBidAdapter_spec.js +++ b/test/spec/modules/adxcgBidAdapter_spec.js @@ -1,7 +1,6 @@ import {expect} from 'chai'; -import * as url from 'src/url'; -import {spec} from 'modules/adxcgBidAdapter'; -import {deepClone} from '../../../src/utils'; +import {spec} from 'modules/adxcgBidAdapter.js'; +import {deepClone, parseUrl} from 'src/utils.js'; describe('AdxcgAdapter', function () { let bidBanner = { @@ -119,7 +118,7 @@ describe('AdxcgAdapter', function () { let request = spec.buildRequests([bidBanner]); expect(request).to.exist; expect(request.method).to.equal('GET'); - let parsedRequestUrl = url.parse(request.url); + let parsedRequestUrl = parseUrl(request.url); expect(parsedRequestUrl.hostname).to.equal('hbps.adxcg.net'); expect(parsedRequestUrl.pathname).to.equal('/get/adi'); @@ -152,7 +151,7 @@ describe('AdxcgAdapter', function () { let request = spec.buildRequests([bidVideo]); expect(request).to.exist; expect(request.method).to.equal('GET'); - let parsedRequestUrl = url.parse(request.url); + let parsedRequestUrl = parseUrl(request.url); expect(parsedRequestUrl.hostname).to.equal('hbps.adxcg.net'); expect(parsedRequestUrl.pathname).to.equal('/get/adi'); @@ -191,7 +190,7 @@ describe('AdxcgAdapter', function () { let request = spec.buildRequests([bidNative]); expect(request).to.exist; expect(request.method).to.equal('GET'); - let parsedRequestUrl = url.parse(request.url); + let parsedRequestUrl = parseUrl(request.url); expect(parsedRequestUrl.hostname).to.equal('hbps.adxcg.net'); expect(parsedRequestUrl.pathname).to.equal('/get/adi'); @@ -229,7 +228,7 @@ describe('AdxcgAdapter', function () { consentString: 'consentDataString' } }); - let parsedRequestUrl = url.parse(request.url); + let parsedRequestUrl = parseUrl(request.url); let query = parsedRequestUrl.search; expect(query.gdpr).to.equal('1'); @@ -243,7 +242,7 @@ describe('AdxcgAdapter', function () { consentString: 'consentDataString' } }); - let parsedRequestUrl = url.parse(request.url); + let parsedRequestUrl = parseUrl(request.url); let query = parsedRequestUrl.search; expect(query.gdpr).to.be.undefined; @@ -258,7 +257,7 @@ describe('AdxcgAdapter', function () { it('should send pubcid if available', function () { let request = spec.buildRequests(bid, bidderRequests); - let parsedRequestUrl = url.parse(request.url); + let parsedRequestUrl = parseUrl(request.url); let query = parsedRequestUrl.search; expect(query.pubcid).to.equal('pubcidabcd'); }); @@ -272,7 +271,7 @@ describe('AdxcgAdapter', function () { it('should send pubcid if available', function () { let request = spec.buildRequests(bid, bidderRequests); - let parsedRequestUrl = url.parse(request.url); + let parsedRequestUrl = parseUrl(request.url); let query = parsedRequestUrl.search; expect(query.tdid).to.equal('tdidabcd'); }); @@ -286,7 +285,7 @@ describe('AdxcgAdapter', function () { it('should send pubcid if available', function () { let request = spec.buildRequests(bid, bidderRequests); - let parsedRequestUrl = url.parse(request.url); + let parsedRequestUrl = parseUrl(request.url); let query = parsedRequestUrl.search; expect(query.id5id).to.equal('id5idsample'); }); @@ -300,7 +299,7 @@ describe('AdxcgAdapter', function () { it('should send pubcid if available', function () { let request = spec.buildRequests(bid, bidderRequests); - let parsedRequestUrl = url.parse(request.url); + let parsedRequestUrl = parseUrl(request.url); let query = parsedRequestUrl.search; expect(query.idl_env).to.equal('idl_envsample'); }); 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 c6e448fdf6a..d2d4e10c17f 100644 --- a/test/spec/modules/adyoulikeBidAdapter_spec.js +++ b/test/spec/modules/adyoulikeBidAdapter_spec.js @@ -1,8 +1,7 @@ import { expect } from 'chai'; -import { parse } from '../../../src/url'; -import { spec } from 'modules/adyoulikeBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/adyoulikeBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('Adyoulike Adapter', function () { const canonicalUrl = 'https://canonical.url/?t=%26'; @@ -276,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/ajaBidAdapter_spec.js b/test/spec/modules/ajaBidAdapter_spec.js index 4b78711f46f..80ecab764e8 100644 --- a/test/spec/modules/ajaBidAdapter_spec.js +++ b/test/spec/modules/ajaBidAdapter_spec.js @@ -1,5 +1,5 @@ -import { spec } from 'modules/ajaBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/ajaBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const ENDPOINT = 'https://ad.as.amanad.adtdp.com/v2/prebid'; diff --git a/test/spec/modules/amxBidAdapter_spec.js b/test/spec/modules/amxBidAdapter_spec.js new file mode 100644 index 00000000000..790f3bf2581 --- /dev/null +++ b/test/spec/modules/amxBidAdapter_spec.js @@ -0,0 +1,384 @@ +import * as utils from 'src/utils.js'; +import { expect } from 'chai'; +import { spec } from 'modules/amxBidAdapter.js'; +import { BANNER, VIDEO } from 'src/mediaTypes.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 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', () => { + 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) + }); + + 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, + aw: 300, + ah: 250, + tf: 0, + vr: false + }); + expect(data.m[sampleRequestId + '_2']).to.deep.equal({ + av: true, + aw: 300, + 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({ + 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 ce8a34509c4..cca175c3388 100644 --- a/test/spec/modules/aniviewBidAdapter_spec.js +++ b/test/spec/modules/aniviewBidAdapter_spec.js @@ -1,5 +1,5 @@ -import { spec } from 'modules/aniviewBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/aniviewBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const { expect } = require('chai'); describe('ANIVIEW Bid Adapter Test', function () { @@ -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'); @@ -180,4 +178,22 @@ describe('ANIVIEW Bid Adapter Test', function () { 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'); + }); + }); }); diff --git a/test/spec/modules/aolBidAdapter_spec.js b/test/spec/modules/aolBidAdapter_spec.js index dd624222d69..dd10a57bbfe 100644 --- a/test/spec/modules/aolBidAdapter_spec.js +++ b/test/spec/modules/aolBidAdapter_spec.js @@ -1,7 +1,7 @@ import {expect} from 'chai'; -import * as utils from 'src/utils'; -import {spec} from 'modules/aolBidAdapter'; -import {config} from 'src/config'; +import * as utils from 'src/utils.js'; +import {spec} from 'modules/aolBidAdapter.js'; +import {config} from 'src/config.js'; const DEFAULT_AD_CONTENT = ''; diff --git a/test/spec/modules/appierAnalyticsAdapter_spec.js b/test/spec/modules/appierAnalyticsAdapter_spec.js index cf47f31afe4..cd026f64d49 100644 --- a/test/spec/modules/appierAnalyticsAdapter_spec.js +++ b/test/spec/modules/appierAnalyticsAdapter_spec.js @@ -1,7 +1,7 @@ import { appierAnalyticsAdapter, getCpmInUsd, parseBidderCode, parseAdUnitCode, ANALYTICS_VERSION, BIDDER_STATUS -} from 'modules/appierAnalyticsAdapter'; +} from 'modules/appierAnalyticsAdapter.js'; import {expect} from 'chai'; const events = require('src/events'); const constants = require('src/constants.json'); diff --git a/test/spec/modules/appierBidAdapter_spec.js b/test/spec/modules/appierBidAdapter_spec.js index c7fc5744d1c..5b6ccf14162 100644 --- a/test/spec/modules/appierBidAdapter_spec.js +++ b/test/spec/modules/appierBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; -import { spec, API_SERVERS_MAP, ADAPTER_VERSION } from 'modules/appierBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; -import { config } from 'src/config'; +import { spec, API_SERVERS_MAP, ADAPTER_VERSION } from 'modules/appierBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import { config } from 'src/config.js'; describe('AppierAdapter', function () { const adapter = newBidder(spec); diff --git a/test/spec/modules/appnexusBidAdapter_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js index 5365b0ac529..7e985045c45 100644 --- a/test/spec/modules/appnexusBidAdapter_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -1,10 +1,10 @@ import { expect } from 'chai'; -import { spec } from 'modules/appnexusBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; -import * as bidderFactory from 'src/adapters/bidderFactory'; -import { auctionManager } from 'src/auctionManager'; -import { deepClone } from 'src/utils'; -import { config } from 'src/config'; +import { spec } from 'modules/appnexusBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import * as bidderFactory from 'src/adapters/bidderFactory.js'; +import { auctionManager } from 'src/auctionManager.js'; +import { deepClone } from 'src/utils.js'; +import { config } from 'src/config.js'; const ENDPOINT = 'https://ib.adnxs.com/ut/v3/prebid'; @@ -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); @@ -164,6 +182,7 @@ describe('AppNexusAdapter', function () { const payload = JSON.parse(request.data); expect(payload.tags[0].ad_types).to.deep.equal(['video']); + expect(payload.tags[0].hb_source).to.deep.equal(1); }); it('sends bid request to ENDPOINT via POST', function () { @@ -193,6 +212,7 @@ describe('AppNexusAdapter', function () { id: 123, minduration: 100 }); + expect(payload.tags[0].hb_source).to.deep.equal(1); }); it('should add video property when adUnit includes a renderer', function () { @@ -228,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 }); }); @@ -256,7 +276,7 @@ describe('AppNexusAdapter', function () { expect(payload.user).to.exist; expect(payload.user).to.deep.equal({ - externalUid: '123', + external_uid: '123', }); }); @@ -417,6 +437,44 @@ describe('AppNexusAdapter', function () { expect(payload3.tags.length).to.equal(15); }); + it('should contain hb_source value for adpod', function() { + let bidRequest = Object.assign({}, + bidRequests[0], + { + params: { placementId: '14542875' } + }, + { + mediaTypes: { + video: { + context: 'adpod', + playerSize: [640, 480], + adPodDurationSec: 300, + durationRangeSec: [15, 30], + } + } + } + ); + const request = spec.buildRequests([bidRequest])[0]; + const payload = JSON.parse(request.data); + expect(payload.tags[0].hb_source).to.deep.equal(7); + }); + + 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: 13144370 + } + } + ); + const request = spec.buildRequests([bidRequest]); + const payload = JSON.parse(request.data); + expect(payload.tags[0].hb_source).to.deep.equal(1); + }); + it('adds brand_category_exclusion to request when set', function() { let bidRequest = Object.assign({}, bidRequests[0]); sinon @@ -480,6 +538,7 @@ describe('AppNexusAdapter', function () { 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 () { @@ -583,6 +642,7 @@ describe('AppNexusAdapter', function () { bidderRequest.bids = bidRequests; const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.options).to.be.empty; const payload = JSON.parse(request.data); expect(payload.gdpr_consent).to.exist; @@ -678,22 +738,6 @@ describe('AppNexusAdapter', function () { }); }); - it('should populate tpids array when userId is available', function () { - const bidRequest = Object.assign({}, bidRequests[0], { - userId: { - criteortus: { - appnexus: { - userid: '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: { @@ -737,6 +781,54 @@ describe('AppNexusAdapter', function () { config.getConfig.restore(); }); + + it('should set withCredentials to false if purpose 1 consent is not given', function () { + let consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; + let bidderRequest = { + 'bidderCode': 'appnexus', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gdprConsent': { + consentString: consentString, + gdprApplies: true, + apiVersion: 2, + vendorData: { + purpose: { + consents: { + 1: false + } + } + } + } + }; + bidderRequest.bids = bidRequests; + + 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 () { @@ -1032,17 +1124,29 @@ describe('AppNexusAdapter', function () { 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].ad_type = 'video'; + responseWithDeal.tags[0].ads[0].deal_priority = 5; responseWithDeal.tags[0].ads[0].deal_code = '123'; + responseWithDeal.tags[0].ads[0].rtb.video = { + duration_ms: 1500, + player_width: 640, + player_height: 340, + }; let bidderRequest = { bids: [{ bidId: '3db3773286ee59', - adUnitCode: 'code' + adUnitCode: 'code', + mediaTypes: { + video: { + context: 'adpod' + } + } }] } let result = spec.interpretResponse({ body: responseWithDeal }, {bidderRequest}); expect(Object.keys(result[0].appnexus)).to.include.members(['buyerMemberId', 'dealPriority', 'dealCode']); + expect(result[0].video.dealTier).to.equal(5); }); it('should add advertiser id', function() { diff --git a/test/spec/modules/astraoneBidAdapter_spec.js b/test/spec/modules/astraoneBidAdapter_spec.js index cd80e742b7d..e422f64b570 100644 --- a/test/spec/modules/astraoneBidAdapter_spec.js +++ b/test/spec/modules/astraoneBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai' -import { spec } from 'modules/astraoneBidAdapter' +import { spec } from 'modules/astraoneBidAdapter.js' function getSlotConfigs(mediaTypes, params) { return { diff --git a/test/spec/modules/atomxBidAdapter_spec.js b/test/spec/modules/atomxBidAdapter_spec.js index 782619d04db..d798bd6308c 100644 --- a/test/spec/modules/atomxBidAdapter_spec.js +++ b/test/spec/modules/atomxBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/atomxBidAdapter'; +import { spec } from 'modules/atomxBidAdapter.js'; describe('atomxAdapterTest', function () { describe('bidRequestValidity', function () { diff --git a/test/spec/modules/atsAnalyticsAdapter_spec.js b/test/spec/modules/atsAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..849ccf88c51 --- /dev/null +++ b/test/spec/modules/atsAnalyticsAdapter_spec.js @@ -0,0 +1,208 @@ +import atsAnalyticsAdapter from '../../../modules/atsAnalyticsAdapter.js'; +import { expect } from 'chai'; +import adapterManager from 'src/adapterManager.js'; +import {server} from '../../mocks/xhr.js'; +import {checkUserBrowser, browserIsChrome, browserIsEdge, browserIsSafari, browserIsFirefox} from '../../../modules/atsAnalyticsAdapter.js'; +let events = require('src/events'); +let constants = require('src/constants.json'); + +describe('ats analytics adapter', function () { + beforeEach(function () { + sinon.stub(events, 'getEvents').returns([]); + }); + + afterEach(function () { + events.getEvents.restore(); + atsAnalyticsAdapter.disableAnalytics(); + }); + + describe('track', function () { + it('builds and sends request and response data', function () { + sinon.spy(atsAnalyticsAdapter, 'track'); + + let initOptions = { + pid: '10433394', + host: 'https://example.com/dev', + }; + let auctionTimestamp = 1496510254326; + + // prepare general auction - request + let bidRequest = { + 'bidderCode': 'appnexus', + 'auctionStart': 1580739265161, + 'bids': [{ + 'bidder': 'appnexus', + 'params': { + 'placementId': '10433394' + }, + 'userId': { + 'idl_env': 'AmThEbO1ssIWjrNdU4noT4ZFBILSVBBYHbipOYt_JP40e5nZdXns2g' + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'transactionId': '2f481ff1-8d20-4c28-8e36-e384e9e3eec6', + 'sizes': '300x250,300x600', + 'bidId': '30c77d079cdf17' + }], + 'refererInfo': { + 'referer': 'https://example.com/dev' + }, + 'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7', + }; + // prepare general auction - response + let bidResponse = { + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '2eddfdc0c791dc', + 'mediaType': 'banner', + 'source': 'client', + 'requestId': '30c77d079cdf17', + 'cpm': 0.5, + 'creativeId': 29681110, + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 300, + 'auctionId': 'a5b849e5-87d7-4205-8300-d063084fcfb7', + 'responseTimestamp': 1580739791978, + 'requestTimestamp': 1580739265164, + 'bidder': 'appnexus', + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'timeToRespond': 2510, + 'size': '300x250' + }; + + // what we expect after general auction + let expectedAfterBid = { + 'Data': [{ + 'has_envelope': true, + 'bidder': 'appnexus', + 'bid_id': '30c77d079cdf17', + 'auction_id': 'a5b849e5-87d7-4205-8300-d063084fcfb7', + 'user_browser': checkUserBrowser(), + 'user_platform': navigator.platform, + 'auction_start': '2020-02-03T14:14:25.161Z', + 'domain': window.location.hostname, + 'pid': '10433394', + 'response_time_stamp': '2020-02-03T14:23:11.978Z', + 'currency': 'USD', + 'cpm': 0.5, + 'net_revenue': true + }] + }; + + // lets simulate that some bidders timeout + let bidTimeoutArgsV1 = [ + { + bidId: '2baa51527bd015', + bidder: 'bidderOne', + adUnitCode: '/19968336/header-bid-tag-0', + auctionId: '66529d4c-8998-47c2-ab3e-5b953490b98f' + }, + { + bidId: '6fe3b4c2c23092', + bidder: 'bidderTwo', + adUnitCode: '/19968336/header-bid-tag-0', + auctionId: '66529d4c-8998-47c2-ab3e-5b953490b98f' + } + ]; + + adapterManager.registerAnalyticsAdapter({ + code: 'atsAnalytics', + adapter: atsAnalyticsAdapter + }); + + adapterManager.enableAnalytics({ + provider: 'atsAnalytics', + options: initOptions + }); + + // Step 1: Send auction init event + events.emit(constants.EVENTS.AUCTION_INIT, { + timestamp: auctionTimestamp + }); + // 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, {}); + + let requests = server.requests.filter(req => { + return req.url.indexOf(initOptions.host) > -1; + }); + + expect(requests.length).to.equal(1); + + let realAfterBid = JSON.parse(requests[0].requestBody); + + // Step 6: assert real data after bid and expected data + expect(realAfterBid['Data']).to.deep.equal(expectedAfterBid['Data']); + + // check that the host and publisher ID is configured via options + 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 index d92db9f4b73..04694731981 100644 --- a/test/spec/modules/audienceNetworkBidAdapter_spec.js +++ b/test/spec/modules/audienceNetworkBidAdapter_spec.js @@ -3,8 +3,8 @@ */ import { expect } from 'chai'; -import { spec } from 'modules/audienceNetworkBidAdapter'; -import * as utils from 'src/utils'; +import { spec } from 'modules/audienceNetworkBidAdapter.js'; +import * as utils from 'src/utils.js'; const { code, diff --git a/test/spec/modules/audiencerunBidAdapter_spec.js b/test/spec/modules/audiencerunBidAdapter_spec.js new file mode 100644 index 00000000000..826944abaf5 --- /dev/null +++ b/test/spec/modules/audiencerunBidAdapter_spec.js @@ -0,0 +1,204 @@ +import { expect } from 'chai'; +import { spec } from 'modules/audiencerunBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; + +const ENDPOINT = 'https://d.audiencerun.com/prebid'; + +const BID_SERVER_RESPONSE = { + body: { + bid: [ + { + 'bidId': '51ef8751f9aead', + 'zoneId': '12345abcde', + 'adId': '1234', + 'crid': '5678', + 'cpm': 8.021951999999999999, + 'currency': 'USD', + 'w': 728, + 'h': 90, + 'isNet': false, + 'buying_type': 'rtb', + 'syncUrl': 'https://ac.audiencerun.com/f/sync.html', + 'adm': '' + } + ] + } +}; + +describe('AudienceRun bid adapter tests', 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': 'audiencerun', + 'params': { + 'zoneId': '12345abcde' + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'creativeId': 'er2ee' + }; + + it('should return true when required params found', function() { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return true when zoneId is valid', function() { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + 'zoneId': '12345abcde' + }; + + 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() { + let bidRequests = [ + { + 'bidder': 'audiencerun', + 'bidId': '51ef8751f9aead', + 'params': { + 'zoneId': '12345abcde' + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'mediaTypes': { + 'banner': { + 'sizes': [[320, 50], [300, 250], [300, 600]] + } + }, + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1 + } + ]; + + it('sends a valid bid request to ENDPOINT via POST', function() { + const request = spec.buildRequests(bidRequests, { + 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: { + canonicalUrl: 'https://example.com/canonical', + referer: 'https://example.com' + } + }); + + expect(request.url).to.equal(ENDPOINT); + expect(request.method).to.equal('POST'); + + const payload = JSON.parse(request.data); + expect(payload.gdpr).to.exist; + + expect(payload.bids).to.exist.and.to.be.an('array').and.to.have.lengthOf(1); + expect(payload.referer).to.exist; + + const bid = payload.bids[0]; + expect(bid).to.exist; + expect(bid).to.have.property('bidId'); + expect(bid).to.have.property('zoneId'); + expect(bid).to.have.property('sizes'); + expect(bid.sizes[0].w).to.be.a('number'); + expect(bid.sizes[0].h).to.be.a('number'); + }); + + it('should send GDPR to endpoint and honor gdprApplies value', function() { + let consentString = 'bogusConsent'; + let bidderRequest = { + 'gdprConsent': { + 'consentString': consentString, + 'gdprApplies': true + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.gdpr).to.exist; + expect(payload.gdpr.consent).to.equal(consentString); + expect(payload.gdpr.applies).to.equal(true); + + let bidderRequest2 = { + 'gdprConsent': { + 'consentString': consentString, + 'gdprApplies': false + } + }; + + const request2 = spec.buildRequests(bidRequests, bidderRequest2); + const payload2 = JSON.parse(request2.data); + + expect(payload2.gdpr).to.exist; + expect(payload2.gdpr.consent).to.equal(consentString); + expect(payload2.gdpr.applies).to.equal(false); + }); + }); + + describe('interpretResponse', function () { + const expectedResponse = [{ + 'requestId': '51ef8751f9aead', + 'adId': '12345abcde', + 'cpm': 8.021951999999999999, + 'width': '728', + 'height': '90', + 'creativeId': '5678', + 'currency': 'USD', + 'netRevenue': false, + 'ttl': 300, + 'ad': '', + 'mediaType': 'banner' + }]; + + it('should get the correct bid response by display ad', function () { + let result = spec.interpretResponse(BID_SERVER_RESPONSE); + expect(Object.keys(result[0])).to.have.members(Object.keys(expectedResponse[0])); + }); + + it('handles empty bid response', function () { + const response = { + body: {} + }; + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); + }); + }); + + describe('getUserSyncs', function () { + const serverResponses = [ BID_SERVER_RESPONSE ]; + const syncOptions = { iframeEnabled: true }; + + it('should return empty if no server responses', function() { + const syncs = spec.getUserSyncs(syncOptions, []); + expect(syncs).to.deep.equal([]) + }); + + it('should return user syncs', function () { + const syncs = spec.getUserSyncs(syncOptions, serverResponses); + expect(syncs).to.deep.equal([{type: 'iframe', url: 'https://ac.audiencerun.com/f/sync.html'}]) + }); + }); +}); diff --git a/test/spec/modules/automatadBidAdapter_spec.js b/test/spec/modules/automatadBidAdapter_spec.js new file mode 100644 index 00000000000..788fd3aefc4 --- /dev/null +++ b/test/spec/modules/automatadBidAdapter_spec.js @@ -0,0 +1,144 @@ +import { expect } from 'chai' +import { spec } from 'modules/automatadBidAdapter.js' +import { newBidder } from 'src/adapters/bidderFactory.js' + +describe('automatadBidAdapter', function () { + const adapter = newBidder(spec) + + let bidRequest = { + bidder: 'automatad', + params: {siteId: '123ad', placementId: '123abc345'}, + mediaTypes: { + banner: { + sizes: [[300, 600]], + } + }, + adUnitCode: 'some-ad-unit-code', + transactionId: '1465569e-52cc-4c36-88a1-7174cfef4b44', + sizes: [[300, 600]], + bidId: '123abc', + bidderRequestId: '3213887463c059', + auctionId: 'abc-123', + src: 'client', + bidRequestsCount: 1 + } + + let expectedResponse = [{ + 'body': { + 'id': 'abc-123', + 'seatbid': [ + { + 'bid': [ + { + 'adm': '', + 'adomain': [ + 'someAdDomain' + ], + 'crid': 123, + 'h': 600, + 'id': 'bid1', + 'impid': '1', + 'nurl': 'https://example/win', + 'price': 0.5, + 'w': 300 + } + ] + } + ] + } + }] + + describe('codes', function () { + it('should return a bidder code of automatad', function () { + expect(spec.code).to.equal('automatad') + }) + it('should alias atd', function () { + expect(spec.aliases.length > 0 && spec.aliases[0] === 'atd').to.be.true + }) + }) + + describe('isBidRequestValid', function () { + let inValidBid = Object.assign({}, bidRequest) + delete inValidBid.params + it('should return true if all params present', function () { + expect(spec.isBidRequestValid(bidRequest)).to.equal(true) + }) + + it('should return false if any parameter missing', function () { + expect(spec.isBidRequestValid(inValidBid)).to.be.false + }) + }) + + describe('buildRequests', function () { + let req = spec.buildRequests([ bidRequest ], { refererInfo: { } }) + let rdata + + it('should return request object', function () { + expect(req).to.not.be.null + }) + + it('should build request data', function () { + expect(req.data).to.not.be.null + }) + + it('should include one request', function () { + rdata = JSON.parse(req.data) + expect(rdata.imp.length).to.equal(1) + }) + + it('should include media types', function () { + let r = rdata.imp[0] + expect(r.media_types !== null).to.be.true + }) + + it('should include all publisher params', function () { + let r = rdata.imp[0] + expect(r.siteID !== null && r.placementID !== null).to.be.true + }) + }) + + describe('interpretResponse', function () { + it('should get the correct bid response', function () { + let result = spec.interpretResponse(expectedResponse[0]) + expect(result).to.be.an('array').that.is.not.empty + }) + + it('handles empty bid response', function () { + let response = { + body: '' + } + let result = spec.interpretResponse(response) + expect(result.length).to.equal(0) + }) + }) + + describe('getUserSyncs', function () { + it('should return iframe sync', function () { + let sync = spec.getUserSyncs() + expect(sync.length).to.equal(1) + expect(sync[0].type === 'iframe') + expect(typeof sync[0].url === 'string') + }) + }) + + describe('onBidWon', function () { + let serverResponses = spec.interpretResponse(expectedResponse[0]) + let wonbid = serverResponses[0] + let ajaxStub + + beforeEach(() => { + ajaxStub = sinon.stub(spec, 'ajaxCall') + }) + + afterEach(() => { + ajaxStub.restore() + }) + + it('Returns true is nurl is good/not blank', function () { + expect(wonbid.nurl).to.not.equal('') + expect(spec.onBidWon(wonbid)).to.be.true + expect(ajaxStub.calledOnce).to.equal(true) + expect(ajaxStub.firstCall.args[0].indexOf('https://')).to.equal(0) + }) + }) +}) diff --git a/test/spec/modules/avocetBidAdapter_spec.js b/test/spec/modules/avocetBidAdapter_spec.js new file mode 100644 index 00000000000..4cfd8ab89d4 --- /dev/null +++ b/test/spec/modules/avocetBidAdapter_spec.js @@ -0,0 +1,165 @@ +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: '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 0b13bdec001..5711e111e30 100644 --- a/test/spec/modules/beachfrontBidAdapter_spec.js +++ b/test/spec/modules/beachfrontBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; import sinon from 'sinon'; -import { spec, VIDEO_ENDPOINT, BANNER_ENDPOINT, OUTSTREAM_SRC, DEFAULT_MIMES } from 'modules/beachfrontBidAdapter'; -import { parse as parseUrl } from 'src/url'; +import { spec, VIDEO_ENDPOINT, BANNER_ENDPOINT, OUTSTREAM_SRC, DEFAULT_MIMES } from 'modules/beachfrontBidAdapter.js'; +import { parseUrl } from 'src/utils.js'; describe('BeachfrontAdapter', function () { let bidRequests; @@ -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/betweenBidAdapter_spec.js b/test/spec/modules/betweenBidAdapter_spec.js index 9323386566d..94db41ba014 100644 --- a/test/spec/modules/betweenBidAdapter_spec.js +++ b/test/spec/modules/betweenBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/betweenBidAdapter'; +import { spec } from 'modules/betweenBidAdapter.js'; describe('betweenBidAdapterTests', function () { it('validate_pub_params', function () { @@ -201,4 +201,24 @@ describe('betweenBidAdapterTests', function () { expect(syncs).to.be.an('array').that.to.have.lengthOf(1); expect(syncs[0]).to.deep.equal({type: 'iframe', url: 'https://ads.betweendigital.com/sspmatch-iframe'}); }); + + it('check sizes', function() { + let bidRequestData = [{ + bidId: 'bid1234', + bidder: 'between', + mediaTypes: { + banner: { + sizes: [[970, 250], [240, 400], [728, 90]] + } + }, + params: { + s: 1112, + }, + }]; + + let request = spec.buildRequests(bidRequestData); + let req_data = request[0].data; + + expect(req_data.sizes).to.deep.equal('970x250%2C240x400%2C728x90'); + }); }); diff --git a/test/spec/modules/bidfluenceBidAdapter_spec.js b/test/spec/modules/bidfluenceBidAdapter_spec.js index 9ce6e808c6b..6b3a0c2b044 100644 --- a/test/spec/modules/bidfluenceBidAdapter_spec.js +++ b/test/spec/modules/bidfluenceBidAdapter_spec.js @@ -1,114 +1,114 @@ -import { expect } from 'chai'; -import { spec } from 'modules/bidfluenceBidAdapter'; - -const BIDDER_CODE = 'bidfluence'; -const PLACEMENT_ID = '1000'; -const PUB_ID = '1000'; -const CONSENT_STRING = 'DUXDSDFSFWRRR8345F=='; - -const validBidRequests = [{ - 'bidder': BIDDER_CODE, - 'params': { - 'placementId': PLACEMENT_ID, - 'publisherId': PUB_ID, - 'reservePrice': 0 - }, - 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250]], - 'bidId': '2b1f23307fb8ef', - 'bidderRequestId': '10edf38ec1a719', - 'auctionId': '1025ba77-5463-4877-b0eb-14b205cb9304' -}]; - -const bidderRequest = { - 'bidderCode': 'bidfluence', - 'auctionId': '1025ba77-5463-4877-b0eb-14b205cb9304', - 'bidderRequestId': '10edf38ec1a719', - 'refererInfo': { - 'numIframes': 0, - 'reachedTop': true, - 'referer': 'test', - 'stack': ['test'] - }, - 'timeout': 1000, - 'gdprConsent': { - 'gdprApplies': true, - 'consentString': CONSENT_STRING, - 'vendorData': '' - } -}; - -bidderRequest.bids = validBidRequests; - -describe('Bidfluence Adapter test', () => { - describe('isBidRequestValid', function () { - it('should return true when required params found', function () { - expect(spec.isBidRequestValid(validBidRequests[0])).to.equal(true); - }); - it('should return the right bidder code', function () { - expect(spec.code).to.eql(BIDDER_CODE); - }); - }); - - describe('buildRequests', function () { - const request = spec.buildRequests(validBidRequests, bidderRequest); - - it('sends bid request to our endpoint via POST', function () { - expect(request.method).to.equal('POST'); - }); - - const payload = JSON.parse(request.data); - - expect(payload.bids[0].bid).to.equal(validBidRequests[0].bidId); - expect(payload.azr).to.equal(true); - expect(payload.ck).to.not.be.undefined; - expect(payload.bids[0].tid).to.equal(PLACEMENT_ID); - expect(payload.bids[0].pid).to.equal(PUB_ID); - expect(payload.bids[0].rp).to.be.a('number'); - expect(payload.re).to.not.be.undefined; - expect(payload.st).to.not.be.undefined; - expect(payload.tz).to.not.be.undefined; - expect(payload.sr).to.not.be.undefined; - expect(payload.vp).to.not.be.undefined; - expect(payload.sdt).to.not.be.undefined; - expect(payload.bids[0].w).to.equal('300'); - expect(payload.bids[0].h).to.equal('250'); - - it('sends gdpr info if exists', function () { - expect(payload.gdpr).to.equal(true); - expect(payload.gdprc).to.equal(CONSENT_STRING); - }); - }); - - describe('interpretResponse', function () { - const response = { - body: { - Bids: - [{ - 'CreativeId': '1000', - 'Cpm': 0.50, - 'Ad': '
', - 'Height': 250, - 'Width': 300 - }] - } - }; - - it('should get correct bid response', function () { - const expectedResponse = [{ - requestId: response.body.Bids[0].BidId, - cpm: response.body.Bids[0].Cpm, - width: response.body.Bids[0].Width, - height: response.body.Bids[0].Height, - creativeId: response.body.Bids[0].CreativeId, - ad: response.body.Bids[0].Ad, - currency: 'USD', - netRevenue: true, - ttl: 360 - }]; - - let result = spec.interpretResponse(response, { 'bidderRequest': validBidRequests[0] }); - expect(result).to.deep.equal(expectedResponse); - }); - }); -}); +import { expect } from 'chai'; +import { spec } from 'modules/bidfluenceBidAdapter.js'; + +const BIDDER_CODE = 'bidfluence'; +const PLACEMENT_ID = '1000'; +const PUB_ID = '1000'; +const CONSENT_STRING = 'DUXDSDFSFWRRR8345F=='; + +const validBidRequests = [{ + 'bidder': BIDDER_CODE, + 'params': { + 'placementId': PLACEMENT_ID, + 'publisherId': PUB_ID, + 'reservePrice': 0 + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250]], + 'bidId': '2b1f23307fb8ef', + 'bidderRequestId': '10edf38ec1a719', + 'auctionId': '1025ba77-5463-4877-b0eb-14b205cb9304' +}]; + +const bidderRequest = { + 'bidderCode': 'bidfluence', + 'auctionId': '1025ba77-5463-4877-b0eb-14b205cb9304', + 'bidderRequestId': '10edf38ec1a719', + 'refererInfo': { + 'numIframes': 0, + 'reachedTop': true, + 'referer': 'test', + 'stack': ['test'] + }, + 'timeout': 1000, + 'gdprConsent': { + 'gdprApplies': true, + 'consentString': CONSENT_STRING, + 'vendorData': '' + } +}; + +bidderRequest.bids = validBidRequests; + +describe('Bidfluence Adapter test', () => { + describe('isBidRequestValid', function () { + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(validBidRequests[0])).to.equal(true); + }); + it('should return the right bidder code', function () { + expect(spec.code).to.eql(BIDDER_CODE); + }); + }); + + describe('buildRequests', function () { + it('sends bid request to our endpoint via POST', function () { + const request = spec.buildRequests(validBidRequests, bidderRequest); + expect(request.method).to.equal('POST'); + const payload = JSON.parse(request.data); + + expect(payload.bids[0].bid).to.equal(validBidRequests[0].bidId); + expect(payload.azr).to.equal(true); + expect(payload.ck).to.not.be.undefined; + expect(payload.bids[0].tid).to.equal(PLACEMENT_ID); + expect(payload.bids[0].pid).to.equal(PUB_ID); + expect(payload.bids[0].rp).to.be.a('number'); + expect(payload.re).to.not.be.undefined; + expect(payload.st).to.not.be.undefined; + expect(payload.tz).to.not.be.undefined; + expect(payload.sr).to.not.be.undefined; + expect(payload.vp).to.not.be.undefined; + expect(payload.sdt).to.not.be.undefined; + expect(payload.bids[0].w).to.equal('300'); + expect(payload.bids[0].h).to.equal('250'); + }); + + it('sends gdpr info if exists', function () { + const request = spec.buildRequests(validBidRequests, bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.gdpr).to.equal(true); + expect(payload.gdprc).to.equal(CONSENT_STRING); + }); + }); + + describe('interpretResponse', function () { + const response = { + body: { + Bids: + [{ + 'CreativeId': '1000', + 'Cpm': 0.50, + 'Ad': '
', + 'Height': 250, + 'Width': 300 + }] + } + }; + + it('should get correct bid response', function () { + const expectedResponse = [{ + requestId: response.body.Bids[0].BidId, + cpm: response.body.Bids[0].Cpm, + width: response.body.Bids[0].Width, + height: response.body.Bids[0].Height, + creativeId: response.body.Bids[0].CreativeId, + ad: response.body.Bids[0].Ad, + currency: 'USD', + netRevenue: true, + ttl: 360 + }]; + + let result = spec.interpretResponse(response, { 'bidderRequest': validBidRequests[0] }); + expect(result).to.deep.equal(expectedResponse); + }); + }); +}); diff --git a/test/spec/modules/bidglassAdapter_spec.js b/test/spec/modules/bidglassAdapter_spec.js index 00a47fc997a..d153430103d 100644 --- a/test/spec/modules/bidglassAdapter_spec.js +++ b/test/spec/modules/bidglassAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/bidglassBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/bidglassBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('Bid Glass Adapter', function () { const adapter = newBidder(spec); diff --git a/test/spec/modules/bidlabBidAdapter_spec.js b/test/spec/modules/bidlabBidAdapter_spec.js new file mode 100644 index 00000000000..cffd43ae6ca --- /dev/null +++ b/test/spec/modules/bidlabBidAdapter_spec.js @@ -0,0 +1,235 @@ +import {expect} from 'chai'; +import {spec} from '../../../modules/bidlabBidAdapter.js'; + +describe('BidlabBidAdapter', function () { + let bid = { + bidId: '23fhj33i987f', + bidder: 'bidlab', + params: { + placementId: 0, + traffic: 'banner' + } + }; + + 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]); + 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://service.bidlab.ai/?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'); + let placement = data['placements'][0]; + expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'sizes'); + expect(placement.placementId).to.equal(0); + expect(placement.bidId).to.equal('23fhj33i987f'); + expect(placement.traffic).to.equal('banner'); + }); + 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 () { + if (spec.noSync) { + expect(userSync).to.be.equal(false); + } else { + 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://service.bidlab.ai/?c=o&m=sync'); + } + }); + }); +}); diff --git a/test/spec/modules/bidphysicsBidAdapter_spec.js b/test/spec/modules/bidphysicsBidAdapter_spec.js index 8c46b8cefa6..fc15c39cf81 100644 --- a/test/spec/modules/bidphysicsBidAdapter_spec.js +++ b/test/spec/modules/bidphysicsBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from 'modules/bidphysicsBidAdapter'; +import {spec} from 'modules/bidphysicsBidAdapter.js'; const REQUEST = { 'bidderCode': 'bidphysics', diff --git a/test/spec/modules/bluebillywigBidAdapter_spec.js b/test/spec/modules/bluebillywigBidAdapter_spec.js new file mode 100644 index 00000000000..73bd4803358 --- /dev/null +++ b/test/spec/modules/bluebillywigBidAdapter_spec.js @@ -0,0 +1,916 @@ +import { expect } from 'chai'; +import { spec } from 'modules/bluebillywigBidAdapter.js'; +import * as bidderFactory from 'src/adapters/bidderFactory.js'; +import { auctionManager } from 'src/auctionManager.js'; +import { deepClone, deepAccess } from 'src/utils.js'; +import { config } from 'src/config.js'; +import { VIDEO } from 'src/mediaTypes.js'; + +const BB_CONSTANTS = { + BIDDER_CODE: 'bluebillywig', + AUCTION_URL: '$$URL_STARTpbs.bluebillywig.com/openrtb2/auction?pub=$$PUBLICATION', + SYNC_URL: '$$URL_STARTpbs.bluebillywig.com/static/cookie-sync.html?pub=$$PUBLICATION', + RENDERER_URL: 'https://$$PUBLICATION.bbvms.com/r/$$RENDERER.js', + DEFAULT_TIMEOUT: 5000, + DEFAULT_TTL: 300, + DEFAULT_WIDTH: 768, + DEFAULT_HEIGHT: 432, + DEFAULT_NET_REVENUE: true +}; + +describe('BlueBillywigAdapter', () => { + describe('isBidRequestValid', () => { + const baseValidBid = { + bidder: BB_CONSTANTS.BIDDER_CODE, + params: { + accountId: 123, + publicationName: 'bbprebid.dev', + rendererCode: 'glorious_renderer', + connections: [ BB_CONSTANTS.BIDDER_CODE ], + bluebillywig: {} + }, + mediaTypes: { + video: { + context: 'outstream' + } + } + }; + + it('should return true when required params found', () => { + expect(spec.isBidRequestValid(baseValidBid)).to.equal(true); + }); + + it('should return false when publicationName is missing', () => { + const bid = deepClone(baseValidBid); + delete bid.params.publicationName; + + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when publicationName is not a string', () => { + const bid = deepClone(baseValidBid); + + bid.params.publicationName = 123; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.publicationName = false; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.publicationName = void (0); + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.publicationName = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when publicationName is formatted poorly', () => { + const bid = deepClone(baseValidBid); + + bid.params.publicationName = 'bb.'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.publicationName = 'bb-test'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.publicationName = '?'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when renderer is not specified', () => { + const bid = deepClone(baseValidBid); + + delete bid.params.rendererCode; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when renderer is not a string', () => { + const bid = deepClone(baseValidBid); + + bid.params.rendererCode = 123; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.rendererCode = false; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.rendererCode = void (0); + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.rendererCode = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when renderer is formatted poorly', () => { + const bid = deepClone(baseValidBid); + + bid.params.rendererCode = 'bb.'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.rendererCode = 'bb-test'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.rendererCode = '?'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when accountId is not specified', () => { + const bid = deepClone(baseValidBid); + + delete bid.params.accountId; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when connections is not specified', () => { + const bid = deepClone(baseValidBid); + + delete bid.params.connections; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when connections is not an array', () => { + const bid = deepClone(baseValidBid); + + bid.params.connections = 123; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.connections = false; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.connections = void (0); + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.connections = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.connections = 'string'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when a connection is missing', () => { + const bid = deepClone(baseValidBid); + + bid.params.connections.push('potatoes'); + expect(spec.isBidRequestValid(bid)).to.equal(false); + + bid.params.connections.pop(); + + delete bid.params[BB_CONSTANTS.BIDDER_CODE]; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail if bid has no mediaTypes', () => { + const bid = deepClone(baseValidBid); + + delete bid.mediaTypes; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail if bid has no mediaTypes.video', () => { + const bid = deepClone(baseValidBid); + + delete bid.mediaTypes[VIDEO]; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail if bid has no mediaTypes.video.context', () => { + const bid = deepClone(baseValidBid); + + delete bid.mediaTypes[VIDEO].context; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should fail if mediaTypes.video.context is not "outstream"', () => { + const bid = deepClone(baseValidBid); + + bid.mediaTypes[VIDEO].context = 'instream'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', () => { + const publicationName = 'bbprebid.dev'; + const rendererCode = 'glorious_renderer'; + + const baseValidBid = { + bidder: BB_CONSTANTS.BIDDER_CODE, + params: { + accountId: 123, + publicationName: publicationName, + rendererCode: rendererCode, + connections: [ BB_CONSTANTS.BIDDER_CODE ], + bluebillywig: {} + }, + mediaTypes: { + video: { + context: 'outstream' + } + } + }; + + const baseValidBidRequests = [baseValidBid]; + + const validBidderRequest = { + auctionId: '12abc345-67d8-9012-e345-6f78901a2b34', + auctionStart: 1585918458868, + bidderCode: BB_CONSTANTS.BIDDER_CODE, + bidderRequestId: '1a2345b67c8d9e0', + bids: [{ + adUnitCode: 'ad-unit-test', + auctionId: '12abc345-67d8-9012-e345-6f78901a2b34', + bidId: '1234ab567c89de0', + bidRequestsCount: 1, + bidder: BB_CONSTANTS.BIDDER_CODE, + bidderRequestId: '1a2345b67c8d9e0', + params: baseValidBid.params, + sizes: [[768, 432], [640, 480], [630, 360]], + transactionId: '2b34c5de-f67a-8901-bcd2-34567efabc89' + }], + start: 11585918458869, + timeout: 3000 + }; + + it('sends bid request to AUCTION_URL via POST', () => { + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + expect(request.url).to.equal(`https://pbs.bluebillywig.com/openrtb2/auction?pub=${publicationName}`); + expect(request.method).to.equal('POST'); + }); + + it('sends data as a string', () => { + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + expect(request.data).to.be.a('string'); + }); + + it('sends all bid parameters', () => { + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + expect(request).to.have.all.keys(['bidderRequest', 'data', 'method', 'url']); + }); + + it('builds the base request properly', () => { + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.id).to.equal(validBidderRequest.auctionId); + expect(payload.source).to.be.an('object'); + expect(payload.source.tid).to.equal(validBidderRequest.auctionId); + expect(payload.tmax).to.equal(BB_CONSTANTS.DEFAULT_TIMEOUT); + expect(payload.imp).to.be.an('array'); + expect(payload.test).to.be.a('number'); + expect(payload).to.have.nested.property('ext.prebid.targeting'); + expect(payload.ext.prebid.targeting).to.be.an('object'); + expect(payload.ext.prebid.targeting.includewinners).to.equal(true); + expect(payload.ext.prebid.targeting.includebidderkeys).to.equal(false); + }); + + it('adds an impression to the payload', () => { + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.imp.length).to.equal(1); + }); + + it('adds connections to ext', () => { + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.imp[0].ext).to.have.all.keys(['bluebillywig']); + }); + + it('adds gdpr when present', () => { + const newValidBidderRequest = deepClone(validBidderRequest); + newValidBidderRequest.gdprConsent = { + consentString: 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAAAAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', + gdprApplies: true + }; + + const request = spec.buildRequests(baseValidBidRequests, newValidBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.nested.property('regs.ext.gdpr'); + expect(payload.regs.ext.gdpr).to.be.a('number'); + expect(payload.regs.ext.gdpr).to.equal(1); + expect(payload).to.have.nested.property('user.ext.consent'); + expect(payload.user.ext.consent).to.equal(newValidBidderRequest.gdprConsent.consentString); + }); + + it('sets gdpr to 0 when explicitly gdprApplies: false', () => { + const newValidBidderRequest = deepClone(validBidderRequest); + newValidBidderRequest.gdprConsent = { + gdprApplies: false + }; + + const request = spec.buildRequests(baseValidBidRequests, newValidBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.nested.property('regs.ext.gdpr'); + expect(payload.regs.ext.gdpr).to.be.a('number'); + expect(payload.regs.ext.gdpr).to.equal(0); + }); + + it('adds usp_consent when present', () => { + const newValidBidderRequest = deepClone(validBidderRequest); + newValidBidderRequest.uspConsent = '1YYY'; + + const request = spec.buildRequests(baseValidBidRequests, newValidBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.nested.property('regs.ext.us_privacy'); + expect(payload.regs.ext.us_privacy).to.equal(newValidBidderRequest.uspConsent); + }); + + it('sets coppa to 1 when specified in config', () => { + config.setConfig({'coppa': true}); + + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.nested.property('regs.coppa'); + expect(payload.regs.coppa).to.equal(1); + + config.resetConfig(); + }); + + it('does not set coppa when disabled in the config', () => { + config.setConfig({'coppa': false}); + + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(deepAccess(payload, 'regs.coppa')).to.be.undefined; + + config.resetConfig(); + }); + + it('does not set coppa when not specified in config', () => { + config.resetConfig(); + + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(deepAccess(payload, 'regs.coppa')).to.be.undefined; + }); + + it('should add window size to request by default', () => { + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.nested.property('device.w'); + expect(payload).to.have.nested.property('device.h'); + expect(payload.device.w).to.be.a('number'); + 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' } }); + + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.property('app'); + expect(payload).to.have.nested.property('app.bundle'); + expect(payload).to.have.nested.property('app.domain'); + expect(payload.app.bundle).to.equal('org.prebid.mobile.demoapp'); + expect(payload.app.domain).to.equal('prebid.org'); + + config.resetConfig(); + }); + + it('should add referrerInfo as site when no app is set', () => { + const newValidBidderRequest = deepClone(validBidderRequest); + + newValidBidderRequest.refererInfo = { referer: 'https://www.bluebillywig.com' }; + + const request = spec.buildRequests(baseValidBidRequests, newValidBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.nested.property('site.page'); + expect(payload.site.page).to.equal('https://www.bluebillywig.com'); + }); + + it('should not add referrerInfo as site when app is set', () => { + config.setConfig({ app: { bundle: 'org.prebid.mobile.demoapp', domain: 'prebid.org' } }); + + const newValidBidderRequest = deepClone(validBidderRequest); + newValidBidderRequest.refererInfo = { referer: 'https://www.bluebillywig.com' }; + + const request = spec.buildRequests(baseValidBidRequests, newValidBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.site).to.be.undefined; + config.resetConfig(); + }); + + it('should add device size to request when specified in config', () => { + config.setConfig({ device: { w: 1, h: 1 } }); + + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.nested.property('device.w'); + expect(payload).to.have.nested.property('device.h'); + expect(payload.device.w).to.be.a('number'); + expect(payload.device.h).to.be.a('number'); + expect(payload.device.w).to.equal(1); + expect(payload.device.h).to.equal(1); + + config.resetConfig(); + }); + + it('should set schain on the request when set on config', () => { + const schain = { + validation: 'lax', + config: { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + hp: 1 + } + ] + } + }; + + const newBaseValidBidRequests = deepClone(baseValidBidRequests); + newBaseValidBidRequests[0].schain = schain; + + const request = spec.buildRequests(newBaseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.nested.property('source.ext.schain'); + expect(payload.source.ext.schain).to.deep.equal(schain); + }); + + it('should add currency when specified on the config', () => { + config.setConfig({ currency: { adServerCurrency: 'USD' } }); + + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.property('cur'); + expect(payload.cur).to.eql(['USD']); // NB not equal, eql to check for same array because [1] === [1] fails normally + + config.resetConfig(); + }); + + it('should also take in array for currency on the config', () => { + config.setConfig({ currency: { adServerCurrency: ['USD', 'PHP'] } }); + + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.property('cur'); + expect(payload.cur).to.eql(['USD']); // NB not equal, eql to check for same array because [1] === [1] fails normally + + config.resetConfig(); + }); + + it('should not set cur when currency is not specified on the config', () => { + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.cur).to.be.undefined; + }); + + it('should set user ids when present', () => { + const userId = { tdid: 123 }; + + const newBaseValidBidRequests = deepClone(baseValidBidRequests); + newBaseValidBidRequests[0].userId = { criteoId: 'sample-userid' }; + + const request = spec.buildRequests(newBaseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(payload).to.have.nested.property('user.ext.eids'); + expect(payload.user.ext.eids).to.be.an('array'); + expect(payload.user.ext.eids.length).to.equal(1); + }); + + it('should not set user ids when none present', () => { + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + 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}}; + + const newBaseValidBidRequests = deepClone(baseValidBidRequests); + newBaseValidBidRequests[0].userId = { digitrustid: digiTrust }; + + 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); + }); + + it('should not set digitrust when opted out', () => { + const digiTrust = {data: {id: 'DTID', keyv: 4, privacy: {optout: true}, producer: 'ABC', version: 2}}; + + const newBaseValidBidRequests = deepClone(baseValidBidRequests); + newBaseValidBidRequests[0].userId = { digitrustid: digiTrust }; + + const request = spec.buildRequests(newBaseValidBidRequests, validBidderRequest); + const payload = JSON.parse(request.data); + + expect(deepAccess(payload, 'user.ext.digitrust')).to.be.undefined; + }); + }); + describe('interpretResponse', () => { + const publicationName = 'bbprebid.dev'; + const rendererCode = 'glorious_renderer'; + + const baseValidBid = { + bidder: BB_CONSTANTS.BIDDER_CODE, + params: { + accountId: 123, + publicationName: publicationName, + rendererCode: rendererCode, + connections: [ BB_CONSTANTS.BIDDER_CODE ], + bluebillywig: {} + }, + mediaTypes: { + video: { + context: 'outstream' + } + } + }; + + const baseValidBidRequests = [baseValidBid]; + + const validBidderRequest = { + auctionId: '12abc345-67d8-9012-e345-6f78901a2b34', + auctionStart: 1585918458868, + bidderCode: BB_CONSTANTS.BIDDER_CODE, + bidderRequestId: '1a2345b67c8d9e0', + bids: [{ + adUnitCode: 'ad-unit-test', + auctionId: '12abc345-67d8-9012-e345-6f78901a2b34', + bidId: '1234ab567c89de0', + bidRequestsCount: 1, + bidder: BB_CONSTANTS.BIDDER_CODE, + bidderRequestId: '1a2345b67c8d9e0', + params: baseValidBid.params, + sizes: [[768, 432], [640, 480], [630, 360]], + transactionId: '2b34c5de-f67a-8901-bcd2-34567efabc89' + }], + start: 11585918458869, + timeout: 3000 + }; + + const validResponse = { + id: 'a12abc345-67d8-9012-e345-6f78901a2b34', + seatbid: [ + { + bid: [ + { + id: '1', + impid: '1234ab567c89de0', + price: 1, + adm: '\r\nBB Adserver00:00:51', + adid: '67069817', + adomain: [ + 'bluebillywig.com' + ], + cid: '3535', + crid: '67069817', + w: 1, + h: 1, + publicationName: 'bbprebid', + accountId: 123, + ext: { + prebid: { + targeting: { + hb_bidder: 'bluebillywig', + hb_pb: '1.00', + hb_size: '1x1' + }, + type: 'video' + }, + bidder: { + prebid: { + targeting: { + hb_bidder: 'bluebillywig', + hb_pb: '10.00', + hb_size: '1x1' + }, + type: 'video', + video: { + duration: 51, + primary_category: '' + } + }, + bidder: { + bluebillywig: { + brand_id: 1, + auction_id: 1, + bid_ad_type: 1, + creative_info: { + video: { + duration: 51, + mimes: [ + 'video/x-flv', + 'video/mp4', + 'video/webm' + ] + } + } + } + } + } + } + } + ], + seat: 'bluebillywig' + } + ], + cur: 'USD', + ext: { + responsetimemillis: { + bluebillywig: 0 + }, + tmaxrequest: 5000 + } + }; + + const serverResponse = { body: validResponse }; + + it('should build bid array', () => { + const response = deepClone(serverResponse); + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(result.length).to.equal(1); + }); + + it('should have all relevant fields', () => { + const response = deepClone(serverResponse); + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + const bid = result[0]; + + // BB_HELPERS.transformRTBToPrebidProps + expect(bid.cpm).to.equal(serverResponse.body.seatbid[0].bid[0].price); + expect(bid.bidId).to.equal(serverResponse.body.seatbid[0].bid[0].impid); + expect(bid.requestId).to.equal(serverResponse.body.seatbid[0].bid[0].impid); + expect(bid.width).to.equal(serverResponse.body.seatbid[0].bid[0].w || BB_CONSTANTS.DEFAULT_WIDTH); + expect(bid.height).to.equal(serverResponse.body.seatbid[0].bid[0].h || BB_CONSTANTS.DEFAULT_HEIGHT); + expect(bid.ad).to.equal(serverResponse.body.seatbid[0].bid[0].adm); + expect(bid.netRevenue).to.equal(BB_CONSTANTS.DEFAULT_NET_REVENUE); + expect(bid.creativeId).to.equal(serverResponse.body.seatbid[0].bid[0].crid); + expect(bid.currency).to.equal(serverResponse.body.cur); + expect(bid.ttl).to.equal(BB_CONSTANTS.DEFAULT_TTL); + + expect(bid.publicationName).to.equal(validBidderRequest.bids[0].params.publicationName); + expect(bid.rendererCode).to.equal(validBidderRequest.bids[0].params.rendererCode); + expect(bid.accountId).to.equal(validBidderRequest.bids[0].params.accountId); + }); + + it('should not give anything when seatbid is an empty array', () => { + const seatbidEmptyArray = deepClone(serverResponse); + seatbidEmptyArray.body.seatbid = []; + + const response = seatbidEmptyArray; + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(result.length).to.equal(0); + }); + + it('should not give anything when seatbid is missing', () => { + const seatbidMissing = deepClone(serverResponse); + delete seatbidMissing.body.seatbid; + + const response = seatbidMissing; + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(result.length).to.equal(0); + }); + + const seatbidNotArrayResponse = deepClone(serverResponse); + it('should not give anything when seatbid is not an array', () => { + const invalidValues = [ false, null, {}, void (0), 123, 'string' ]; + + for (const invalidValue of invalidValues) { + seatbidNotArrayResponse.body.seatbid = invalidValue + const response = deepClone(seatbidNotArrayResponse); // interpretResponse is destructive + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(result.length).to.equal(0); + } + }); + + it('should not give anything when seatbid.bid is an empty array', () => { + const seatbidBidEmpty = deepClone(serverResponse); + seatbidBidEmpty.body.seatbid[0].bid = []; + + const response = seatbidBidEmpty; + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(result.length).to.equal(0); + }); + + it('should not give anything when seatbid.bid is missing', () => { + const seatbidBidMissing = deepClone(serverResponse); + delete seatbidBidMissing.body.seatbid[0].bid; + + const response = seatbidBidMissing; + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(result.length).to.equal(0); + }); + + it('should not give anything when seatbid.bid is not an array', () => { + const seatbidBidNotArray = deepClone(serverResponse); + + const invalidValues = [ false, null, {}, void (0), 123, 'string' ]; + + for (const invalidValue of invalidValues) { + seatbidBidNotArray.body.seatbid[0].bid = invalidValue; + + const response = deepClone(seatbidBidNotArray); // interpretResponse is destructive + const request = spec.buildRequests(baseValidBidRequests, validBidderRequest); + const result = spec.interpretResponse(response, request); + + expect(result.length).to.equal(0); + } + }); + }); + describe('getUserSyncs', () => { + const publicationName = 'bbprebid.dev'; + const rendererCode = 'glorious_renderer'; + + const baseValidBid = { + bidder: BB_CONSTANTS.BIDDER_CODE, + params: { + accountId: 123, + publicationName: publicationName, + rendererCode: rendererCode, + connections: [ BB_CONSTANTS.BIDDER_CODE ], + bluebillywig: {} + }, + mediaTypes: { + video: { + context: 'outstream' + } + } + }; + + const validBidRequests = [baseValidBid]; + + const validBidderRequest = { + auctionId: '12abc345-67d8-9012-e345-6f78901a2b34', + auctionStart: 1585918458868, + bidderCode: BB_CONSTANTS.BIDDER_CODE, + bidderRequestId: '1a2345b67c8d9e0', + bids: [{ + adUnitCode: 'ad-unit-test', + auctionId: '12abc345-67d8-9012-e345-6f78901a2b34', + bidId: '1234ab567c89de0', + bidRequestsCount: 1, + bidder: BB_CONSTANTS.BIDDER_CODE, + bidderRequestId: '1a2345b67c8d9e0', + params: baseValidBid.params, + sizes: [[768, 432], [640, 480], [630, 360]], + transactionId: '2b34c5de-f67a-8901-bcd2-34567efabc89' + }], + start: 11585918458869, + timeout: 3000 + }; + const validResponse = { + id: 'a12abc345-67d8-9012-e345-6f78901a2b34', + seatbid: [ + { + bid: [ + { + id: '1', + impid: '1234ab567c89de0', + price: 1, + adm: '\r\nBB Adserver00:00:51', + adid: '67069817', + adomain: [ + 'bluebillywig.com' + ], + cid: '3535', + crid: '67069817', + w: 1, + h: 1, + publicationName: 'bbprebid', + accountId: 123, + ext: { + prebid: { + targeting: { + hb_bidder: 'bluebillywig', + hb_pb: '1.00', + hb_size: '1x1' + }, + type: 'video' + }, + bidder: { + prebid: { + targeting: { + hb_bidder: 'bluebillywig', + hb_pb: '10.00', + hb_size: '1x1' + }, + type: 'video', + video: { + duration: 51, + primary_category: '' + } + }, + bidder: { + bluebillywig: { + brand_id: 1, + auction_id: 1, + bid_ad_type: 1, + creative_info: { + video: { + duration: 51, + mimes: [ + 'video/x-flv', + 'video/mp4', + 'video/webm' + ] + } + } + } + } + } + } + } + ], + seat: 'bluebillywig' + } + ], + cur: 'USD', + ext: { + responsetimemillis: { + bluebillywig: 0 + }, + tmaxrequest: 5000 + } + }; + + const serverResponse = { body: validResponse }; + + const gdpr = { + consentString: 'BOh7mtYOh7mtYAcABBENCU-AAAAncgPIXJiiAoao0PxBFkgCAC8ACIAAQAQQAAIAAAIAAAhBGAAAQAQAEQgAAAAAAABAAAAAAAAA AAAAAACAAAAAAAACgAAAAABAAAAQAAAAAAA', + gdprApplies: true + }; + + it('should return empty if no server response', function () { + const result = spec.getUserSyncs({}, false, gdpr); + expect(result).to.be.empty; + }); + + it('should return empty if server response is empty', function () { + const result = spec.getUserSyncs({}, [], gdpr); + expect(result).to.be.empty; + }); + + it('should return empty if iframeEnabled is not true', () => { + const result = spec.getUserSyncs({iframeEnabled: false}, [serverResponse], gdpr); + expect(result).to.be.empty; + }); + + it('should append the various values if they exist', function() { + // push data to syncStore + spec.buildRequests(validBidRequests, validBidderRequest); + + const result = spec.getUserSyncs({iframeEnabled: true}, [serverResponse], gdpr); + + expect(result).to.not.be.empty; + + expect(result[0].url).to.include('gdpr=1'); + expect(result[0].url).to.include(gdpr.consentString); + expect(result[0].url).to.include('accountId=123'); + expect(result[0].url).to.include(`bidders=${btoa(JSON.stringify(validBidRequests[0].params.connections))}`); + expect(result[0].url).to.include('cb='); + }); + }); +}); diff --git a/test/spec/modules/bridgewellBidAdapter_spec.js b/test/spec/modules/bridgewellBidAdapter_spec.js new file mode 100644 index 00000000000..644f468abe8 --- /dev/null +++ b/test/spec/modules/bridgewellBidAdapter_spec.js @@ -0,0 +1,1219 @@ +import { expect } from 'chai'; +import { spec } from 'modules/bridgewellBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; + +describe('bridgewellBidAdapter', 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 () { + const validTag = { + 'bidder': 'bridgewell', + 'params': { + 'ChannelID': 'CLJgEAYYvxUiBXBlbm55KgkIrAIQ-gEaATk' + }, + }; + expect(spec.isBidRequestValid(validTag)).to.equal(true); + }); + + it('should return false when required params not found', function () { + const invalidTag = { + 'bidder': 'bridgewell', + 'params': {}, + }; + expect(spec.isBidRequestValid(invalidTag)).to.equal(false); + }); + + it('should return false when required params are empty', function () { + const invalidTag = { + 'bidder': 'bridgewell', + 'params': { + 'ChannelID': '', + }, + }; + expect(spec.isBidRequestValid(invalidTag)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + const bidRequests = [ + { + 'bidder': 'bridgewell', + 'params': { + 'ChannelID': 'CgUxMjMzOBIBNiIGcGVubnkzKggI2AUQWhoBOQ', + }, + 'adUnitCode': 'adunit-code-2', + 'mediaTypes': { + 'banner': { + 'sizes': [728, 90] + } + }, + 'bidId': '3150ccb55da321', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }, + { + 'bidder': 'bridgewell', + 'params': { + 'ChannelID': 'CgUxMjMzOBIBNiIGcGVubnkzKggI2AUQWhoBOQ', + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [1, 1], + 'mediaTypes': { + 'native': { + 'title': { + 'required': true, + 'len': 15 + }, + 'body': { + 'required': true + }, + 'image': { + 'required': true, + 'sizes': [150, 150] + }, + 'icon': { + 'required': true, + 'sizes': [50, 50] + }, + 'clickUrl': { + 'required': true + }, + 'cta': { + 'required': true + }, + 'sponsoredBy': { + 'required': true + } + } + }, + 'bidId': '3150ccb55da321', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + } + ]; + + it('should attach valid params to the tag', function () { + const bidderRequest = { + refererInfo: { + referer: 'https://www.bridgewell.com/' + } + } + const request = spec.buildRequests(bidRequests, 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('ChannelID').that.is.a('string'); + expect(payload.adUnits[i]).to.have.property('adUnitCode').and.to.equal('adunit-code-2'); + } + }); + + it('should attach validBidRequests to the tag', function () { + const request = spec.buildRequests(bidRequests); + const validBidRequests = request.validBidRequests; + expect(validBidRequests).to.deep.equal(bidRequests); + }); + }); + + describe('interpretResponse', function () { + const nativeBidRequests = { + validBidRequests: [ + { + 'bidder': 'bridgewell', + 'params': { + 'ChannelID': 'CgUxMjMzOBIBNiIGcGVubnkzKggI2AUQWhoBOQ', + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [1, 1], + 'mediaTypes': { + 'native': { + 'title': { + 'required': true, + 'len': 15 + }, + 'body': { + 'required': true + }, + 'image': { + 'required': true, + 'sizes': [150, 150] + }, + 'icon': { + 'required': true, + 'sizes': [50, 50] + }, + 'clickUrl': { + 'required': true + }, + 'cta': { + 'required': true + }, + 'sponsoredBy': { + 'required': true + } + } + }, + 'bidId': '3150ccb55da321', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }, + ] + }; + const nativeServerResponses = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + const bannerBidRequests = { + validBidRequests: [ + { + 'mediaTypes': { + 'banner': { + 'sizes': [300, 250] + } + }, + 'bidId': '3150ccb55da321', + }, + ] + }; + const bannerServerResponses = [ + { + 'id': 'e5b10774-32bf-4931-85ee-05095e8cff21', + 'bidder_code': 'bridgewell', + 'cpm': 5.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 360, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + it('should return all required parameters', function () { + const result = spec.interpretResponse({ 'body': nativeServerResponses }, nativeBidRequests); + + expect(result[0].requestId).to.equal('3150ccb55da321'); + expect(result[0].cpm).to.equal(7.0); + expect(result[0].width).to.equal(1); + expect(result[0].height).to.equal(1); + expect(result[0].ttl).to.equal(400); + expect(result[0].creativeId).to.equal('0e4048d3-5c74-4380-a21a-00ba35629f7d'); + expect(result[0].netRevenue).to.equal(true); + expect(result[0].currency).to.equal('NTD'); + expect(result[0].mediaType).to.equal('native'); + expect(result[0].native.image.url).to.equal('https://img.scupio.com/test/test-image.jpg'); + }); + + it('should return all required parameters banner', function () { + const result = spec.interpretResponse({ 'body': bannerServerResponses }, bannerBidRequests); + + expect(result[0].requestId).to.equal('3150ccb55da321'); + expect(result[0].cpm).to.equal(5.0); + expect(result[0].width).to.equal(300); + expect(result[0].height).to.equal(250); + expect(result[0].ttl).to.equal(360); + expect(result[0].creativeId).to.equal('e5b10774-32bf-4931-85ee-05095e8cff21'); + expect(result[0].netRevenue).to.equal(true); + expect(result[0].currency).to.equal('NTD'); + expect(result[0].mediaType).to.equal('banner'); + expect(result[0].ad).to.equal('
test 300x250
'); + }); + + it('should give up bid if server response is undefiend', function () { + let result = spec.interpretResponse({ 'body': undefined }, bannerBidRequests); + + expect(result).to.deep.equal([]); + }); + + it('should give up bid if request sizes is missing', function () { + const request = { + validBidRequests: [ + { + 'mediaTypes': { + 'banner': {} + }, + 'bidId': '3150ccb55da321', + }, + ] + }; + const result = spec.interpretResponse({ 'body': bannerServerResponses }, request); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if response sizes is invalid', function () { + const request = { + validBidRequests: [ + { + 'mediaTypes': { + 'banner': { + 'sizes': [728, 90] + } + }, + 'bidId': '3150ccb55da321', + }, + ] + }; + const result = spec.interpretResponse({ 'body': bannerServerResponses }, request); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if cpm is missing', function () { + const response = [ + { + 'id': 'e5b10774-32bf-4931-85ee-05095e8cff21', + 'bidder_code': 'bridgewell', + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 360, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, bannerBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if width or height is missing', function () { + const response = [ + { + 'id': 'e5b10774-32bf-4931-85ee-05095e8cff21', + 'bidder_code': 'bridgewell', + 'cpm': 5.0, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 360, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, bannerBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if ad is missing', function () { + const response = [ + { + 'id': 'e5b10774-32bf-4931-85ee-05095e8cff21', + 'bidder_code': 'bridgewell', + 'cpm': 5.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ttl': 360, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, bannerBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if revenue mode is missing', function () { + const response = [ + { + 'id': 'e5b10774-32bf-4931-85ee-05095e8cff21', + 'bidder_code': 'bridgewell', + 'cpm': 5.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 360, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, bannerBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if currency is missing', function () { + const response = [ + { + 'id': 'e5b10774-32bf-4931-85ee-05095e8cff21', + 'bidder_code': 'bridgewell', + 'cpm': 5.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 360, + 'netRevenue': true, + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, bannerBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if mediaType is missing', function () { + const response = [ + { + 'id': 'e5b10774-32bf-4931-85ee-05095e8cff21', + 'bidder_code': 'bridgewell', + 'cpm': 5.0, + 'width': 300, + 'height': 250, + 'ad': '
test 300x250
', + 'ttl': 360, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, bannerBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if mediaType is not support', function () { + const responses = [ + { + 'id': 'e5b10774-32bf-4931-85ee-05095e8cff21', + 'bidder_code': 'bridgewell', + 'cpm': 5.0, + 'width': 300, + 'height': 250, + 'mediaType': 'superNiceAd', + 'ad': '
test 300x250
', + 'ttl': 360, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': responses }, bannerBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if property native of mediaType native is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native title is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native title is too long', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-titletest-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native body is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native image url is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native image is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native image is empty', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': {}, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native image sizes is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg' + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native sponsoredBy is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native icon is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native icon url is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native icon sizes is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native clickUrl is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native clickTrackers is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native clickTrackers is empty', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': [], + 'impressionTrackers': ['https://img.scupio.com/test-impressionTracker'] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native impressionTrackers is missing', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should give up bid if native impressionTrackers is empty', function () { + const response = [ + { + 'id': '0e4048d3-5c74-4380-a21a-00ba35629f7d', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 1, + 'height': 1, + 'mediaType': 'native', + 'native': { + 'image': { + 'url': 'https://img.scupio.com/test/test-image.jpg', + 'width': 150, + 'height': 150 + }, + 'title': 'test-title', + 'sponsoredBy': 'test-sponsoredBy', + 'body': 'test-body', + 'icon': { + 'url': 'https://img.scupio.com/test/test-icon.jpg', + 'width': 50, + 'height': 50 + }, + 'clickUrl': 'https://img.scupio.com/test-clickUrl', + 'clickTrackers': ['https://img.scupio.com/test-clickTracker'], + 'impressionTrackers': [] + }, + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, + ]; + + const result = spec.interpretResponse({ 'body': response }, nativeBidRequests); + expect(result).to.deep.equal([]); + }); + + it('should contain every request bid id in responses', function () { + const request = { + validBidRequests: [ + { + 'mediaTypes': { + 'banner': { + 'sizes': [300, 250] + } + }, + 'bidId': '3150ccb55da321', + }, + { + 'mediaTypes': { + 'banner': { + 'sizes': [300, 250] + } + }, + 'bidId': '3150ccb55da322', + } + ], + }; + const response = [{ + 'id': '0cd250f4-f40e-4a78-90f5-5168eb0a97e9', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, { + 'id': '8a740063-6820-45e4-b01f-34ce9b38e858', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }]; + const result = spec.interpretResponse({ 'body': response }, request); + let actualBidId = result.map(obj => obj.requestId); + let expectedBidId = ['3150ccb55da321', '3150ccb55da322']; + + expect(actualBidId).to.include(expectedBidId[0]).and.to.include(expectedBidId[1]); + }); + + it('should have 2 consumed responses when two requests with same sizes are given', function () { + const request = { + validBidRequests: [ + { + 'mediaTypes': { + 'banner': { + 'sizes': [300, 250] + } + }, + 'bidId': '3150ccb55da321', + }, + { + 'mediaTypes': { + 'banner': { + 'sizes': [300, 250] + } + }, + 'bidId': '3150ccb55da322', + } + ], + }; + const response = [{ + 'id': '0cd250f4-f40e-4a78-90f5-5168eb0a97e9', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, { + 'id': '8a740063-6820-45e4-b01f-34ce9b38e858', + 'bidder_code': 'bridgewell', + 'cpm': 7.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }]; + const reducer = function(accumulator, currentValue) { + if (currentValue.consumed) accumulator++; + return accumulator; + }; + + spec.interpretResponse({ 'body': response }, request); + expect(response.reduce(reducer, 0)).to.equal(2); + }); + + it('should use adUnitCode to build bidResponses', function () { + const request = { + validBidRequests: [ + { + 'adUnitCode': 'div-gpt-ad-1564632520056-0', + 'bidId': '3150ccb55da321', + }, + { + 'adUnitCode': 'div-gpt-ad-1564632520056-1', + 'bidId': '3150ccb55da322', + } + ], + }; + const response = [{ + 'id': '0cd250f4-f40e-4a78-90f5-5168eb0a97e9', + 'bidder_code': 'bridgewell', + 'adUnitCode': 'div-gpt-ad-1564632520056-0', + 'cpm': 7.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, { + 'id': '8a740063-6820-45e4-b01f-34ce9b38e858', + 'bidder_code': 'bridgewell', + 'adUnitCode': 'div-gpt-ad-1564632520056-1', + 'cpm': 7.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }]; + const result = spec.interpretResponse({ 'body': response }, request); + let actualBidId = result.map(obj => obj.requestId); + let expectedBidId = ['3150ccb55da321', '3150ccb55da322']; + + expect(actualBidId).to.include(expectedBidId[0]).and.to.include(expectedBidId[1]); + }); + + it('should use size to match when adUnitCode is empty string in server response', function () { + const request = { + validBidRequests: [ + { + 'mediaTypes': { + 'banner': { + 'sizes': [300, 250] + } + }, + 'adUnitCode': 'div-gpt-ad-1564632520056-0', + 'bidId': '3150ccb55da321', + }, + { + 'mediaTypes': { + 'banner': { + 'sizes': [300, 250] + } + }, + 'adUnitCode': 'div-gpt-ad-1564632520056-1', + 'bidId': '3150ccb55da322', + } + ], + }; + const response = [{ + 'id': '0cd250f4-f40e-4a78-90f5-5168eb0a97e9', + 'bidder_code': 'bridgewell', + 'adUnitCode': '', + 'cpm': 7.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }, { + 'id': '8a740063-6820-45e4-b01f-34ce9b38e858', + 'bidder_code': 'bridgewell', + 'adUnitCode': '', + 'cpm': 7.0, + 'width': 300, + 'height': 250, + 'mediaType': 'banner', + 'ad': '
test 300x250
', + 'ttl': 400, + 'netRevenue': true, + 'currency': 'NTD' + }]; + const result = spec.interpretResponse({ 'body': response }, request); + let actualBidId = result.map(obj => obj.requestId); + let expectedBidId = ['3150ccb55da321', '3150ccb55da322']; + + expect(actualBidId).to.include(expectedBidId[0]).and.to.include(expectedBidId[1]); + }); + }); +}); diff --git a/test/spec/modules/brightcomBidAdapter_spec.js b/test/spec/modules/brightcomBidAdapter_spec.js index 14ed4d3024d..6477e94d9d6 100644 --- a/test/spec/modules/brightcomBidAdapter_spec.js +++ b/test/spec/modules/brightcomBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; -import * as utils from 'src/utils'; -import { spec } from 'modules/brightcomBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import * as utils from 'src/utils.js'; +import { spec } from 'modules/brightcomBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const URL = 'https://brightcombid.marphezis.com/hb'; diff --git a/test/spec/modules/britepoolIdSystem_spec.js b/test/spec/modules/britepoolIdSystem_spec.js index d7250eeb941..2c6dd234a90 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'; +import {britepoolIdSubmodule} from 'modules/britepoolIdSystem.js'; describe('BritePool Submodule', () => { const api_key = '1111'; diff --git a/test/spec/modules/bucksenseBidAdapter_spec.js b/test/spec/modules/bucksenseBidAdapter_spec.js index b9da6c077b2..f49a63d2003 100644 --- a/test/spec/modules/bucksenseBidAdapter_spec.js +++ b/test/spec/modules/bucksenseBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from 'modules/bucksenseBidAdapter'; +import {spec} from 'modules/bucksenseBidAdapter.js'; describe('Bucksense Adapter', function() { const BIDDER_CODE = 'bucksense'; @@ -104,7 +104,7 @@ describe('Bucksense Adapter', function() { beforeEach(function() { serverRequest = { 'method': 'POST', - 'url': 'https://prebid.bksn.se:445/prebidjs/', + 'url': 'https://prebid.bksn.se/prebidjs/', 'data': { 'pub_id': 'prebid.org', 'pl_id': '1000', diff --git a/test/spec/modules/buzzoolaBidAdapter_spec.js b/test/spec/modules/buzzoolaBidAdapter_spec.js index e6f22d1da20..8a04999219d 100644 --- a/test/spec/modules/buzzoolaBidAdapter_spec.js +++ b/test/spec/modules/buzzoolaBidAdapter_spec.js @@ -1,8 +1,8 @@ import {expect} from 'chai'; -import {spec} from 'modules/buzzoolaBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; -import {executeRenderer, Renderer} from '../../../src/Renderer'; -import {deepClone} from '../../../src/utils'; +import {spec} from 'modules/buzzoolaBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; +import {executeRenderer, Renderer} from '../../../src/Renderer.js'; +import {deepClone} from '../../../src/utils.js'; const ENDPOINT = 'https://exchange.buzzoola.com/ssp/prebidjs'; const RENDERER_SRC = 'https://tube.buzzoola.com/new/build/buzzlibrary.js'; diff --git a/test/spec/modules/byplayBidAdapter_spec.js b/test/spec/modules/byplayBidAdapter_spec.js new file mode 100644 index 00000000000..57aad403c4e --- /dev/null +++ b/test/spec/modules/byplayBidAdapter_spec.js @@ -0,0 +1,93 @@ +import { expect } from 'chai'; +import { spec } from 'modules/byplayBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import * as bidderFactory from 'src/adapters/bidderFactory.js'; + +describe('byplayBidAdapter', () => { + describe('isBidRequestValid', () => { + describe('exist sectionId', () => { + const bid = { + 'bidder': 'byplay', + 'params': { + 'sectionId': '11111' + }, + }; + + it('should equal true', () => { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + }); + + describe('not exist sectionId', () => { + const bid = { + 'bidder': 'byplay', + 'params': { + }, + }; + + it('should equal false', () => { + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + }); + + describe('buildRequests', () => { + const bids = [ + { + 'bidder': 'byplay', + 'bidId': '1234', + 'params': { + 'sectionId': '1111' + }, + } + ]; + + const request = spec.buildRequests(bids); + + it('should return POST', () => { + expect(request[0].method).to.equal('POST'); + }); + + it('should return data', () => { + expect(request[0].data).to.equal('{"requestId":"1234","sectionId":"1111"}'); + }); + }); + + describe('interpretResponse', () => { + const serverResponse = { + body: { + 'cpm': 1500, + 'width': 320, + 'height': 180, + 'netRevenue': true, + 'creativeId': '1', + 'requestId': '209c1fb5ad88f5', + 'vastXml': '' + } + }; + + const bidderRequest = { + 'method': 'GET', + 'url': 'https://tasp0g98f2.execute-api.ap-northeast-1.amazonaws.com/v1/bidder', + 'data': '{"requestId":"209c1fb5ad88f5","sectionId":7986}' + }; + + const result = spec.interpretResponse(serverResponse, bidderRequest); + + it('should return Array', () => { + expect(Array.isArray(result)).to.equal(true); + }); + + it('should get the correct bid response', () => { + expect(result[0].cpm).to.equal(1500); + expect(result[0].creativeId).to.equal('1'); + expect(result[0].width).to.equal(320); + expect(result[0].height).to.equal(180); + expect(result[0].mediaType).to.equal('video'); + expect(result[0].netRevenue).to.equal(true); + expect(result[0].requestId).to.equal('209c1fb5ad88f5'); + expect(result[0].ttl).to.equal(3000); + expect(result[0].vastXml).to.equal(''); + }); + }); +}); diff --git a/test/spec/modules/c1xBidAdapter_spec.js b/test/spec/modules/c1xBidAdapter_spec.js index a728e52dbc4..00741abda7a 100644 --- a/test/spec/modules/c1xBidAdapter_spec.js +++ b/test/spec/modules/c1xBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { c1xAdapter } from 'modules/c1xBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { c1xAdapter } from 'modules/c1xBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const ENDPOINT = 'https://ht.c1exchange.com/ht'; const BIDDER_CODE = 'c1x'; diff --git a/test/spec/modules/categoryTranslation_spec.js b/test/spec/modules/categoryTranslation_spec.js index 17cc07269b0..2301d6aab1b 100644 --- a/test/spec/modules/categoryTranslation_spec.js +++ b/test/spec/modules/categoryTranslation_spec.js @@ -1,6 +1,6 @@ -import { getAdserverCategoryHook, initTranslation } from 'modules/categoryTranslation'; -import { config } from 'src/config'; -import * as utils from 'src/utils'; +import { getAdserverCategoryHook, initTranslation, storage } from 'modules/categoryTranslation.js'; +import { config } from 'src/config.js'; +import * as utils from 'src/utils.js'; import { expect } from 'chai'; describe('category translation', function () { @@ -9,7 +9,7 @@ describe('category translation', function () { beforeEach(function () { fakeTranslationServer = sinon.fakeServer.create(); - getLocalStorageStub = sinon.stub(utils, 'getDataFromLocalStorage'); + getLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage'); }); afterEach(function() { @@ -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/ccxBidAdapter_spec.js b/test/spec/modules/ccxBidAdapter_spec.js index 01e52c3559a..f14612629b1 100644 --- a/test/spec/modules/ccxBidAdapter_spec.js +++ b/test/spec/modules/ccxBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/ccxBidAdapter'; -import * as utils from 'src/utils'; +import { spec } from 'modules/ccxBidAdapter.js'; +import * as utils from 'src/utils.js'; describe('ccxAdapter', function () { let bids = [ diff --git a/test/spec/modules/cedatoBidAdapter_spec.js b/test/spec/modules/cedatoBidAdapter_spec.js index 0cf6d14147a..a7f4875afff 100644 --- a/test/spec/modules/cedatoBidAdapter_spec.js +++ b/test/spec/modules/cedatoBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from 'modules/cedatoBidAdapter'; +import {spec} from 'modules/cedatoBidAdapter.js'; describe('the cedato adapter', function () { function getValidBidObject() { @@ -50,12 +50,12 @@ describe('the cedato adapter', function () { }); it('should build a very basic request', function() { - var request = spec.buildRequests([bid], bidRequestObj); + var [request] = spec.buildRequests([bid], bidRequestObj); expect(request.method).to.equal('POST'); }); it('should pass gdpr and usp strings to server', function() { - var request = spec.buildRequests([bid], bidRequestObj); + var [request] = spec.buildRequests([bid], bidRequestObj); var payload = JSON.parse(request.data); expect(payload.gdpr_consent).to.not.be.undefined; expect(payload.gdpr_consent.consent_string).to.equal(bidRequestObj.gdprConsent.consentString); diff --git a/test/spec/modules/cleanmedianetBidAdapter_spec.js b/test/spec/modules/cleanmedianetBidAdapter_spec.js index af3eeb853fd..5438f6c8701 100644 --- a/test/spec/modules/cleanmedianetBidAdapter_spec.js +++ b/test/spec/modules/cleanmedianetBidAdapter_spec.js @@ -1,7 +1,7 @@ import {expect} from 'chai'; -import {spec, helper} from 'modules/cleanmedianetBidAdapter'; -import * as utils from 'src/utils'; -import {newBidder} from '../../../src/adapters/bidderFactory'; +import {spec, helper} from 'modules/cleanmedianetBidAdapter.js'; +import * as utils from 'src/utils.js'; +import {newBidder} from '../../../src/adapters/bidderFactory.js'; const supplyPartnerId = '123'; const adapter = newBidder(spec); diff --git a/test/spec/modules/clickforceBidAdapter_spec.js b/test/spec/modules/clickforceBidAdapter_spec.js index 3d4fc70c057..dad00f94641 100644 --- a/test/spec/modules/clickforceBidAdapter_spec.js +++ b/test/spec/modules/clickforceBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/clickforceBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/clickforceBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('ClickforceAdapter', function () { const adapter = newBidder(spec); @@ -175,7 +175,7 @@ describe('ClickforceAdapter', function () { } let userSync = spec.getUserSyncs(syncOptions); expect(userSync[0].type).to.equal('iframe'); - expect(userSync[0].url).to.equal('https://cdn.doublemax.net/js/capmapping.htm'); + expect(userSync[0].url).to.equal('https://cdn.holmesmind.com/js/capmapping.htm'); }); it('should register type is image', function () { @@ -184,7 +184,7 @@ describe('ClickforceAdapter', function () { } let userSync = spec.getUserSyncs(syncOptions); expect(userSync[0].type).to.equal('image'); - expect(userSync[0].url).to.equal('https://c.doublemax.net/cm'); + expect(userSync[0].url).to.equal('https://c.holmesmind.com/cm'); }); }); }); diff --git a/test/spec/modules/clicktripzBidAdapter_spec.js b/test/spec/modules/clicktripzBidAdapter_spec.js new file mode 100644 index 00000000000..fed94811c4e --- /dev/null +++ b/test/spec/modules/clicktripzBidAdapter_spec.js @@ -0,0 +1,152 @@ +import {expect} from 'chai'; +import {spec} from 'modules/clicktripzBidAdapter.js'; + +const ENDPOINT_URL = 'https://www.clicktripz.com/x/prebid/v1'; + +describe('clicktripzBidAdapter', function () { + describe('isBidRequestValid', function () { + let bid = { + 'bidder': 'clicktripz', + 'params': { + placementId: 'testPlacementId', + siteId: 'testSiteId' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250] + ], + 'bidId': '1234asdf1234', + 'bidderRequestId': '1234asdf1234asdf', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf120' + }; + + let bid2 = { + 'bidder': 'clicktripz', + 'params': { + placementId: 'testPlacementId' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250] + ], + 'bidId': '1234asdf1234', + 'bidderRequestId': '1234asdf1234asdf', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf120' + }; + + let bid3 = { + 'bidder': 'clicktripz', + 'params': { + siteId: 'testSiteId' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250] + ], + 'bidId': '1234asdf1234', + 'bidderRequestId': '1234asdf1234asdf', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf120' + }; + + 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 found', function () { + expect(spec.isBidRequestValid(bid2)).to.equal(false); + expect(spec.isBidRequestValid(bid3)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + let validBidRequests = [{ + 'bidder': 'clicktripz', + 'params': { + placementId: 'testPlacementId', + siteId: 'testSiteId' + }, + 'sizes': [ + [300, 250], + [300, 300] + ], + 'bidId': '23beaa6af6cdde', + 'bidderRequestId': '19c0c1efdf37e7', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1', + }, { + 'bidder': 'clicktripz', + 'params': { + placementId: 'testPlacementId2', + siteId: 'testSiteId2' + }, + 'sizes': [ + [300, 250] + ], + 'bidId': '25beaa6af6cdde', + 'bidderRequestId': '19c0c1efdf37e7', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1', + }]; + + const request = spec.buildRequests(validBidRequests); + it('sends bid request to our endpoint via POST', function () { + expect(request.method).to.equal('POST'); + }); + it('sends bid request to our endpoint via POST', function () { + expect(request.method).to.equal('POST'); + }); + + it('sends bid request to our endpoint at the correct URL', function () { + expect(request.url).to.equal(ENDPOINT_URL); + }); + it('sends bid request to our endpoint at the correct URL', function () { + expect(request.url).to.equal(ENDPOINT_URL); + }); + + it('transforms sizes into an array of strings. Pairs of concatenated sizes joined with an x', function () { + expect(request.data[0].sizes.toString()).to.equal('300x250,300x300'); + }); + it('transforms sizes into an array of strings. Pairs of concatenated sizes joined with an x', function () { + expect(request.data[1].sizes.toString()).to.equal('300x250'); + }); + + it('includes bidId, siteId, and placementId in payload', function () { + expect(request.data[0].bidId).to.equal('23beaa6af6cdde'); + expect(request.data[0].siteId).to.equal('testSiteId'); + expect(request.data[0].placementId).to.equal('testPlacementId'); + }); + it('includes bidId, siteId, and placementId in payload', function () { + expect(request.data[1].bidId).to.equal('25beaa6af6cdde'); + expect(request.data[1].siteId).to.equal('testSiteId2'); + expect(request.data[1].placementId).to.equal('testPlacementId2'); + }); + }); + + describe('interpretResponse', function () { + let serverResponse = { + body: [{ + 'bidId': 'bid-request-id', + 'ttl': 120, + 'netRevenue': true, + 'size': '300x200', + 'currency': 'USD', + 'adUrl': 'https://www.clicktripz.com/n3/crane/v0/render?t=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXlsb2FkIjoiaHR0cHM6XC9cL3d3dy5jbGlja3RyaXB6LmNvbVwvY2xpY2sucGhwP2NhbXBhaWduSUQ9MTkxNTYmcHJlQ2hlY2tlZD0xJnB1Ymxpc2hlcklEPTM2MCZzZWFyY2hLZXk9N2M5MzQ0NzhlM2M1NTc3Y2EyN2ZmN2Y1NTg5N2NkMzkmc2VhcmNoRGlzcGxheVR5cGU9MSZkaXNwbGF5VHlwZT00JmNyZWF0aXZlVHlwZT1zaW5nbGUmaXNQb3BVbmRlcj0wJnBvc2l0aW9uPTEmdHlwZT0xJmNpdHk9TWFkcmlkJTJDK1NwYWluJmNoZWNrSW5EYXRlPTAzJTJGMDElMkYyMDIwJmNoZWNrT3V0RGF0ZT0wMyUyRjA1JTJGMjAyMCZndWVzdHM9MiZyb29tcz0xIn0.WBDGYr1qfkSvOuK02VpMW3iAua1E02jjDGDViFc2kaE', + 'creativeId': '25ef9876abc5681f153', + 'cpm': 50 + }] + }; + it('should get the correct bid response', function () { + let expectedResponse = [{ + 'requestId': 'bid-request-id', + 'cpm': 50, + 'netRevenue': true, + 'width': '300', + 'height': '200', + 'creativeId': '25ef9876abc5681f153', + 'currency': 'USD', + 'adUrl': 'https://www.clicktripz.com/n3/crane/v0/render?t=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXlsb2FkIjoiaHR0cHM6XC9cL3d3dy5jbGlja3RyaXB6LmNvbVwvY2xpY2sucGhwP2NhbXBhaWduSUQ9MTkxNTYmcHJlQ2hlY2tlZD0xJnB1Ymxpc2hlcklEPTM2MCZzZWFyY2hLZXk9N2M5MzQ0NzhlM2M1NTc3Y2EyN2ZmN2Y1NTg5N2NkMzkmc2VhcmNoRGlzcGxheVR5cGU9MSZkaXNwbGF5VHlwZT00JmNyZWF0aXZlVHlwZT1zaW5nbGUmaXNQb3BVbmRlcj0wJnBvc2l0aW9uPTEmdHlwZT0xJmNpdHk9TWFkcmlkJTJDK1NwYWluJmNoZWNrSW5EYXRlPTAzJTJGMDElMkYyMDIwJmNoZWNrT3V0RGF0ZT0wMyUyRjA1JTJGMjAyMCZndWVzdHM9MiZyb29tcz0xIn0.WBDGYr1qfkSvOuK02VpMW3iAua1E02jjDGDViFc2kaE', + 'ttl': 120 + }]; + let result = spec.interpretResponse(serverResponse); + expect(result).to.deep.equal(expectedResponse); + }); + }); +}); diff --git a/test/spec/modules/coinzillaBidAdapter_spec.js b/test/spec/modules/coinzillaBidAdapter_spec.js index e9157e2a735..a3438b80126 100644 --- a/test/spec/modules/coinzillaBidAdapter_spec.js +++ b/test/spec/modules/coinzillaBidAdapter_spec.js @@ -1,6 +1,6 @@ import {assert, expect} from 'chai'; -import {spec} from 'modules/coinzillaBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; +import {spec} from 'modules/coinzillaBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; const ENDPOINT_URL = 'https://request.czilladx.com/serve/request.php'; diff --git a/test/spec/modules/collectcentBidAdapter_spec.js b/test/spec/modules/collectcentBidAdapter_spec.js index 7398c5c7dd9..0ab83a8024b 100644 --- a/test/spec/modules/collectcentBidAdapter_spec.js +++ b/test/spec/modules/collectcentBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from '../../../modules/collectcentBidAdapter'; +import {spec} from '../../../modules/collectcentBidAdapter.js'; describe('Collectcent', function () { let bid = { diff --git a/test/spec/modules/colombiaBidAdapter_spec.js b/test/spec/modules/colombiaBidAdapter_spec.js new file mode 100644 index 00000000000..4e80c6b1d9d --- /dev/null +++ b/test/spec/modules/colombiaBidAdapter_spec.js @@ -0,0 +1,152 @@ +import { expect } from 'chai'; +import { spec } from 'modules/colombiaBidAdapter'; +import { newBidder } from 'src/adapters/bidderFactory'; + +const HOST_NAME = document.location.protocol + '//' + window.location.host; +const ENDPOINT = 'https://ade.clmbtech.com/cde/prebid.htm'; + +describe('colombiaBidAdapter', function() { + const adapter = newBidder(spec); + + describe('isBidRequestValid', function () { + let bid = { + 'bidder': 'colombia', + 'params': { + placementId: '307466' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250] + ], + 'bidId': '23beaa6af6cdde', + 'bidderRequestId': '19c0c1efdf37e7', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1', + }; + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when placementId not passed correctly', function () { + bid.params.placementId = ''; + 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 () { + let bidRequests = [ + { + 'bidder': 'colombia', + 'params': { + placementId: '307466' + }, + 'adUnitCode': 'adunit-code1', + 'sizes': [ + [300, 250] + ], + 'bidId': '23beaa6af6cdde', + 'bidderRequestId': '19c0c1efdf37e7', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1', + }, + { + 'bidder': 'colombia', + 'params': { + placementId: '307466' + }, + 'adUnitCode': 'adunit-code2', + 'sizes': [ + [300, 250] + ], + 'bidId': '382091349b149f"', + 'bidderRequestId': '"1f9c98192de251"', + 'auctionId': '61466567-d482-4a16-96f0-fe5f25ffbdf1', + } + ]; + + const request = spec.buildRequests(bidRequests); + + 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); + expect(request[1].url).to.equal(ENDPOINT); + }); + }); + + describe('interpretResponse', function () { + let bidRequest = [ + { + 'method': 'POST', + 'url': 'https://ade.clmbtech.com/cde/prebid.htm', + 'data': { + 'v': 'hb1', + 'p': '307466', + 'w': '300', + 'h': '250', + 'cb': 12892917383, + 'r': 'http%3A%2F%2Flocalhost%3A9876%2F%3Fid%3D74552836', + 'uid': '23beaa6af6cdde', + 't': 'i', + } + } + ]; + + let serverResponse = { + body: { + 'ad': '
This is test case for colombia adapter
', + 'cpm': 3.14, + 'creativeId': '6b958110-612c-4b03-b6a9-7436c9f746dc-1sk24', + 'currency': 'USD', + 'uid': '23beaa6af6cdde', + 'width': 728, + 'height': 90, + 'netRevenue': true, + 'ttl': 600, + 'dealid': '', + 'referrer': 'http%3A%2F%2Flocalhost%3A9876%2F%3Fid%3D74552836' + } + }; + + it('should get the correct bid response', function () { + let expectedResponse = [{ + 'requestId': '23beaa6af6cdde', + 'cpm': 3.14, + 'width': 728, + 'height': 90, + 'creativeId': '6b958110-612c-4b03-b6a9-7436c9f746dc-1sk24', + 'dealId': '', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 300, + 'referrer': 'http%3A%2F%2Flocalhost%3A9876%2F%3Fid%3D74552836', + 'ad': '
This is test case for colombia adapter
' + }]; + let result = spec.interpretResponse(serverResponse, bidRequest[0]); + expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + }); + + it('handles empty bid response', function () { + let response = { + body: { + 'uid': '23beaa6af6cdde', + 'height': 0, + 'creativeId': '', + 'statusMessage': 'Bid returned empty or error response', + 'width': 0, + 'cpm': 0 + } + }; + let result = spec.interpretResponse(response, bidRequest[0]); + expect(result.length).to.equal(0); + }); + }); +}); diff --git a/test/spec/modules/colossussspBidAdapter_spec.js b/test/spec/modules/colossussspBidAdapter_spec.js index 9ed2dbe6e6b..df9bdcbd47b 100644 --- a/test/spec/modules/colossussspBidAdapter_spec.js +++ b/test/spec/modules/colossussspBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from '../../../modules/colossussspBidAdapter'; +import {spec} from '../../../modules/colossussspBidAdapter.js'; describe('ColossussspAdapter', function () { let bid = { @@ -88,7 +88,7 @@ describe('ColossussspAdapter', function () { 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', 'schain'); + expect(placement).to.have.all.keys('placementId', 'eids', 'bidId', 'traffic', 'sizes', 'schain'); expect(placement.schain).to.be.an('object') expect(placement.placementId).to.be.a('number'); expect(placement.bidId).to.be.a('string'); @@ -102,6 +102,36 @@ describe('ColossussspAdapter', function () { expect(data.placements).to.be.an('array').that.is.empty; }); }); + + describe('buildRequests with user ids', function () { + bid.userId = {} + bid.userId.britepoolid = 'britepoolid123'; + bid.userId.idl_env = 'idl_env123'; + bid.userId.tdid = 'tdid123'; + bid.userId.id5id = 'id5id123' + let serverRequest = spec.buildRequests([bid], bidderRequest); + it('Returns valid data if array of bids is valid', 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('eids') + expect(placement.eids).to.be.an('array') + expect(placement.eids.length).to.be.equal(4) + for (let index in placement.eids) { + let v = placement.eids[index]; + expect(v).to.have.all.keys('source', 'uids') + expect(v.source).to.be.oneOf(['britepool.com', 'identityLink', 'adserver.org', 'id5-sync.com']) + expect(v.uids).to.be.an('array'); + expect(v.uids.length).to.be.equal(1) + expect(v.uids[0]).to.have.property('id') + expect(v.uids[0].id).to.be.oneOf(['britepoolid123', 'idl_env123', 'tdid123', 'id5id123']) + } + } + }); + }); + describe('interpretResponse', function () { let resObject = { body: [ { diff --git a/test/spec/modules/connectadBidAdapter_spec.js b/test/spec/modules/connectadBidAdapter_spec.js new file mode 100644 index 00000000000..626018241c4 --- /dev/null +++ b/test/spec/modules/connectadBidAdapter_spec.js @@ -0,0 +1,453 @@ +import {expect} from 'chai'; +import {spec} from 'modules/connectadBidAdapter.js'; +import { config } from 'src/config.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; + +describe('ConnectAd Adapter', function () { + let bidRequests; + let bidderRequest; + let bidRequestsUserIds; + + beforeEach(function () { + bidRequests = [ + { + bidder: 'conntectad', + params: { + siteId: 123456, + networkId: 123456 + }, + adUnitCode: '/19968336/header-bid-tag-1', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + bidId: '2f95c00074b931', + auctionId: 'e76cbb58-f3e1-4ad9-9f4c-718c1919d0df', + bidderRequestId: '1c56ad30b9b8ca8', + transactionId: 'e76cbb58-f3e1-4ad9-9f4c-718c1919d0df' + } + ]; + + bidRequestsUserIds = [{ + bidder: 'conntectad', + params: { + siteId: 123456, + networkId: 123456 + }, + adUnitCode: '/19968336/header-bid-tag-1', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + bidId: '2f95c00074b931', + auctionId: 'e76cbb58-f3e1-4ad9-9f4c-718c1919d0df', + bidderRequestId: '1c56ad30b9b8ca8', + transactionId: 'e76cbb58-f3e1-4ad9-9f4c-718c1919d0df', + userId: { + tdid: '123456', + digitrustid: {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}} + } + }]; + + bidderRequest = { + timeout: 3000, + gdprConsent: { + gdprApplies: true, + consentString: 'consentDataString', + vendorData: {} + } + } + }); + + describe('inherited functions', function () { + it('should exists and is a function', function () { + const adapter = newBidder(spec); + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + }); + + describe('implementation', function () { + describe('for requests', function () { + it('should accept bid', function () { + let validBid = { + bidder: 'connectad', + params: { + siteId: 123456, + networkId: 123456 + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + } + }; + const isValid = spec.isBidRequestValid(validBid); + + expect(isValid).to.equal(true); + }); + + it('should reject if missing sizes', function () { + let invalidBid = { + bidder: 'connectad', + params: { + siteId: 123456, + } + }; + const isValid = spec.isBidRequestValid(invalidBid); + expect(isValid).to.equal(false); + }); + + it('should return true when optional bidFloor params found for an ad', function () { + let validBid = { + bidder: 'connectad', + params: { + siteId: 123456, + networkId: 123456, + bidfloor: 0.20 + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + } + }; + const isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(true) + }); + + it('should reject if missing siteId/networkId', function () { + let invalidBid = { + bidder: 'connectad', + params: {}, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + } + }; + const isValid = spec.isBidRequestValid(invalidBid); + expect(isValid).to.equal(false); + }); + + it('should reject if missing networkId', function () { + let invalidBid = { + bidder: 'connectad', + params: { + siteId: 123456 + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + } + }; + const isValid = spec.isBidRequestValid(invalidBid); + expect(isValid).to.equal(false); + }); + + it('should contain SiteId and NetworkId', function () { + const request = spec.buildRequests(bidRequests, bidderRequest); + const requestparse = JSON.parse(request.data); + expect(requestparse.placements[0].siteId).to.equal(123456); + expect(requestparse.placements[0].networkId).to.equal(123456); + }); + + it('should contain gdpr info', function () { + const request = spec.buildRequests(bidRequests, bidderRequest); + const requestparse = JSON.parse(request.data); + + expect(requestparse.user.ext.gdpr).to.equal(1); + expect(requestparse.user.ext.consent).to.equal('consentDataString'); + }); + + it('should build a request if Consent but no gdprApplies', function () { + let bidderRequest = { + timeout: 3000, + gdprConsent: { + gdprApplies: false, + consentString: 'consentDataString', + }, + } + const request = spec.buildRequests(bidRequests, bidderRequest); + const requestparse = JSON.parse(request.data); + + expect(requestparse.placements[0].adTypes).to.be.an('array'); + expect(requestparse.placements[0].siteId).to.equal(123456); + expect(requestparse.user.ext.consent).to.equal('consentDataString'); + }); + + it('should build a request if gdprConsent empty', function () { + let bidderRequest = { + timeout: 3000, + gdprConsent: {} + } + const request = spec.buildRequests(bidRequests, bidderRequest); + const requestparse = JSON.parse(request.data); + + expect(requestparse.placements[0].adTypes).to.be.an('array'); + expect(requestparse.placements[0].siteId).to.equal(123456); + }); + + it('should have CCPA Consent if defined', function () { + const uspConsent = '1YYN' + bidderRequest.uspConsent = uspConsent + const request = spec.buildRequests(bidRequests, bidderRequest); + const requestparse = JSON.parse(request.data); + + expect(requestparse.user.ext.us_privacy).to.equal(uspConsent); + }); + + it('should not have CCPA Consent if not defined', function () { + bidderRequest.uspConsent = undefined + const request = spec.buildRequests(bidRequests, bidderRequest); + const requestparse = JSON.parse(request.data); + expect(requestparse.user.ext.us_privacy).to.be.undefined; + }); + + it('should not include schain when not provided', function () { + const request = spec.buildRequests(bidRequests, bidderRequest); + const requestparse = JSON.parse(request.data); + expect(requestparse.source).to.not.exist; + }); + + it('should submit coppa if set in config', function () { + sinon.stub(config, 'getConfig') + .withArgs('coppa') + .returns(true); + const request = spec.buildRequests(bidRequests, bidderRequest); + const requestparse = JSON.parse(request.data); + expect(requestparse.user.coppa).to.equal(1); + config.getConfig.restore(); + }); + + it('should send all UserData data', function () { + const request = spec.buildRequests(bidRequestsUserIds, bidderRequest); + 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 () { + const bidRequest = Object.assign({}, bidRequests[0]) + const bidderRequ = { + refererInfo: { + referer: 'https://connectad.io/page.html', + reachedTop: true, + numIframes: 2, + stack: [ + 'https://connectad.io/page.html', + 'https://connectad.io/iframe1.html', + 'https://connectad.io/iframe2.html' + ] + } + } + const request = spec.buildRequests([bidRequest], bidderRequ); + const requestparse = JSON.parse(request.data); + + expect(requestparse.referrer_info).to.exist; + }); + + it('should populate schain', function () { + const bidRequest = Object.assign({}, bidRequests[0], { + schain: { + ver: '1.0', + complete: 1, + nodes: [ + { + 'asi': 'reseller1.com', + 'sid': 'absc1', + 'hp': 1 + } + ] + } + }); + + const request = spec.buildRequests([bidRequest], bidderRequest); + const requestparse = JSON.parse(request.data); + expect(requestparse.source.ext.schain).to.deep.equal({ + ver: '1.0', + complete: 1, + nodes: [ + { + 'asi': 'reseller1.com', + 'sid': 'absc1', + 'hp': 1 + } + ] + }); + }); + }); + + describe('bid responses', function () { + it('should return complete bid response', function () { + let serverResponse = { + body: { + decisions: { + '2f95c00074b931': { + adId: '0', + contents: [ + { + body: '<<<---- Creative --->>>' + } + ], + height: '250', + width: '300', + pricing: { + clearPrice: 11.899999999999999 + } + } + } + } + }; + const request = spec.buildRequests(bidRequests, bidderRequest); + const bids = spec.interpretResponse(serverResponse, request); + + expect(bids).to.be.lengthOf(1); + expect(bids[0].cpm).to.equal(11.899999999999999); + expect(bids[0].width).to.equal('300'); + expect(bids[0].height).to.equal('250'); + expect(bids[0].ad).to.have.length.above(1); + }); + + it('should return empty bid response', function () { + let serverResponse = { + body: { + decisions: [] + } + }; + const request = spec.buildRequests(bidRequests, bidderRequest); + const bids = spec.interpretResponse(serverResponse, request); + expect(bids).to.be.lengthOf(0); + }); + + it('should return empty bid response on incorrect size', function () { + let serverResponse = { + body: { + decisions: { + '2f95c00074b931': { + adId: '0', + contents: [ + { + body: '<<<---- Creative --->>>' + } + ], + height: '160', + width: '600', + pricing: { + clearPrice: 0 + } + } + } + } + }; + const request = spec.buildRequests(bidRequests, bidderRequest); + const bids = spec.interpretResponse(serverResponse, request); + expect(bids).to.be.lengthOf(0); + }); + + it('should return empty bid response on 0 cpm', function () { + let serverResponse = { + body: { + decisions: { + '2f95c00074b931': { + adId: '0', + contents: [ + { + body: '<<<---- Creative --->>>' + } + ], + height: '300', + width: '250', + pricing: { + clearPrice: 0 + } + } + } + } + }; + const request = spec.buildRequests(bidRequests, bidderRequest); + const bids = spec.interpretResponse(serverResponse, request); + expect(bids).to.be.lengthOf(0); + }); + + it('should process a deal id', function () { + let serverResponse = { + body: { + decisions: { + '2f95c00074b931': { + adId: '0', + dealid: 'ABC90210', + contents: [ + { + body: '<<<---- Creative --->>>' + } + ], + height: '300', + width: '250', + pricing: { + clearPrice: 11.899999999999999 + } + } + } + } + }; + const request = spec.buildRequests(bidRequests, bidderRequest); + const bids = spec.interpretResponse(serverResponse, request); + expect(bids).to.be.lengthOf(1); + expect(bids[0].dealid).to.equal('ABC90210'); + }); + }); + }); + + describe('getUserSyncs', () => { + let testParams = [ + { + name: 'iframe/no gdpr or ccpa', + arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, null], + expect: { + type: 'iframe', + pixels: ['https://cdn.connectad.io/connectmyusers.php?'] + } + }, + { + name: 'iframe/gdpr', + arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, {gdprApplies: true, consentString: '234234'}], + expect: { + type: 'iframe', + pixels: ['https://cdn.connectad.io/connectmyusers.php?gdpr=1&gdpr_consent=234234&'] + } + }, + { + name: 'iframe/ccpa', + arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, null, 'YN12'], + expect: { + type: 'iframe', + pixels: ['https://cdn.connectad.io/connectmyusers.php?us_privacy=YN12&'] + } + }, + { + name: 'iframe/ccpa & gdpr', + arguments: [{ iframeEnabled: true, pixelEnabled: true }, {}, {gdprApplies: true, consentString: '234234'}, 'YN12'], + expect: { + type: 'iframe', + pixels: ['https://cdn.connectad.io/connectmyusers.php?gdpr=1&gdpr_consent=234234&us_privacy=YN12&'] + } + } + ]; + + for (let i = 0; i < testParams.length; i++) { + let currParams = testParams[i]; + it(currParams.name, function () { + const result = spec.getUserSyncs.apply(this, currParams.arguments); + expect(result).to.have.lengthOf(currParams.expect.pixels.length); + for (let ix = 0; ix < currParams.expect.pixels.length; ix++) { + expect(result[ix].url).to.equal(currParams.expect.pixels[ix]); + expect(result[ix].type).to.equal(currParams.expect.type); + } + }); + } + }); +}); diff --git a/test/spec/modules/consentManagementUsp_spec.js b/test/spec/modules/consentManagementUsp_spec.js index 05f98d1c6a3..2e8d7db92b5 100644 --- a/test/spec/modules/consentManagementUsp_spec.js +++ b/test/spec/modules/consentManagementUsp_spec.js @@ -5,10 +5,10 @@ import { consentAPI, consentTimeout, staticConsentData -} from 'modules/consentManagementUsp'; -import * as utils from 'src/utils'; -import { config } from 'src/config'; -import { uspDataHandler } from 'src/adapterManager'; +} from 'modules/consentManagementUsp.js'; +import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; +import { uspDataHandler } from 'src/adapterManager.js'; let assert = require('chai').assert; let expect = require('chai').expect; diff --git a/test/spec/modules/consentManagement_spec.js b/test/spec/modules/consentManagement_spec.js index 9731164c655..c4f6fe70dd1 100644 --- a/test/spec/modules/consentManagement_spec.js +++ b/test/spec/modules/consentManagement_spec.js @@ -1,9 +1,8 @@ -import {setConsentConfig, requestBidsHook, resetConsentData, userCMP, consentTimeout, allowAuction, staticConsentData} from 'modules/consentManagement'; -import {gdprDataHandler} from 'src/adapterManager'; -import * as utils from 'src/utils'; -import { config } from 'src/config'; +import { setConsentConfig, requestBidsHook, resetConsentData, userCMP, consentTimeout, allowAuction, staticConsentData, gdprScope } from 'modules/consentManagement.js'; +import { gdprDataHandler } from 'src/adapterManager.js'; +import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; -let assert = require('chai').assert; let expect = require('chai').expect; describe('consentManagement', function () { @@ -26,16 +25,17 @@ describe('consentManagement', function () { 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); }); - it('should exit consent manager if config is not an object', function() { + it('should exit consent manager if config is not an object', function () { setConsentConfig(''); expect(userCMP).to.be.undefined; sinon.assert.calledOnce(utils.logWarn); }); - it('should exit consent manager if gdpr not set with new config structure', function() { + it('should exit consent manager if gdpr not set with new config structure', function () { setConsentConfig({ usp: { cmpApi: 'iab', timeout: 50 } }); expect(userCMP).to.be.undefined; sinon.assert.calledOnce(utils.logWarn); @@ -45,23 +45,24 @@ describe('consentManagement', function () { describe('valid setConsentConfig value', function () { afterEach(function () { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); it('results in all user settings overriding system defaults', function () { let allConfig = { cmpApi: 'iab', timeout: 7500, - allowAuctionWithoutConsent: false + allowAuctionWithoutConsent: false, + defaultGdprScope: true }; setConsentConfig(allConfig); expect(userCMP).to.be.equal('iab'); expect(consentTimeout).to.be.equal(7500); expect(allowAuction).to.be.false; + expect(gdprScope).to.be.true; }); - it('should use new consent manager config structure for gdpr', function() { + it('should use new consent manager config structure for gdpr', function () { setConsentConfig({ gdpr: { cmpApi: 'daa', timeout: 8700 } }); @@ -70,7 +71,7 @@ describe('consentManagement', function () { expect(consentTimeout).to.be.equal(8700); }); - it('should ignore config.usp and use config.gdpr, with default cmpApi', function() { + it('should ignore config.usp and use config.gdpr, with default cmpApi', function () { setConsentConfig({ gdpr: { timeout: 5000 }, usp: { cmpApi: 'daa', timeout: 50 } @@ -80,7 +81,7 @@ describe('consentManagement', function () { expect(consentTimeout).to.be.equal(5000); }); - it('should ignore config.usp and use config.gdpr, with default cmpAip and timeout', function() { + it('should ignore config.usp and use config.gdpr, with default cmpAip and timeout', function () { setConsentConfig({ gdpr: {}, usp: { cmpApi: 'daa', timeout: 50 } @@ -90,7 +91,7 @@ describe('consentManagement', function () { expect(consentTimeout).to.be.equal(10000); }); - it('should recognize config.gdpr, with default cmpAip and timeout', function() { + it('should recognize config.gdpr, with default cmpAip and timeout', function () { setConsentConfig({ gdpr: {} }); @@ -99,7 +100,7 @@ describe('consentManagement', function () { expect(consentTimeout).to.be.equal(10000); }); - it('should fallback to old consent manager config object if no config.gdpr', function() { + it('should fallback to old consent manager config object if no config.gdpr', function () { setConsentConfig({ cmpApi: 'iab', timeout: 3333, @@ -110,15 +111,15 @@ describe('consentManagement', function () { expect(userCMP).to.be.equal('iab'); expect(consentTimeout).to.be.equal(3333); expect(allowAuction).to.be.equal(false); + expect(gdprScope).to.be.equal(false); }); }); describe('static consent string setConsentConfig value', () => { afterEach(() => { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); }); - it('results in user settings overriding system defaults', () => { + it('results in user settings overriding system defaults for v1 spec', () => { let staticConfig = { cmpApi: 'static', timeout: 7500, @@ -154,361 +155,7 @@ describe('consentManagement', function () { '2': true, '3': true, '4': true, - '5': false, - '6': true, - '7': true, - '8': true, - '9': true, - '10': true, - '11': true, - '12': true, - '13': true, - '14': true, - '15': true, - '16': true, - '17': true, - '18': true, - '19': true, - '20': true, - '21': true, - '22': true, - '23': true, - '24': true, - '25': true, - '26': true, - '27': true, - '28': true, - '29': true, - '30': true, - '31': true, - '32': true, - '33': true, - '34': true, - '35': true, - '36': true, - '37': true, - '38': true, - '39': true, - '40': true, - '41': true, - '42': true, - '43': true, - '44': true, - '45': true, - '46': true, - '47': true, - '48': true, - '49': true, - '50': true, - '51': true, - '52': true, - '53': true, - '54': false, - '55': true, - '56': true, - '57': true, - '58': true, - '59': true, - '60': true, - '61': true, - '62': true, - '63': true, - '64': true, - '65': true, - '66': true, - '67': true, - '68': true, - '69': true, - '70': true, - '71': true, - '72': true, - '73': true, - '74': true, - '75': true, - '76': true, - '77': true, - '78': true, - '79': true, - '80': true, - '81': true, - '82': true, - '83': false, - '84': true, - '85': true, - '86': true, - '87': true, - '88': true, - '89': true, - '90': true, - '91': true, - '92': true, - '93': true, - '94': true, - '95': true, - '96': false, - '97': true, - '98': true, - '99': false, - '100': true, - '101': true, - '102': true, - '103': false, - '104': true, - '105': true, - '106': false, - '107': false, - '108': true, - '109': true, - '110': true, - '111': true, - '112': true, - '113': true, - '114': true, - '115': true, - '116': false, - '117': false, - '118': false, - '119': true, - '120': true, - '121': false, - '122': true, - '123': false, - '124': true, - '125': true, - '126': true, - '127': true, - '128': true, - '129': true, - '130': true, - '131': true, - '132': true, - '133': true, - '134': true, - '135': false, - '136': true, - '137': false, - '138': true, - '139': true, - '140': true, - '141': true, - '142': true, - '143': true, - '144': true, - '145': true, - '146': false, - '147': true, - '148': true, - '149': true, - '150': true, - '151': true, - '152': false, - '153': true, - '154': true, - '155': true, - '156': true, - '157': true, - '158': true, - '159': true, - '160': true, - '161': true, - '162': true, - '163': true, - '164': true, - '165': true, - '166': false, - '167': true, - '168': true, - '169': true, - '170': true, - '171': false, - '172': false, - '173': true, - '174': true, - '175': true, - '176': false, - '177': true, - '178': false, - '179': true, - '180': true, - '181': false, - '182': true, - '183': true, - '184': false, - '185': true, - '186': false, - '187': false, - '188': true, - '189': true, - '190': true, - '191': false, - '192': true, - '193': true, - '194': true, - '195': true, - '196': false, - '197': true, - '198': true, - '199': true, - '200': true, - '201': true, - '202': true, - '203': true, - '204': false, - '205': true, - '206': false, - '207': false, - '208': true, - '209': true, - '210': true, - '211': true, - '212': true, - '213': true, - '214': false, - '215': true, - '216': false, - '217': true, - '218': false, - '219': false, - '220': false, - '221': false, - '222': false, - '223': false, - '224': true, - '225': true, - '226': true, - '227': true, - '228': true, - '229': true, - '230': true, - '231': false, - '232': true, - '233': false, - '234': true, - '235': true, - '236': true, - '237': true, - '238': true, - '239': true, - '240': true, - '241': true, - '242': false, - '243': false, - '244': true, - '245': true, - '246': true, - '247': false, - '248': true, - '249': true, - '250': false, - '251': false, - '252': true, - '253': true, - '254': true, - '255': true, - '256': true, - '257': true, - '258': true, - '259': true, - '260': true, - '261': false, - '262': true, - '263': false, - '264': true, - '265': true, - '266': true, - '267': false, - '268': false, - '269': true, - '270': true, - '271': false, - '272': true, - '273': true, - '274': true, - '275': true, - '276': true, - '277': true, - '278': true, - '279': true, - '280': true, - '281': true, - '282': true, - '283': false, - '284': true, - '285': true, - '286': false, - '287': false, - '288': true, - '289': true, - '290': true, - '291': true, - '292': false, - '293': false, - '294': true, - '295': true, - '296': false, - '297': true, - '298': false, - '299': true, - '300': false, - '301': true, - '302': true, - '303': true, - '304': true, - '305': false, - '306': false, - '307': false, - '308': true, - '309': true, - '310': true, - '311': false, - '312': false, - '313': false, - '314': true, - '315': true, - '316': true, - '317': true, - '318': true, - '319': true, - '320': true, - '321': false, - '322': false, - '323': true, - '324': false, - '325': true, - '326': true, - '327': false, - '328': true, - '329': false, - '330': false, - '331': true, - '332': false, - '333': true, - '334': false, - '335': false, - '336': false, - '337': false, - '338': false, - '339': true, - '340': false, - '341': false, - '342': false, - '343': false, - '344': false, - '345': true, - '346': false, - '347': false, - '348': false, - '349': true, - '350': false, - '351': false, - '352': false, - '353': false, - '354': true, - '355': false, - '356': false, - '357': false, - '358': false, - '359': true + '5': false } } } @@ -520,6 +167,87 @@ describe('consentManagement', function () { expect(allowAuction).to.be.false; expect(staticConsentData).to.be.equal(staticConfig.consentData); }); + + it('results in user settings overriding system defaults for v2 spec', () => { + let staticConfig = { + cmpApi: 'static', + timeout: 7500, + allowAuctionWithoutConsent: false, + consentData: { + getTCData: { + 'tcString': 'COuqj-POu90rDBcBkBENAZCgAPzAAAPAACiQFwwBAABAA1ADEAbQC4YAYAAgAxAG0A', + 'cmpId': 92, + 'cmpVersion': 100, + 'tcfPolicyVersion': 2, + 'gdprApplies': true, + 'isServiceSpecific': true, + 'useNonStandardStacks': false, + 'purposeOneTreatment': false, + 'publisherCC': 'US', + 'cmpStatus': 'loaded', + 'eventStatus': 'tcloaded', + 'outOfBand': { + 'allowedVendors': {}, + 'discloseVendors': {} + }, + 'purpose': { + 'consents': { + '1': true, + '2': true, + '3': true + }, + 'legitimateInterests': { + '1': false, + '2': false, + '3': false + } + }, + 'vendor': { + 'consents': { + '1': false, + '2': true, + '3': false + }, + 'legitimateInterests': { + '1': false, + '2': true, + '3': false, + '4': false, + '5': false + } + }, + 'specialFeatureOptins': { + '1': false, + '2': false + }, + 'restrictions': {}, + 'publisher': { + 'consents': { + '1': false, + '2': false, + '3': false + }, + 'legitimateInterests': { + '1': false, + '2': false, + '3': false + }, + 'customPurpose': { + 'consents': {}, + 'legitimateInterests': {} + } + } + } + } + }; + + 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(gdprScope).to.be.equal(false); + expect(staticConsentData).to.be.equal(staticConfig.consentData); + }); }); }); @@ -554,7 +282,6 @@ describe('consentManagement', function () { utils.logWarn.restore(); utils.logError.restore(); config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); resetConsentData(); }); @@ -593,12 +320,11 @@ describe('consentManagement', function () { beforeEach(function () { didHookReturn = false; - window.__cmp = function() {}; + window.__cmp = function () { }; }); afterEach(function () { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); cmpStub.restore(); delete window.__cmp; resetConsentData(); @@ -614,7 +340,7 @@ describe('consentManagement', function () { args[2](testConsentData); }); setConsentConfig(goodConfigWithAllowAuction); - requestBidsHook(() => {}, {}); + requestBidsHook(() => { }, {}); cmpStub.restore(); // reset the stub to ensure it wasn't called during the second round of calls @@ -632,123 +358,66 @@ describe('consentManagement', function () { expect(consent.gdprApplies).to.be.true; sinon.assert.notCalled(cmpStub); }); - }); - describe('CMP workflow for safeframe page', function () { - let registerStub = sinon.stub(); - - beforeEach(function () { - didHookReturn = false; - window.$sf = { - ext: { - register: function() {}, - cmp: function() {} - } + it('should not set consent.gdprApplies to true if defaultGdprScope is true', function () { + let testConsentData = { + gdprApplies: false, + consentData: 'xyz' }; - sinon.stub(utils, 'logError'); - sinon.stub(utils, 'logWarn'); - }); - afterEach(function () { - delete window.$sf; - config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); - registerStub.restore(); - utils.logError.restore(); - utils.logWarn.restore(); - resetConsentData(); - }); + cmpStub = sinon.stub(window, '__cmp').callsFake((...args) => { + args[2](testConsentData); + }); - it('should return the consent data from a safeframe callback', function () { - var testConsentData = { - data: { - msgName: 'cmpReturn', - vendorConsents: { - metadata: 'abc123def', - gdprApplies: true - }, - vendorConsentData: { - consentData: 'abc123def', - gdprApplies: true - } - } - }; - registerStub = sinon.stub(window.$sf.ext, 'register').callsFake((...args) => { - args[2](testConsentData.data.msgName, testConsentData.data); + setConsentConfig({ + cmpApi: 'iab', + timeout: 7500, + defaultGdprScope: true }); - setConsentConfig(goodConfigWithAllowAuction); requestBidsHook(() => { didHookReturn = true; - }, {adUnits: [{ sizes: [[300, 250]] }]}); + }, {}); + let consent = gdprDataHandler.getConsentData(); - sinon.assert.notCalled(utils.logWarn); - sinon.assert.notCalled(utils.logError); - expect(didHookReturn).to.be.true; - expect(consent.consentString).to.equal('abc123def'); - expect(consent.gdprApplies).to.be.true; + expect(consent.gdprApplies).to.be.false; }); }); - describe('CMP workflow for iframed page', function () { - let ifr = null; - let stringifyResponse = false; - - beforeEach(function () { - sinon.stub(utils, 'logError'); - sinon.stub(utils, 'logWarn'); - ifr = createIFrameMarker(); - window.addEventListener('message', cmpMessageHandler, false); - }); - - afterEach(function () { - config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); - delete window.__cmp; - utils.logError.restore(); - utils.logWarn.restore(); - resetConsentData(); - document.body.removeChild(ifr); - window.removeEventListener('message', cmpMessageHandler); - }); + describe('iframe tests', function () { + let cmpPostMessageCb = () => { }; + let stringifyResponse; - function createIFrameMarker() { - var ifr = document.createElement('iframe'); + function createIFrameMarker(frameName) { + let ifr = document.createElement('iframe'); ifr.width = 0; ifr.height = 0; - ifr.name = '__cmpLocator'; + ifr.name = frameName; document.body.appendChild(ifr); return ifr; } - function cmpMessageHandler(event) { - if (event && event.data) { - var data = event.data; - if (data.__cmpCall) { - var callId = data.__cmpCall.callId; - var returnValue = null; - var response = { - __cmpReturn: { - callId, - returnValue: { - consentData: 'encoded_consent_data_via_post_message', - gdprApplies: true, - }, - success: true - } - }; - event.source.postMessage(stringifyResponse ? JSON.stringify(response) : response, '*'); + function creatCmpMessageHandler(prefix, returnValue) { + return function (event) { + if (event && event.data) { + let data = event.data; + if (data[`${prefix}Call`]) { + let callId = data[`${prefix}Call`].callId; + let response = { + [`${prefix}Return`]: { + callId, + returnValue, + success: true + } + }; + event.source.postMessage(stringifyResponse ? JSON.stringify(response) : response, '*'); + } } } } - // Run tests with JSON response and String response - // from CMP window postMessage listener. - testIFramedPage('with/JSON response', false); - testIFramedPage('with/String response', true); - - function testIFramedPage(testName, messageFormatString) { + function testIFramedPage(testName, messageFormatString, tarConsentString, ver) { it(`should return the consent string from a postmessage + addEventListener response - ${testName}`, (done) => { stringifyResponse = messageFormatString; setConsentConfig(goodConfigWithAllowAuction); @@ -756,96 +425,285 @@ describe('consentManagement', function () { let consent = gdprDataHandler.getConsentData(); sinon.assert.notCalled(utils.logWarn); sinon.assert.notCalled(utils.logError); - expect(consent.consentString).to.equal('encoded_consent_data_via_post_message'); + expect(consent.consentString).to.equal(tarConsentString); expect(consent.gdprApplies).to.be.true; + expect(consent.apiVersion).to.equal(ver); done(); }, {}); }); } + + beforeEach(function () { + sinon.stub(utils, 'logError'); + sinon.stub(utils, 'logWarn'); + }); + + afterEach(function () { + utils.logError.restore(); + utils.logWarn.restore(); + config.resetConfig(); + resetConsentData(); + }); + + describe('v1 CMP workflow for safeframe page', function () { + let registerStub = sinon.stub(); + let ifrSf = null; + beforeEach(function () { + didHookReturn = false; + window.$sf = { + ext: { + register: function () { }, + cmp: function () { } + } + }; + ifrSf = createIFrameMarker('__cmpLocator'); + }); + + afterEach(function () { + delete window.$sf; + registerStub.restore(); + document.body.removeChild(ifrSf); + }); + + it('should return the consent data from a safeframe callback', function () { + let testConsentData = { + data: { + msgName: 'cmpReturn', + vendorConsents: { + metadata: 'abc123def', + gdprApplies: true + }, + vendorConsentData: { + consentData: 'abc123def', + gdprApplies: true + } + } + }; + registerStub = sinon.stub(window.$sf.ext, 'register').callsFake((...args) => { + args[2](testConsentData.data.msgName, testConsentData.data); + }); + + setConsentConfig(goodConfigWithAllowAuction); + requestBidsHook(() => { + didHookReturn = true; + }, { adUnits: [{ sizes: [[300, 250]] }] }); + let consent = gdprDataHandler.getConsentData(); + + sinon.assert.notCalled(utils.logWarn); + sinon.assert.notCalled(utils.logError); + expect(didHookReturn).to.be.true; + expect(consent.consentString).to.equal('abc123def'); + expect(consent.gdprApplies).to.be.true; + expect(consent.apiVersion).to.equal(1); + }); + }); + + describe('v1 CMP workflow for iframe pages', function () { + stringifyResponse = false; + let ifr1 = null; + + beforeEach(function () { + ifr1 = createIFrameMarker('__cmpLocator'); + cmpPostMessageCb = creatCmpMessageHandler('__cmp', { + consentData: 'encoded_consent_data_via_post_message', + gdprApplies: true, + }); + window.addEventListener('message', cmpPostMessageCb, false); + }); + + afterEach(function () { + delete window.__cmp; // deletes the local copy made by the postMessage CMP call function + document.body.removeChild(ifr1); + window.removeEventListener('message', cmpPostMessageCb); + }); + + // Run tests with JSON response and String response + // from CMP window postMessage listener. + testIFramedPage('with/JSON response', false, 'encoded_consent_data_via_post_message', 1); + testIFramedPage('with/String response', true, 'encoded_consent_data_via_post_message', 1); + }); + + describe('v2 CMP workflow for iframe pages:', function () { + stringifyResponse = false; + let ifr2 = null; + + beforeEach(function () { + ifr2 = createIFrameMarker('__tcfapiLocator'); + cmpPostMessageCb = creatCmpMessageHandler('__tcfapi', { + tcString: 'abc12345234', + gdprApplies: true, + purposeOneTreatment: false, + eventStatus: 'tcloaded' + }); + window.addEventListener('message', cmpPostMessageCb, false); + }); + + afterEach(function () { + delete window.__tcfapi; // deletes the local copy made by the postMessage CMP call function + document.body.removeChild(ifr2); + window.removeEventListener('message', cmpPostMessageCb); + }); + + testIFramedPage('with/JSON response', false, 'abc12345234', 2); + testIFramedPage('with/String response', true, 'abc12345234', 2); + }); }); - describe('CMP workflow for normal pages:', function () { + describe('direct calls to CMP API tests', function () { let cmpStub = sinon.stub(); beforeEach(function () { didHookReturn = false; sinon.stub(utils, 'logError'); sinon.stub(utils, 'logWarn'); - window.__cmp = function() {}; }); afterEach(function () { config.resetConfig(); - $$PREBID_GLOBAL$$.requestBids.removeAll(); cmpStub.restore(); utils.logError.restore(); utils.logWarn.restore(); - delete window.__cmp; resetConsentData(); }); - it('performs lookup check and stores consentData for a valid existing user', function () { - let testConsentData = { - gdprApplies: true, - consentData: 'BOJy+UqOJy+UqABAB+AAAAAZ+A==' - }; - cmpStub = sinon.stub(window, '__cmp').callsFake((...args) => { - args[2](testConsentData); + describe('v1 CMP workflow for normal pages:', function () { + beforeEach(function () { + window.__cmp = function () { }; }); - setConsentConfig(goodConfigWithAllowAuction); + afterEach(function () { + delete window.__cmp; + }); - requestBidsHook(() => { - didHookReturn = true; - }, {}); - let consent = gdprDataHandler.getConsentData(); + it('performs lookup check and stores consentData for a valid existing user', function () { + let testConsentData = { + gdprApplies: true, + consentData: 'BOJy+UqOJy+UqABAB+AAAAAZ+A==' + }; + cmpStub = sinon.stub(window, '__cmp').callsFake((...args) => { + args[2](testConsentData); + }); - sinon.assert.notCalled(utils.logWarn); - sinon.assert.notCalled(utils.logError); - expect(didHookReturn).to.be.true; - expect(consent.consentString).to.equal(testConsentData.consentData); - expect(consent.gdprApplies).to.be.true; + setConsentConfig(goodConfigWithAllowAuction); + + requestBidsHook(() => { + 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.consentData); + expect(consent.gdprApplies).to.be.true; + expect(consent.apiVersion).to.equal(1); + }); }); - it('throws an error when processCmpData check failed while config had allowAuction set to false', function () { - let testConsentData = {}; - let bidsBackHandlerReturn = false; + describe('v2 CMP workflow for normal pages:', function () { + beforeEach(function() { + window.__tcfapi = function () { }; + }); - cmpStub = sinon.stub(window, '__cmp').callsFake((...args) => { - args[2](testConsentData); + afterEach(function () { + delete window.__tcfapi; }); - setConsentConfig(goodConfigWithCancelAuction); + it('performs lookup check and stores consentData for a valid existing user', function () { + let testConsentData = { + tcString: 'abc12345234', + gdprApplies: true, + purposeOneTreatment: false, + eventStatus: 'tcloaded' + }; + cmpStub = sinon.stub(window, '__tcfapi').callsFake((...args) => { + args[2](testConsentData, true); + }); - requestBidsHook(() => { - didHookReturn = true; - }, { bidsBackHandler: () => bidsBackHandlerReturn = true }); - let consent = gdprDataHandler.getConsentData(); + setConsentConfig(goodConfigWithAllowAuction); - sinon.assert.calledOnce(utils.logError); - expect(didHookReturn).to.be.false; - expect(bidsBackHandlerReturn).to.be.true; - expect(consent).to.be.null; - }); + requestBidsHook(() => { + 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); + expect(consent.gdprApplies).to.be.true; + expect(consent.apiVersion).to.equal(2); + }); - it('throws a warning + stores consentData + calls callback when processCmpData check failed while config had allowAuction set to true', function () { - let testConsentData = {}; + it('throws an error when processCmpData check failed while config had allowAuction set to false', function () { + let testConsentData = {}; + let bidsBackHandlerReturn = false; - cmpStub = sinon.stub(window, '__cmp').callsFake((...args) => { - args[2](testConsentData); + cmpStub = sinon.stub(window, '__tcfapi').callsFake((...args) => { + args[2](testConsentData); + }); + + setConsentConfig(goodConfigWithCancelAuction); + + requestBidsHook(() => { + didHookReturn = true; + }, { bidsBackHandler: () => bidsBackHandlerReturn = true }); + let consent = gdprDataHandler.getConsentData(); + + sinon.assert.calledOnce(utils.logError); + expect(didHookReturn).to.be.false; + expect(bidsBackHandlerReturn).to.be.true; + expect(consent).to.be.null; }); - setConsentConfig(goodConfigWithAllowAuction); + 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, true); + }); + + setConsentConfig({ + cmpApi: 'iab', + timeout: 7500, + defaultGdprScope: true + }); - requestBidsHook(() => { - didHookReturn = true; - }, {}); - let consent = gdprDataHandler.getConsentData(); + requestBidsHook(() => { + 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); + expect(consent.gdprApplies).to.be.true; + expect(consent.apiVersion).to.equal(2); + }); - sinon.assert.calledOnce(utils.logWarn); - expect(didHookReturn).to.be.true; - expect(consent.consentString).to.be.undefined; - expect(consent.gdprApplies).to.be.undefined; + it('throws a warning + stores consentData + calls callback when processCmpData check failed while config had allowAuction set to true', function () { + let testConsentData = {}; + + cmpStub = sinon.stub(window, '__tcfapi').callsFake((...args) => { + args[2](testConsentData); + }); + + setConsentConfig(goodConfigWithAllowAuction); + + requestBidsHook(() => { + didHookReturn = true; + }, {}); + let consent = gdprDataHandler.getConsentData(); + + sinon.assert.calledOnce(utils.logWarn); + expect(didHookReturn).to.be.true; + expect(consent.consentString).to.be.undefined; + expect(consent.gdprApplies).to.be.false; + expect(consent.apiVersion).to.equal(2); + }); }); }); }); diff --git a/test/spec/modules/consumableBidAdapter_spec.js b/test/spec/modules/consumableBidAdapter_spec.js index 7785454f8e1..44076194885 100644 --- a/test/spec/modules/consumableBidAdapter_spec.js +++ b/test/spec/modules/consumableBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; -import {spec} from 'modules/consumableBidAdapter'; -import {createBid} from 'src/bidfactory'; +import {spec} from 'modules/consumableBidAdapter.js'; +import {createBid} from 'src/bidfactory.js'; const ENDPOINT = 'https://e.serverbid.com/api/v2'; const SMARTSYNC_CALLBACK = 'serverbidCallBids'; diff --git a/test/spec/modules/convergeBidAdapter_spec.js b/test/spec/modules/convergeBidAdapter_spec.js new file mode 100644 index 00000000000..e92ed475497 --- /dev/null +++ b/test/spec/modules/convergeBidAdapter_spec.js @@ -0,0 +1,899 @@ +import { expect } from 'chai'; +import { spec, resetUserSync, getSyncUrl } from 'modules/convergeBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; + +describe('ConvergeAdapter', 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': 'converge', + 'params': { + 'uid': '1' + }, + '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 = { + 'uid': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + function parseRequest(url) { + const res = {}; + url.split('&').forEach((it) => { + const couple = it.split('='); + res[couple[0]] = decodeURIComponent(couple[1]); + }); + return res; + } + + const bidderRequest = { + refererInfo: { + referer: 'https://example.com' + } + }; + const referrer = bidderRequest.refererInfo.referer; + + let bidRequests = [ + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90], [300, 250]], + 'bidId': '3150ccb55da321', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '60' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '42dbe3a7168a6a', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + } + ]; + + 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.have.property('u', referrer); + expect(payload).to.have.property('pt', 'net'); + expect(payload).to.have.property('auids', '59'); + expect(payload).to.have.property('sizes', '300x250,300x600'); + expect(payload).to.have.property('r', '22edbae2733bf6'); + expect(payload).to.have.property('wrapperType', 'Prebid_js'); + expect(payload).to.have.property('wrapperVersion', '$prebid.version$'); + }); + + it('sizes must not be duplicated', function () { + 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); + expect(payload).to.have.property('pt', 'net'); + expect(payload).to.have.property('auids', '59,59,60'); + expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); + expect(payload).to.have.property('r', '22edbae2733bf6'); + }); + + it('pt parameter must be "gross" if params.priceType === "gross"', function () { + bidRequests[1].params.priceType = 'gross'; + 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); + expect(payload).to.have.property('pt', 'gross'); + expect(payload).to.have.property('auids', '59,59,60'); + expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); + expect(payload).to.have.property('r', '22edbae2733bf6'); + delete bidRequests[1].params.priceType; + }); + + it('pt parameter must be "net" or "gross"', function () { + bidRequests[1].params.priceType = 'some'; + 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); + expect(payload).to.have.property('pt', 'net'); + expect(payload).to.have.property('auids', '59,59,60'); + expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); + expect(payload).to.have.property('r', '22edbae2733bf6'); + delete bidRequests[1].params.priceType; + }); + + it('if gdprConsent is present payload must have gdpr params', function () { + const bidderRequestWithGDPR = Object.assign({gdprConsent: {consentString: 'AAA', gdprApplies: true}}, bidderRequest); + const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.have.property('gdpr_consent', 'AAA'); + expect(payload).to.have.property('gdpr_applies', '1'); + }); + + it('if gdprApplies is false gdpr_applies must be 0', function () { + const bidderRequestWithGDPR = Object.assign({gdprConsent: {consentString: 'AAA', gdprApplies: false}}, bidderRequest); + const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.have.property('gdpr_consent', 'AAA'); + expect(payload).to.have.property('gdpr_applies', '0'); + }); + + it('if gdprApplies is undefined gdpr_applies must be 1', function () { + const bidderRequestWithGDPR = Object.assign({gdprConsent: {consentString: 'AAA'}}, bidderRequest); + const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); + expect(payload).to.have.property('gdpr_consent', 'AAA'); + expect(payload).to.have.property('gdpr_applies', '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('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: '59', + 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(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': ['5'] + }, { + 'key': 'multiValMixed', + 'value': ['value1', '2', 'value3'] + }, { + 'key': 'singleValNum', + 'value': ['123'] + }, { + 'key': 'emptyStr' + }, { + 'key': 'emptyArr' + }]); + }); + }); + + describe('interpretResponse', function () { + const responses = [ + {'bid': [{'price': 1.15, 'adm': '
test content 1
', 'auid': 59, 'h': 250, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.5, 'adm': '
test content 2
', 'auid': 60, 'h': 600, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.15, 'adm': '
test content 3
', 'auid': 59, 'h': 90, 'w': 728}], 'seat': '1'}, + {'bid': [{'price': 0, 'auid': 61, 'h': 250, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0, 'adm': '
test content 5
', 'h': 250, 'w': 300}], 'seat': '1'}, + undefined, + {'bid': [], 'seat': '1'}, + {'seat': '1'}, + ]; + + it('should get correct bid response', function () { + const bidRequests = [ + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '659423fff799cb', + 'bidderRequestId': '5f2009617a7c0a', + 'auctionId': '1cbd2feafe5e8b', + } + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '659423fff799cb', + 'cpm': 1.15, + 'creativeId': 59, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + } + ]; + + const result = spec.interpretResponse({'body': {'seatbid': [responses[0]]}}, request); + expect(result).to.deep.equal(expectedResponse); + }); + + it('should get correct multi bid response', function () { + const bidRequests = [ + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '300bfeb0d71a5b', + 'bidderRequestId': '2c2bb1972df9a', + 'auctionId': '1fa09aee5c8c99', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '60' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '4dff80cc4ee346', + 'bidderRequestId': '2c2bb1972df9a', + 'auctionId': '1fa09aee5c8c99', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '5703af74d0472a', + 'bidderRequestId': '2c2bb1972df9a', + 'auctionId': '1fa09aee5c8c99', + } + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '300bfeb0d71a5b', + 'cpm': 1.15, + 'creativeId': 59, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '4dff80cc4ee346', + 'cpm': 0.5, + 'creativeId': 60, + 'dealId': undefined, + 'width': 300, + 'height': 600, + 'ad': '
test content 2
', + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '5703af74d0472a', + 'cpm': 0.15, + 'creativeId': 59, + 'dealId': undefined, + 'width': 728, + 'height': 90, + 'ad': '
test content 3
', + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + } + ]; + + const result = spec.interpretResponse({'body': {'seatbid': responses.slice(0, 3)}}, request); + expect(result).to.deep.equal(expectedResponse); + }); + + it('handles wrong and nobid responses', function () { + const bidRequests = [ + { + 'bidder': 'converge', + 'params': { + 'uid': '61' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '300bfeb0d7190gf', + 'bidderRequestId': '2c2bb1972d23af', + 'auctionId': '1fa09aee5c84d34', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '65' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '300bfeb0d71321', + 'bidderRequestId': '2c2bb1972d23af', + 'auctionId': '1fa09aee5c84d34', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '70' + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '300bfeb0d7183bb', + 'bidderRequestId': '2c2bb1972d23af', + 'auctionId': '1fa09aee5c84d34', + } + ]; + const request = spec.buildRequests(bidRequests); + const result = spec.interpretResponse({'body': {'seatbid': responses.slice(3)}}, request); + expect(result.length).to.equal(0); + }); + + it('complicated case', function () { + const fullResponse = [ + {'bid': [{'price': 1.15, 'adm': '
test content 1
', 'auid': 59, 'h': 250, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.5, 'adm': '
test content 2
', 'auid': 60, 'h': 600, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.15, 'adm': '
test content 3
', 'auid': 59, 'h': 90, 'w': 728}], 'seat': '1'}, + {'bid': [{'price': 0.15, 'adm': '
test content 4
', 'auid': 59, 'h': 600, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.5, 'adm': '
test content 5
', 'auid': 60, 'h': 600, 'w': 350}], 'seat': '1'}, + ]; + const bidRequests = [ + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '2164be6358b9', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '326bde7fbf69', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '60' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '4e111f1b66e4', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '26d6f897b516', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '60' + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '1751cd90161', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + } + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '2164be6358b9', + 'cpm': 1.15, + 'creativeId': 59, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '4e111f1b66e4', + 'cpm': 0.5, + 'creativeId': 60, + 'dealId': undefined, + 'width': 300, + 'height': 600, + 'ad': '
test content 2
', + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '26d6f897b516', + 'cpm': 0.15, + 'creativeId': 59, + 'dealId': undefined, + 'width': 728, + 'height': 90, + 'ad': '
test content 3
', + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '326bde7fbf69', + 'cpm': 0.15, + 'creativeId': 59, + 'dealId': undefined, + 'width': 300, + 'height': 600, + 'ad': '
test content 4
', + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + } + ]; + + const result = spec.interpretResponse({'body': {'seatbid': fullResponse}}, request); + expect(result).to.deep.equal(expectedResponse); + }); + + it('dublicate uids and sizes in one slot', function () { + const fullResponse = [ + {'bid': [{'price': 1.15, 'adm': '
test content 1
', 'auid': 59, 'h': 250, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.5, 'adm': '
test content 2
', 'auid': 59, 'h': 250, 'w': 300}], 'seat': '1'}, + ]; + const bidRequests = [ + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '5126e301f4be', + 'bidderRequestId': '171c5405a390', + 'auctionId': '35bcbc0f7e79c', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '57b2ebe70e16', + 'bidderRequestId': '171c5405a390', + 'auctionId': '35bcbc0f7e79c', + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '59' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '225fcd44b18c', + 'bidderRequestId': '171c5405a390', + 'auctionId': '35bcbc0f7e79c', + } + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '5126e301f4be', + 'cpm': 1.15, + 'creativeId': 59, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '57b2ebe70e16', + 'cpm': 0.5, + 'creativeId': 59, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 2
', + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'banner', + 'netRevenue': true, + 'ttl': 360, + } + ]; + + const result = spec.interpretResponse({'body': {'seatbid': fullResponse}}, request); + expect(result).to.deep.equal(expectedResponse); + }); + }); + + it('should get correct video bid response', function () { + const bidRequests = [ + { + 'bidder': 'converge', + 'params': { + 'uid': '58' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '57dfefb80eca', + 'bidderRequestId': '20394420a762a2', + 'auctionId': '140132d07b031', + 'mediaTypes': { + 'video': { + 'context': 'instream' + } + } + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '60' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': 'e893c787c22dd', + 'bidderRequestId': '20394420a762a2', + 'auctionId': '140132d07b031', + 'mediaTypes': { + 'video': { + 'context': 'instream' + } + } + } + ]; + const response = [ + {'bid': [{'price': 1.15, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 58, content_type: 'video', w: 300, h: 600}], 'seat': '2'}, + {'bid': [{'price': 1.00, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 60, content_type: 'video'}], 'seat': '2'} + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '57dfefb80eca', + 'cpm': 1.15, + 'creativeId': 58, + 'dealId': undefined, + 'width': 300, + 'height': 600, + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'video', + 'netRevenue': true, + 'ttl': 360, + 'vastXml': '\n<\/Ad>\n<\/VAST>', + 'adResponse': { + 'content': '\n<\/Ad>\n<\/VAST>' + } + } + ]; + + const result = spec.interpretResponse({'body': {'seatbid': response}}, request); + expect(result).to.deep.equal(expectedResponse); + }); + + it('should have right renderer in the bid response', function () { + const spySetRenderer = sinon.spy(); + const stubRenderer = { + setRender: spySetRenderer + }; + const spyRendererInstall = sinon.spy(function() { return stubRenderer; }); + const stubRendererConst = { + install: spyRendererInstall + }; + const bidRequests = [ + { + 'bidder': 'converge', + 'params': { + 'uid': '58' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': 'e6e65553fc8', + 'bidderRequestId': '1380f393215dc7', + 'auctionId': '10b8d2f3c697e3', + 'mediaTypes': { + 'video': { + 'context': 'outstream' + } + } + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '60' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': 'c8fdcb3f269f', + 'bidderRequestId': '1380f393215dc7', + 'auctionId': '10b8d2f3c697e3' + }, + { + 'bidder': 'converge', + 'params': { + 'uid': '61' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '1de036c37685', + 'bidderRequestId': '1380f393215dc7', + 'auctionId': '10b8d2f3c697e3', + 'renderer': {} + } + ]; + const response = [ + {'bid': [{'price': 1.15, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 58, content_type: 'video', w: 300, h: 600}], 'seat': '2'}, + {'bid': [{'price': 1.00, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 60, content_type: 'video', w: 300, h: 250}], 'seat': '2'}, + {'bid': [{'price': 1.20, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 61, content_type: 'video', w: 300, h: 250}], 'seat': '2'} + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': 'e6e65553fc8', + 'cpm': 1.15, + 'creativeId': 58, + 'dealId': undefined, + 'width': 300, + 'height': 600, + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'video', + 'netRevenue': true, + 'ttl': 360, + 'vastXml': '\n<\/Ad>\n<\/VAST>', + 'adResponse': { + 'content': '\n<\/Ad>\n<\/VAST>' + }, + 'renderer': stubRenderer + }, + { + 'requestId': 'c8fdcb3f269f', + 'cpm': 1.00, + 'creativeId': 60, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'video', + 'netRevenue': true, + 'ttl': 360, + 'vastXml': '\n<\/Ad>\n<\/VAST>', + 'adResponse': { + 'content': '\n<\/Ad>\n<\/VAST>' + }, + 'renderer': stubRenderer + }, + { + 'requestId': '1de036c37685', + 'cpm': 1.20, + 'creativeId': 61, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'bidderCode': 'converge', + 'currency': 'EUR', + 'mediaType': 'video', + 'netRevenue': true, + 'ttl': 360, + 'vastXml': '\n<\/Ad>\n<\/VAST>', + 'adResponse': { + 'content': '\n<\/Ad>\n<\/VAST>' + } + } + ]; + + const result = spec.interpretResponse({'body': {'seatbid': response}}, request, stubRendererConst); + + expect(spySetRenderer.calledTwice).to.equal(true); + expect(spySetRenderer.getCall(0).args[0]).to.be.a('function'); + expect(spySetRenderer.getCall(1).args[0]).to.be.a('function'); + + expect(spyRendererInstall.calledTwice).to.equal(true); + expect(spyRendererInstall.getCall(0).args[0]).to.deep.equal({ + id: 'e6e65553fc8', + url: 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js', + loaded: false + }); + expect(spyRendererInstall.getCall(1).args[0]).to.deep.equal({ + id: 'c8fdcb3f269f', + url: 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js', + loaded: false + }); + + expect(result).to.deep.equal(expectedResponse); + }); + + describe('user sync', function () { + const syncUrl = getSyncUrl(); + + beforeEach(function () { + resetUserSync(); + }); + + it('should register sync image', function () { + let syncs = spec.getUserSyncs({ + pixelEnabled: true + }); + + expect(syncs).to.deep.equal({type: 'image', url: syncUrl}); + }); + + it('should not register sync image more than once', function () { + let syncs = spec.getUserSyncs({ + pixelEnabled: true + }); + expect(syncs).to.deep.equal({type: 'image', url: syncUrl}); + + // when called again, should still have only been called once + syncs = spec.getUserSyncs(); + expect(syncs).to.equal(undefined); + }); + + it('should pass gdpr params if consent is true', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + gdprApplies: true, consentString: 'foo' + })).to.deep.equal({ + type: 'image', url: `${syncUrl}&gdpr=1&gdpr_consent=foo` + }); + }); + + it('should pass gdpr params if consent is false', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + gdprApplies: false, consentString: 'foo' + })).to.deep.equal({ + type: 'image', url: `${syncUrl}&gdpr=0&gdpr_consent=foo` + }); + }); + + it('should pass gdpr param gdpr_consent only when gdprApplies is undefined', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: 'foo' + })).to.deep.equal({ + type: 'image', url: `${syncUrl}&gdpr_consent=foo` + }); + }); + + it('should pass no params if gdpr consentString is not defined', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {})).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr consentString is a number', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: 0 + })).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr consentString is null', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: null + })).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr consentString is a object', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: {} + })).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr is not defined', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined)).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass usPrivacy param if it is available', function() { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {}, '1YNN')).to.deep.equal({ + type: 'image', url: `${syncUrl}&us_privacy=1YNN` + }); + }); + }); +}); diff --git a/test/spec/modules/conversantBidAdapter_spec.js b/test/spec/modules/conversantBidAdapter_spec.js index 67dd721a059..d802cd288ef 100644 --- a/test/spec/modules/conversantBidAdapter_spec.js +++ b/test/spec/modules/conversantBidAdapter_spec.js @@ -1,6 +1,7 @@ import {expect} from 'chai'; -import {spec} from 'modules/conversantBidAdapter'; -import * as utils from 'src/utils'; +import {spec, storage} from 'modules/conversantBidAdapter.js'; +import * as utils from 'src/utils.js'; +import { createEidsArray } from 'modules/userId/eids.js'; describe('Conversant adapter tests', function() { const siteId = '108060'; @@ -209,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'); @@ -320,6 +321,12 @@ describe('Conversant adapter tests', function() { expect(payload).to.not.have.property('user'); // there should be no user by default }); + it('Verify override url', function() { + const testUrl = 'https://someurl?name=value'; + const request = spec.buildRequests([{params: {white_label_url: testUrl}}]); + expect(request.url).to.equal(testUrl); + }); + it('Verify interpretResponse', function() { const request = spec.buildRequests(bidRequests); const response = spec.interpretResponse(bidResponses, request); @@ -395,6 +402,7 @@ describe('Conversant adapter tests', function() { // add pubcid to every entry requests.forEach((unit) => { Object.assign(unit, {userId: {pubcid: 67890}}); + Object.assign(unit, {userIdAsEids: createEidsArray(unit.userId)}); }); // construct http post payload const payload = spec.buildRequests(requests).data; @@ -468,13 +476,14 @@ describe('Conversant adapter tests', function() { // add pubcid to every entry requests.forEach((unit) => { - Object.assign(unit, {userId: {pubcid: 112233, tdid: 223344, idl_env: 334455}}); + Object.assign(unit, {userId: {pubcid: '112233', tdid: '223344', idl_env: '334455'}}); + Object.assign(unit, {userIdAsEids: createEidsArray(unit.userId)}); }); // construct http post payload const payload = spec.buildRequests(requests).data; expect(payload).to.have.deep.nested.property('user.ext.eids', [ - {source: 'adserver.org', uids: [{id: 223344, atype: 1}]}, - {source: 'liveramp.com', uids: [{id: 334455, atype: 1}]} + {source: 'adserver.org', uids: [{id: '223344', atype: 1, ext: {rtiPartner: 'TDID'}}]}, + {source: 'liveramp.com', uids: [{id: '334455', atype: 1}]} ]); }); }); @@ -505,7 +514,7 @@ describe('Conversant adapter tests', function() { const requests = utils.deepClone(bidRequests); // add a pubcid cookie - utils.setCookie(ID_NAME, '12345', expStr(TIMEOUT)); + storage.setCookie(ID_NAME, '12345', expStr(TIMEOUT)); // construct http post payload const payload = spec.buildRequests(requests).data; @@ -518,7 +527,7 @@ describe('Conversant adapter tests', function() { requests[0].params.pubcid_name = CUSTOM_ID_NAME; // add a pubcid cookie - utils.setCookie(CUSTOM_ID_NAME, '12345', expStr(TIMEOUT)); + storage.setCookie(CUSTOM_ID_NAME, '12345', expStr(TIMEOUT)); // construct http post payload const payload = spec.buildRequests(requests).data; @@ -530,8 +539,8 @@ describe('Conversant adapter tests', function() { const requests = utils.deepClone(bidRequests); // add a pubcid in local storage - utils.setDataInLocalStorage(ID_NAME + EXP, ''); - utils.setDataInLocalStorage(ID_NAME, 'abcde'); + storage.setDataInLocalStorage(ID_NAME + EXP, ''); + storage.setDataInLocalStorage(ID_NAME, 'abcde'); // construct http post payload const payload = spec.buildRequests(requests).data; @@ -543,8 +552,8 @@ describe('Conversant adapter tests', function() { const requests = utils.deepClone(bidRequests); // add a pubcid in local storage - utils.setDataInLocalStorage(ID_NAME + EXP, expStr(TIMEOUT)); - utils.setDataInLocalStorage(ID_NAME, 'fghijk'); + storage.setDataInLocalStorage(ID_NAME + EXP, expStr(TIMEOUT)); + storage.setDataInLocalStorage(ID_NAME, 'fghijk'); // construct http post payload const payload = spec.buildRequests(requests).data; @@ -556,8 +565,8 @@ describe('Conversant adapter tests', function() { const requests = utils.deepClone(bidRequests); // add a pubcid in local storage - utils.setDataInLocalStorage(ID_NAME + EXP, expStr(-TIMEOUT)); - utils.setDataInLocalStorage(ID_NAME, 'lmnopq'); + storage.setDataInLocalStorage(ID_NAME + EXP, expStr(-TIMEOUT)); + storage.setDataInLocalStorage(ID_NAME, 'lmnopq'); // construct http post payload const payload = spec.buildRequests(requests).data; @@ -570,8 +579,8 @@ describe('Conversant adapter tests', function() { requests[0].params.pubcid_name = CUSTOM_ID_NAME; // add a pubcid in local storage - utils.setDataInLocalStorage(CUSTOM_ID_NAME + EXP, expStr(TIMEOUT)); - utils.setDataInLocalStorage(CUSTOM_ID_NAME, 'fghijk'); + storage.setDataInLocalStorage(CUSTOM_ID_NAME + EXP, expStr(TIMEOUT)); + storage.setDataInLocalStorage(CUSTOM_ID_NAME, 'fghijk'); // construct http post payload const payload = spec.buildRequests(requests).data; diff --git a/test/spec/modules/cosmosBidAdapter_spec.js b/test/spec/modules/cosmosBidAdapter_spec.js index 7eb51c596e4..b33f53221e2 100644 --- a/test/spec/modules/cosmosBidAdapter_spec.js +++ b/test/spec/modules/cosmosBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/cosmosBidAdapter'; -import * as utils from 'src/utils'; +import { spec } from 'modules/cosmosBidAdapter.js'; +import * as utils from 'src/utils.js'; const constants = require('src/constants.json'); describe('Cosmos adapter', function () { diff --git a/test/spec/modules/cpmstarBidAdapter_spec.js b/test/spec/modules/cpmstarBidAdapter_spec.js index d080a2570ab..1993f28e5d5 100755 --- a/test/spec/modules/cpmstarBidAdapter_spec.js +++ b/test/spec/modules/cpmstarBidAdapter_spec.js @@ -1,6 +1,7 @@ import { expect } from 'chai'; -import { spec } from 'modules/cpmstarBidAdapter'; -import { deepClone } from 'src/utils'; +import { spec } from 'modules/cpmstarBidAdapter.js'; +import { deepClone } from 'src/utils.js'; +import { config } from 'src/config.js'; describe('Cpmstar Bid Adapter', function () { describe('isBidRequestValid', function () { @@ -15,22 +16,26 @@ 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); }) @@ -79,6 +84,31 @@ 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'); + }); }) describe('interpretResponse', function () { 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 3114fbc7355..c5068d11d31 100755 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -1,23 +1,26 @@ import { expect } from 'chai'; -import { tryGetCriteoFastBid, spec, PROFILE_ID_PUBLISHERTAG, ADAPTER_VERSION, PUBLISHER_TAG_URL } from 'modules/criteoBidAdapter'; -import { createBid } from 'src/bidfactory'; +import { tryGetCriteoFastBid, spec, PROFILE_ID_PUBLISHERTAG, ADAPTER_VERSION } from 'modules/criteoBidAdapter.js'; +import { createBid } from 'src/bidfactory.js'; import CONSTANTS from 'src/constants.json'; -import * as utils from 'src/utils'; -import { config } from '../../../src/config'; -import { NATIVE, VIDEO } from '../../../src/mediaTypes'; +import * as utils from 'src/utils.js'; +import { config } from '../../../src/config.js'; +import { NATIVE, VIDEO } from '../../../src/mediaTypes.js'; describe('The Criteo bidding adapter', function () { - let utilsMock; + let utilsMock, sandbox; beforeEach(function () { // Remove FastBid to avoid side effects localStorage.removeItem('criteo_fast_bid'); utilsMock = sinon.mock(utils); + + sandbox = sinon.sandbox.create(); }); afterEach(function() { global.Criteo = undefined; utilsMock.restore(); + sandbox.restore(); }); describe('isBidRequestValid', function () { @@ -382,6 +385,7 @@ describe('The Criteo bidding adapter', function () { '91': 1 }, }, + apiVersion: 1, }, }; @@ -433,7 +437,63 @@ describe('The Criteo bidding adapter', function () { expect(ortbRequest.slots[0].zoneid).to.equal(123); expect(ortbRequest.gdprConsent.consentData).to.equal('concentDataString'); expect(ortbRequest.gdprConsent.gdprApplies).to.equal(true); - expect(ortbRequest.gdprConsent.consentGiven).to.equal(true); + expect(ortbRequest.gdprConsent.version).to.equal(1); + }); + + it('should keep undefined sizes for non native banner', function () { + const bidRequests = [ + { + sizes: [[undefined, undefined]], + params: {}, + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + const ortbRequest = request.data; + expect(ortbRequest.slots[0].sizes).to.have.lengthOf(1); + expect(ortbRequest.slots[0].sizes[0]).to.equal('undefinedxundefined'); + }); + + it('should keep undefined size for non native banner', function () { + const bidRequests = [ + { + sizes: [undefined, undefined], + params: {}, + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + const ortbRequest = request.data; + expect(ortbRequest.slots[0].sizes).to.have.lengthOf(1); + expect(ortbRequest.slots[0].sizes[0]).to.equal('undefinedxundefined'); + }); + + it('should properly detect and get sizes of native sizeless banner', function () { + const bidRequests = [ + { + sizes: [[undefined, undefined]], + params: { + nativeCallback: function() {} + }, + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + const ortbRequest = request.data; + expect(ortbRequest.slots[0].sizes).to.have.lengthOf(1); + expect(ortbRequest.slots[0].sizes[0]).to.equal('2x2'); + }); + + it('should properly detect and get size of native sizeless banner', function () { + const bidRequests = [ + { + sizes: [undefined, undefined], + params: { + nativeCallback: function() {} + }, + }, + ]; + const request = spec.buildRequests(bidRequests, bidderRequest); + const ortbRequest = request.data; + expect(ortbRequest.slots[0].sizes).to.have.lengthOf(1); + expect(ortbRequest.slots[0].sizes[0]).to.equal('2x2'); }); it('should properly build a networkId request', function () { @@ -481,7 +541,6 @@ describe('The Criteo bidding adapter', function () { expect(ortbRequest.slots[0].sizes[1]).to.equal('728x90'); expect(ortbRequest.gdprConsent.consentData).to.equal(undefined); expect(ortbRequest.gdprConsent.gdprApplies).to.equal(false); - expect(ortbRequest.gdprConsent.consentGiven).to.equal(undefined); }); it('should properly build a mixed request', function () { @@ -530,7 +589,7 @@ describe('The Criteo bidding adapter', function () { expect(ortbRequest.gdprConsent).to.equal(undefined); }); - it('should properly build request with undefined gdpr consent fields when they are not provided', function () { + it('should properly build a request with undefined gdpr consent fields when they are not provided', function () { const bidRequests = [ { bidder: 'criteo', @@ -550,7 +609,6 @@ describe('The Criteo bidding adapter', function () { const ortbRequest = spec.buildRequests(bidRequests, bidderRequest).data; expect(ortbRequest.gdprConsent.consentData).to.equal(undefined); expect(ortbRequest.gdprConsent.gdprApplies).to.equal(undefined); - expect(ortbRequest.gdprConsent.consentGiven).to.equal(undefined); }); it('should properly build a request with ccpa consent field', function () { @@ -705,6 +763,115 @@ describe('The Criteo bidding adapter', function () { expect(request.data.user).to.not.be.null; expect(request.data.user.ceh).to.equal('hashedemail'); }); + + it('should properly build a request without first party data', function () { + const bidRequests = [ + { + bidder: 'criteo', + adUnitCode: 'bid-123', + transactionId: 'transaction-123', + sizes: [[728, 90]], + params: { + zoneId: 123 + } + }, + ]; + + sandbox.stub(config, 'getConfig').callsFake(key => { + const config = { + }; + return utils.deepAccess(config, key); + }); + + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.publisher.ext).to.equal(undefined); + expect(request.data.user.ext).to.equal(undefined); + expect(request.data.slots[0].ext).to.equal(undefined); + }); + + it('should properly build a request with criteo specific ad unit first party data', function () { + const bidRequests = [ + { + bidder: 'criteo', + adUnitCode: 'bid-123', + transactionId: 'transaction-123', + sizes: [[728, 90]], + params: { + zoneId: 123, + ext: { + bidfloor: 0.75 + } + } + }, + ]; + + sandbox.stub(config, 'getConfig').callsFake(key => { + const config = { + }; + return utils.deepAccess(config, key); + }); + + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.slots[0].ext).to.deep.equal({ + bidfloor: 0.75, + }); + }); + + it('should properly build a request with first party data', function () { + const contextData = { + keywords: ['power tools'], + data: { + pageType: 'article' + } + }; + const userData = { + gender: 'M', + data: { + registered: true + } + }; + const bidRequests = [ + { + bidder: 'criteo', + adUnitCode: 'bid-123', + transactionId: 'transaction-123', + sizes: [[728, 90]], + params: { + zoneId: 123, + ext: { + bidfloor: 0.75 + } + }, + fpd: { + context: { + data: { + someContextAttribute: 'abc' + } + } + } + }, + ]; + + sandbox.stub(config, 'getConfig').callsFake(key => { + const config = { + fpd: { + context: contextData, + user: userData + } + }; + return utils.deepAccess(config, key); + }); + + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request.data.publisher.ext).to.deep.equal(contextData); + expect(request.data.user.ext).to.deep.equal(userData); + expect(request.data.slots[0].ext).to.deep.equal({ + bidfloor: 0.75, + data: { + someContextAttribute: 'abc' + } + }); + }); }); describe('interpretResponse', function () { @@ -1006,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(); @@ -1054,6 +1220,132 @@ describe('The Criteo bidding adapter', function () { }); }); + describe('when pubtag prebid adapter is not available', function () { + it('should not warn if sendId is provided on required fields for native bidRequest', () => { + const bidderRequest = { }; + const bidRequestsWithSendId = [ + { + bidder: 'criteo', + adUnitCode: 'bid-123', + transactionId: 'transaction-123', + sizes: [[728, 90]], + params: { + zoneId: 123, + publisherSubId: '123', + nativeCallback: function() {} + }, + nativeParams: { + image: { + sendId: true + }, + icon: { + sendId: true + }, + clickUrl: { + sendId: true + }, + displayUrl: { + sendId: true + }, + privacyLink: { + sendId: true + }, + privacyIcon: { + sendId: true + } + } + } + ]; + + utilsMock.expects('logWarn').withArgs('Criteo: all native assets containing URL should be sent as placeholders with sendId(icon, image, clickUrl, displayUrl, privacyLink, privacyIcon)').never(); + const request = spec.buildRequests(bidRequestsWithSendId, bidderRequest); + utilsMock.verify(); + }); + + it('should warn only once if sendId is not provided on required fields for native bidRequest', () => { + const bidderRequest = { }; + const bidRequests = [ + { + bidder: 'criteo', + adUnitCode: 'bid-123', + transactionId: 'transaction-123', + sizes: [[728, 90]], + params: { + zoneId: 123, + publisherSubId: '123', + nativeCallback: function() {} + }, + }, + { + bidder: 'criteo', + adUnitCode: 'bid-456', + transactionId: 'transaction-456', + sizes: [[728, 90]], + params: { + zoneId: 456, + publisherSubId: '456', + nativeCallback: function() {} + }, + }, + ]; + + const nativeParamsWithoutSendId = [ + { + nativeParams: { + image: { + sendId: false + }, + } + }, + { + nativeParams: { + icon: { + sendId: false + }, + } + }, + { + nativeParams: { + clickUrl: { + sendId: false + }, + } + }, + { + nativeParams: { + displayUrl: { + sendId: false + }, + } + }, + { + nativeParams: { + privacyLink: { + sendId: false + }, + } + }, + { + nativeParams: { + privacyIcon: { + sendId: false + }, + } + } + ]; + + utilsMock.expects('logWarn') + .withArgs('Criteo: all native assets containing URL should be sent as placeholders with sendId(icon, image, clickUrl, displayUrl, privacyLink, privacyIcon)') + .exactly(nativeParamsWithoutSendId.length * bidRequests.length); + nativeParamsWithoutSendId.forEach(nativeParams => { + let transformedBidRequests = {...bidRequests}; + transformedBidRequests = [Object.assign(transformedBidRequests[0], nativeParams), Object.assign(transformedBidRequests[1], nativeParams)]; + spec.buildRequests(transformedBidRequests, bidderRequest); + }); + utilsMock.verify(); + }); + }); + describe('when pubtag prebid adapter is available', function () { it('should forward response to pubtag when calling interpretResponse', () => { const response = {}; @@ -1126,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/criteoIdSystem_spec.js b/test/spec/modules/criteoIdSystem_spec.js index 44decfd56b6..aa5807da0da 100644 --- a/test/spec/modules/criteoIdSystem_spec.js +++ b/test/spec/modules/criteoIdSystem_spec.js @@ -1,7 +1,6 @@ -import { criteoIdSubmodule } from 'modules/criteoIdSystem'; -import * as utils from 'src/utils'; -import * as ajaxLib from 'src/ajax'; -import * as urlLib from 'src/url'; +import { criteoIdSubmodule, storage } from 'modules/criteoIdSystem.js'; +import * as utils from 'src/utils.js'; +import * as ajaxLib from 'src/ajax.js'; const pastDateString = new Date(0).toString() @@ -27,14 +26,14 @@ describe('CriteoId module', function () { let triggerPixelStub; beforeEach(function (done) { - getCookieStub = sinon.stub(utils, 'getCookie'); - setCookieStub = sinon.stub(utils, 'setCookie'); - getLocalStorageStub = sinon.stub(utils, 'getDataFromLocalStorage'); - setLocalStorageStub = sinon.stub(utils, 'setDataInLocalStorage'); - removeFromLocalStorageStub = sinon.stub(utils, 'removeDataFromLocalStorage'); + 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); ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockResponse('{}')); - parseUrlStub = sinon.stub(urlLib, 'parse').returns({protocol: 'https', hostname: 'testdev.com'}) + parseUrlStub = sinon.stub(utils, 'parseUrl').returns({protocol: 'https', hostname: 'testdev.com'}) triggerPixelStub = sinon.stub(utils, 'triggerPixel'); done(); }); @@ -132,4 +131,26 @@ describe('CriteoId module', function () { } }); })); + + const gdprConsentTestCases = [ + { consentData: { gdprApplies: true, consentString: 'expectedConsentString' }, expected: 'expectedConsentString' }, + { consentData: { gdprApplies: false, consentString: 'expectedConsentString' }, expected: undefined }, + { consentData: { gdprApplies: true, consentString: undefined }, expected: undefined }, + { consentData: { gdprApplies: 'oui', consentString: 'expectedConsentString' }, expected: undefined }, + { consentData: undefined, expected: undefined } + ]; + + gdprConsentTestCases.forEach(testCase => it('should call user sync url with the gdprConsent', function () { + const emptyObj = '{}'; + let ajaxStub = sinon.stub().callsFake((url, callback) => callback(emptyObj)); + ajaxBuilderStub.callsFake(mockResponse(undefined, ajaxStub)) + + criteoIdSubmodule.getId(undefined, testCase.consentData); + + if (testCase.expected) { + expect(ajaxStub.calledWithMatch(`gdprString=${testCase.expected}`)).to.be.true; + } else { + expect(ajaxStub.calledWithMatch('gdprString')).not.to.be.true; + } + })); }); diff --git a/test/spec/modules/criteortusIdSystem_spec.js b/test/spec/modules/criteortusIdSystem_spec.js deleted file mode 100644 index 6ceaa7aa953..00000000000 --- a/test/spec/modules/criteortusIdSystem_spec.js +++ /dev/null @@ -1,87 +0,0 @@ -import { criteortusIdSubmodule } from 'modules/criteortusIdSystem'; -import * as utils from 'src/utils'; -import { server } from 'test/mocks/xhr'; - -describe('Criteo RTUS', function() { - let xhr; - let requests; - let getCookieStub; - let logErrorStub; - - beforeEach(function () { - getCookieStub = sinon.stub(utils, 'getCookie'); - logErrorStub = sinon.stub(utils, 'logError'); - }); - - afterEach(function () { - getCookieStub.restore(); - logErrorStub.restore(); - }); - - it('should log error when configParams are not passed', function() { - criteortusIdSubmodule.getId(); - expect(logErrorStub.calledOnce).to.be.true; - }) - - it('should call criteo endpoint to get user id', function() { - getCookieStub.returns(null); - let configParams = { - clientIdentifier: { - 'sampleBidder': 1 - } - } - - let response = { 'status': 'ok', 'userid': 'sample-userid' } - let callBackSpy = sinon.spy(); - const idResp = criteortusIdSubmodule.getId(configParams); - const submoduleCallback = idResp.callback; - submoduleCallback(callBackSpy); - server.requests[0].respond( - 200, - { 'Content-Type': 'text/plain' }, - JSON.stringify(response) - ); - expect(callBackSpy.calledOnce).to.be.true; - expect(callBackSpy.calledWith({'sampleBidder': response})).to.be.true; - }) - - it('should get uid from cookie and not call endpoint', function() { - let response = {'appnexus': {'status': 'ok', 'userid': 'sample-userid'}} - getCookieStub.returns(JSON.stringify(response)); - let configParams = { - clientIdentifier: { - 'sampleBidder': 1 - } - } - let uid = criteortusIdSubmodule.getId(configParams); - expect(server.requests.length).to.equal(0); - }) - - it('should call criteo endpoint for multiple bidders', function() { - getCookieStub.returns(null); - let configParams = { - clientIdentifier: { - 'sampleBidder': 1, - 'sampleBidder2': 2 - } - } - - let response = { 'status': 'ok', 'userid': 'sample-userid' } - let callBackSpy = sinon.spy(); - const idResp = criteortusIdSubmodule.getId(configParams); - const submoduleCallback = idResp.callback; - submoduleCallback(callBackSpy); - server.requests[0].respond( - 200, - { 'Content-Type': 'text/plain' }, - JSON.stringify(response) - ); - expect(callBackSpy.calledOnce).to.be.false; - server.requests[1].respond( - 200, - { 'Content-Type': 'text/plain' }, - JSON.stringify(response) - ); - expect(callBackSpy.calledOnce).to.be.true; - }) -}); diff --git a/test/spec/modules/currency_spec.js b/test/spec/modules/currency_spec.js index 98f51b72251..ccd205964a9 100644 --- a/test/spec/modules/currency_spec.js +++ b/test/spec/modules/currency_spec.js @@ -1,14 +1,16 @@ import { getCurrencyRates -} from 'test/fixtures/fixtures'; +} from 'test/fixtures/fixtures.js'; + +import { getGlobal } from 'src/prebidGlobal.js'; import { setConfig, addBidResponseHook, currencySupportEnabled, currencyRates -} from 'modules/currency'; +} from 'modules/currency.js'; var assert = require('chai').assert; var expect = require('chai').expect; @@ -43,8 +45,12 @@ describe('currency', function () { it('results in currencySupportEnabled = false when currency not configured', function () { setConfig({}); expect(currencySupportEnabled).to.equal(false); + expect(getGlobal().convertCurrency).to.be.undefined; + }); + it('adds conversion function onto pbjs global var once initiated', function () { + setConfig({ 'adServerCurrency': 'JPY' }); + expect(getGlobal().convertCurrency).to.be.a('function'); }); - it('results in currencySupportEnabled = true and currencyRates being loaded when configured', function () { fakeCurrencyFileServer.respondWith(JSON.stringify(getCurrencyRates())); setConfig({ 'adServerCurrency': 'JPY' }); @@ -124,6 +130,38 @@ describe('currency', function () { }); }); + describe('global currency function', function () { + it('still returns conversion if default rates present with fetch not returned yet', function () { + setConfig({ + 'adServerCurrency': 'USD', + 'defaultRates': { + 'USD': { EUR: 2, JPY: 100 } + } + }); + // first conversion should use default rates + expect(getGlobal().convertCurrency(1.0, 'USD', 'EUR')).to.equal(2); + expect(getGlobal().convertCurrency(1.0, 'USD', 'JPY')).to.equal(100); + fakeCurrencyFileServer.respond(); + }); + it('uses fetch rates if returned', function () { + fakeCurrencyFileServer.respondWith(JSON.stringify({ + 'dataAsOf': '2017-04-25', + 'conversions': { + 'USD': { EUR: 4, JPY: 200 } + } + })); + setConfig({ + 'adServerCurrency': 'USD', + 'defaultRates': { + 'USD': { EUR: 2, JPY: 100 } + } + }); + // now respond and should use updates rates + fakeCurrencyFileServer.respond(); + expect(getGlobal().convertCurrency(1.0, 'USD', 'EUR')).to.equal(4); + expect(getGlobal().convertCurrency(1.0, 'USD', 'JPY')).to.equal(200); + }); + }); describe('bidder override', function () { it('allows setConfig to set bidder currency', function () { setConfig({}); diff --git a/test/spec/modules/dailyhuntBidAdapter_spec.js b/test/spec/modules/dailyhuntBidAdapter_spec.js index 617c1be04bb..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'; +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/datablocksBidAdapter_spec.js b/test/spec/modules/datablocksBidAdapter_spec.js index af0fd8a3bc9..18b8aac7371 100644 --- a/test/spec/modules/datablocksBidAdapter_spec.js +++ b/test/spec/modules/datablocksBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from '../../../modules/datablocksBidAdapter'; +import { spec } from '../../../modules/datablocksBidAdapter.js'; let bid = { bidId: '2dd581a2b6281d', diff --git a/test/spec/modules/deepintentBidAdapter_spec.js b/test/spec/modules/deepintentBidAdapter_spec.js index 33dfd14d074..6d9b883e2bb 100644 --- a/test/spec/modules/deepintentBidAdapter_spec.js +++ b/test/spec/modules/deepintentBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; -import {spec} from 'modules/deepintentBidAdapter'; -import * as utils from '../../../src/utils'; +import {spec} from 'modules/deepintentBidAdapter.js'; +import * as utils from '../../../src/utils.js'; describe('Deepintent adapter', function () { let request; @@ -19,6 +19,7 @@ describe('Deepintent adapter', function () { tagId: '100013', w: 728, h: 90, + pos: 1, user: { id: 'di_testuid', buyeruid: 'di_testbuyeruid', @@ -129,6 +130,11 @@ describe('Deepintent adapter', function () { expect(data.imp[0].ext).to.be.a('object'); expect(data.imp[0].ext.deepintent.position).to.equal('right-box'); }); + it('bid request check: position check', function () { + let bRequest = spec.buildRequests(request); + let data = JSON.parse(bRequest.data); + expect(data.imp[0].banner.pos).to.equal(1); + }); it('bid request check: displaymanager check', function() { let bRequest = spec.buildRequests(request); let data = JSON.parse(bRequest.data); @@ -143,7 +149,36 @@ describe('Deepintent adapter', function () { expect(data.user.buyeruid).to.equal('di_testbuyeruid'); expect(data.user.yob).to.equal(2002); expect(data.user.gender).to.equal('F'); - }) + }); + it('bid request check: CCPA Check', function () { + let bidRequest = { + uspConsent: '1NYN' + }; + let bRequest = spec.buildRequests(request, bidRequest); + let data = JSON.parse(bRequest.data); + expect(data.regs.ext.us_privacy).to.equal('1NYN'); + let bidRequest2 = {}; + let bRequest2 = spec.buildRequests(request, bidRequest2); + let data2 = JSON.parse(bRequest2.data); + expect(data2.regs).to.equal(undefined); + }); + it('bid Request check: GDPR Check', function () { + let bidRequest = { + gdprConsent: { + consentString: 'kjfdnidasd123sadsd', + gdprApplies: true + } + }; + let bRequest = spec.buildRequests(request, bidRequest); + let data = JSON.parse(bRequest.data); + expect(data.user.ext.consent).to.equal('kjfdnidasd123sadsd'); + expect(data.regs.ext.gdpr).to.equal(1); + let bidRequest2 = {}; + let bRequest2 = spec.buildRequests(request, bidRequest2); + let data2 = JSON.parse(bRequest2.data); + expect(data2.regs).to.equal(undefined); + expect(data2.user.ext).to.equal(undefined); + }); }); describe('user sync check', function () { it('user sync url check', function () { diff --git a/test/spec/modules/dfpAdServerVideo_spec.js b/test/spec/modules/dfpAdServerVideo_spec.js index ff527c379e2..cd412530d2b 100644 --- a/test/spec/modules/dfpAdServerVideo_spec.js +++ b/test/spec/modules/dfpAdServerVideo_spec.js @@ -1,15 +1,14 @@ import { expect } from 'chai'; import parse from 'url-parse'; -import { buildDfpVideoUrl, buildAdpodVideoUrl } from 'modules/dfpAdServerVideo'; -import { parseQS } from 'src/url'; -import adUnit from 'test/fixtures/video/adUnit'; -import * as utils from 'src/utils'; -import { config } from 'src/config'; -import { targeting } from 'src/targeting'; -import { auctionManager } from 'src/auctionManager'; -import * as adpod from 'modules/adpod'; -import { server } from 'test/mocks/xhr'; +import { buildDfpVideoUrl, buildAdpodVideoUrl } from 'modules/dfpAdServerVideo.js'; +import adUnit from 'test/fixtures/video/adUnit.json'; +import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; +import { targeting } from 'src/targeting.js'; +import { auctionManager } from 'src/auctionManager.js'; +import * as adpod from 'modules/adpod.js'; +import { server } from 'test/mocks/xhr.js'; const bid = { videoCacheKey: 'abc', @@ -33,7 +32,7 @@ describe('The DFP video support module', function () { expect(url.protocol).to.equal('https:'); expect(url.host).to.equal('securepubads.g.doubleclick.net'); - const queryParams = parseQS(url.query); + const queryParams = utils.parseQS(url.query); expect(queryParams).to.have.property('correlator'); expect(queryParams).to.have.property('description_url', 'someUrl.com'); expect(queryParams).to.have.property('env', 'vp'); @@ -57,7 +56,7 @@ describe('The DFP video support module', function () { expect(url.host).to.equal('video.adserver.example'); - const queryObject = parseQS(url.query); + const queryObject = utils.parseQS(url.query); expect(queryObject.description_url).to.equal('vastUrl.example'); }); @@ -78,7 +77,7 @@ describe('The DFP video support module', function () { params: { iu: 'my/adUnit' } })); - const queryObject = parseQS(url.query); + const queryObject = utils.parseQS(url.query); expect(queryObject.iu).to.equal('my/adUnit'); }); @@ -92,7 +91,7 @@ describe('The DFP video support module', function () { } })); - expect(parseQS(url.query)).to.have.property('output', 'vast'); + expect(utils.parseQS(url.query)).to.have.property('output', 'vast'); }); it('should include the cache key and adserver targeting in cust_params', function () { @@ -108,8 +107,8 @@ describe('The DFP video support module', function () { 'iu': 'my/adUnit' } })); - const queryObject = parseQS(url.query); - const customParams = parseQS('?' + decodeURIComponent(queryObject.cust_params)); + const queryObject = utils.parseQS(url.query); + const customParams = utils.parseQS('?' + decodeURIComponent(queryObject.cust_params)); expect(customParams).to.have.property('hb_adid', 'ad_id'); expect(customParams).to.have.property('hb_uuid', bid.videoCacheKey); @@ -178,8 +177,8 @@ describe('The DFP video support module', function () { 'iu': 'my/adUnit' } })); - const queryObject = parseQS(url.query); - const customParams = parseQS('?' + decodeURIComponent(queryObject.cust_params)); + const queryObject = utils.parseQS(url.query); + const customParams = utils.parseQS('?' + decodeURIComponent(queryObject.cust_params)); expect(customParams).to.have.property('hb_adid', 'ad_id'); expect(customParams).to.have.property('hb_uuid', bid.videoCacheKey); @@ -205,8 +204,8 @@ describe('The DFP video support module', function () { }, }, })); - const queryObject = parseQS(url.query); - const customParams = parseQS('?' + decodeURIComponent(queryObject.cust_params)); + const queryObject = utils.parseQS(url.query); + const customParams = utils.parseQS('?' + decodeURIComponent(queryObject.cust_params)); expect(customParams).to.have.property('hb_adid', 'ad_id'); expect(customParams).to.have.property('my_targeting', 'foo'); @@ -224,8 +223,8 @@ describe('The DFP video support module', function () { url: 'https://video.adserver.example/ads?sz=640x480&iu=/123/aduniturl&impl=s&cust_params=section%3dblog%26mykey%3dmyvalue' })); - const queryObject = parseQS(url.query); - const customParams = parseQS('?' + decodeURIComponent(queryObject.cust_params)); + const queryObject = utils.parseQS(url.query); + const customParams = utils.parseQS('?' + decodeURIComponent(queryObject.cust_params)); expect(customParams).to.have.property('hb_adid', 'ad_id'); expect(customParams).to.have.property('section', 'blog'); @@ -247,7 +246,7 @@ describe('The DFP video support module', function () { } })); - const queryObject = parseQS(url.query); + const queryObject = utils.parseQS(url.query); expect(queryObject.description_url).to.equal('descriptionurl.example'); }); @@ -272,8 +271,8 @@ describe('The DFP video support module', function () { 'iu': 'my/adUnit' } })); - const queryObject = parseQS(url.query); - const customParams = parseQS('?' + decodeURIComponent(queryObject.cust_params)); + const queryObject = utils.parseQS(url.query); + const customParams = utils.parseQS('?' + decodeURIComponent(queryObject.cust_params)); expect(customParams).to.have.property('hb_uuid', bid.videoCacheKey); expect(customParams).to.have.property('hb_cache_id', bid.videoCacheKey); @@ -293,8 +292,8 @@ describe('The DFP video support module', function () { 'iu': 'my/adUnit' } })); - const queryObject = parseQS(url.query); - const customParams = parseQS('?' + decodeURIComponent(queryObject.cust_params)); + const queryObject = utils.parseQS(url.query); + const customParams = utils.parseQS('?' + decodeURIComponent(queryObject.cust_params)); expect(customParams).to.have.property('hb_uuid', 'def'); expect(customParams).to.have.property('hb_cache_id', 'def'); @@ -370,7 +369,7 @@ describe('The DFP video support module', function () { expect(url.protocol).to.equal('https:'); expect(url.host).to.equal('securepubads.g.doubleclick.net'); - const queryParams = parseQS(url.query); + const queryParams = utils.parseQS(url.query); expect(queryParams).to.have.property('correlator'); expect(queryParams).to.have.property('description_url', 'someUrl.com'); expect(queryParams).to.have.property('env', 'vp'); @@ -382,7 +381,7 @@ describe('The DFP video support module', function () { expect(queryParams).to.have.property('url'); expect(queryParams).to.have.property('cust_params'); - const custParams = parseQS(decodeURIComponent(queryParams.cust_params)); + const custParams = utils.parseQS(decodeURIComponent(queryParams.cust_params)); expect(custParams).to.have.property('hb_cache_id', '123'); expect(custParams).to.have.property('hb_pb_cat_dur', '15.00_395_15s,15.00_406_30s,10.00_395_15s'); } @@ -424,7 +423,7 @@ describe('The DFP video support module', function () { expect(url.protocol).to.equal('https:'); expect(url.host).to.equal('securepubads.g.doubleclick.net'); - const queryParams = parseQS(url.query); + const queryParams = utils.parseQS(url.query); expect(queryParams).to.have.property('correlator'); expect(queryParams).to.have.property('description_url', 'someUrl.com'); expect(queryParams).to.have.property('env', 'vp'); @@ -436,7 +435,7 @@ describe('The DFP video support module', function () { expect(queryParams).to.have.property('url'); expect(queryParams).to.have.property('cust_params'); - const custParams = parseQS(decodeURIComponent(queryParams.cust_params)); + const custParams = utils.parseQS(decodeURIComponent(queryParams.cust_params)); expect(custParams).to.have.property('hb_cache_id', '123'); expect(custParams).to.have.property('hb_pb_cat_dur', '10.00_15s,15.00_15s,15.00_30s'); } @@ -529,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 index 4b138e0d49d..befd6eb75b6 100644 --- a/test/spec/modules/digitrustIdSystem_spec.js +++ b/test/spec/modules/digitrustIdSystem_spec.js @@ -1,7 +1,7 @@ import { digiTrustIdSubmodule, surfaceTestHook -} from 'modules/digiTrustIdSystem'; +} from 'modules/digiTrustIdSystem.js'; let assert = require('chai').assert; let expect = require('chai').expect; @@ -109,13 +109,23 @@ describe('DigiTrust Id System', function () { testHook.gdpr.hasConsent(null, handler); }); - it('Should allow consent if timeout', function (done) { + it('Should deny consent if timeout', function (done) { window.__cmp = function () { }; var handler = function (result) { - expect(result).to.be.true; + 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 a98bcaca9e0..d8f0beb9a36 100644 --- a/test/spec/modules/districtmDmxBidAdapter_spec.js +++ b/test/spec/modules/districtmDmxBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; import * as _ from 'lodash'; -import {spec, matchRequest, checkDeepArray, defaultSize, upto5, cleanSizes, shuffle} from '../../../modules/districtmDMXBidAdapter'; +import {spec, matchRequest, checkDeepArray, defaultSize, upto5, cleanSizes, shuffle} from '../../../modules/districtmDMXBidAdapter.js'; const supportedSize = [ { @@ -40,7 +40,7 @@ const bidRequest = [{ 'bidder': 'districtmDMX', 'params': { 'dmxid': 100001, - 'memberid': 100003 + 'memberid': 100003, }, 'adUnitCode': 'div-gpt-ad-12345678-1', 'transactionId': 'f6d13fa6-ebc1-41ac-9afa-d8171d22d2c2', @@ -53,6 +53,22 @@ const bidRequest = [{ 'auctionId': '3d62f2d3-56a2-4991-888e-f7754619ddcf' }]; +const bidRequestNoCoppa = [{ + 'bidder': 'districtmDMX', + 'params': { + 'dmxid': 100001, + 'memberid': 100003 + }, + '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 bidderRequest = { 'bidderCode': 'districtmDMX', 'auctionId': '3d62f2d3-56a2-4991-888e-f7754619ddcf', @@ -61,7 +77,7 @@ const bidderRequest = { 'bidder': 'districtmDMX', 'params': { 'dmxid': 100001, - 'memberid': 100003 + 'memberid': 100003, }, 'adUnitCode': 'div-gpt-ad-12345678-1', 'transactionId': 'f6d13fa6-ebc1-41ac-9afa-d8171d22d2c2', @@ -420,6 +436,32 @@ const bidderRequest = { 'doneCbCallCount': 0 }; +const bidderRequestNoCoppa = { + 'bidderCode': 'districtmDMX', + 'auctionId': '3d62f2d3-56a2-4991-888e-f7754619ddcf', + 'bidderRequestId': '124b579a136515', + 'bids': [{ + 'bidder': 'districtmDMX', + 'params': { + 'dmxid': 100001, + 'memberid': 100003, + }, + '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' + }], + 'auctionStart': 1529511035677, + 'timeout': 700, + 'start': 1529511035686, + 'doneCbCallCount': 0 +}; + const responses = { 'body': { 'id': '1f45b37c-5298-4934-b517-4d911aadabfd', @@ -522,6 +564,7 @@ describe('DistrictM Adaptor', function () { describe(`buildRequests test usage`, function () { const buildRequestResults = districtm.buildRequests(bidRequest, bidderRequest); + const buildRequestResultsNoCoppa = districtm.buildRequests(bidRequestNoCoppa, bidderRequestNoCoppa); it(`the function should return an array`, function () { expect(buildRequestResults).to.be.an('object'); }); @@ -531,6 +574,16 @@ describe('DistrictM Adaptor', function () { expect(bidr.regs.ext.us_privacy).to.be.equal('1NY'); expect(bidr.user.ext.consent).to.be.an('string'); }); + it(`test contain COPPA`, function() { + const bidr = JSON.parse(buildRequestResults.data) + bidr.regs = bidr.regs || {}; + bidr.regs.coppa = 1; + expect(bidr.regs.coppa).to.be.equal(1) + }) + it(`test should not contain COPPA`, function() { + const bidr = JSON.parse(buildRequestResultsNoCoppa.data) + expect(bidr.regs.coppa).to.be.equal(0) + }) it(`the function should return array length of 1`, function () { expect(buildRequestResults.data).to.be.a('string'); }); @@ -559,6 +612,32 @@ describe('DistrictM Adaptor', function () { }); }); + describe(`check validation for id sync gdpr ccpa`, () => { + let allin = spec.getUserSyncs({iframeEnabled: true}, {}, bidderRequest.gdprConsent, bidderRequest.uspConsent)[0] + let noCCPA = spec.getUserSyncs({iframeEnabled: true}, {}, bidderRequest.gdprConsent, null)[0] + let noGDPR = spec.getUserSyncs({iframeEnabled: true}, {}, null, bidderRequest.uspConsent)[0] + let nothing = spec.getUserSyncs({iframeEnabled: true}, {}, null, null)[0] + + /* + + 'uspConsent': '1NY', + 'gdprConsent': { + 'consentString': 'BOPqNzUOPqNzUAHABBAAA5AAAAAAAA', + */ + it(`gdpr & ccpa should be present`, () => { + expect(allin.url).to.be.equal('https://cdn.districtm.io/ids/index.html?gdpr=BOPqNzUOPqNzUAHABBAAA5AAAAAAAA&ccpa=1NY') + }) + it(`ccpa should be present`, () => { + expect(noGDPR.url).to.be.equal('https://cdn.districtm.io/ids/index.html?ccpa=1NY') + }) + it(`gdpr should be present`, () => { + expect(noCCPA.url).to.be.equal('https://cdn.districtm.io/ids/index.html?gdpr=BOPqNzUOPqNzUAHABBAAA5AAAAAAAA') + }) + it(`gdpr & ccpa shouldn't be present`, () => { + expect(nothing.url).to.be.equal('https://cdn.districtm.io/ids/index.html') + }) + }) + describe(`Helper function testing`, function () { const bid = matchRequest('29a28a1bbc8a8d', {bidderRequest}); const {width, height} = defaultSize(bid); diff --git a/test/spec/modules/djaxBidAdapter_spec.js b/test/spec/modules/djaxBidAdapter_spec.js index 82955ba43bc..bef2b1fddc5 100644 --- a/test/spec/modules/djaxBidAdapter_spec.js +++ b/test/spec/modules/djaxBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/djaxBidAdapter'; +import { spec } from 'modules/djaxBidAdapter.js'; const ENDPOINT = 'https://demo.reviveadservermod.com/headerbidding_adminshare/www/admin/plugins/Prebid/getAd.php'; diff --git a/test/spec/modules/dspxBidAdapter_spec.js b/test/spec/modules/dspxBidAdapter_spec.js index b1f392188a2..cf36c3f62c4 100644 --- a/test/spec/modules/dspxBidAdapter_spec.js +++ b/test/spec/modules/dspxBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/dspxBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/dspxBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const ENDPOINT_URL = 'https://buyer.dspx.tv/request/'; const ENDPOINT_URL_DEV = 'https://dcbuyer.dspx.tv/request/'; @@ -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'); }); }); @@ -108,6 +193,7 @@ describe('dspxAdapter', function () { 'crid': 100500, 'width': '300', 'height': '250', + 'type': 'sspHTML', 'tag': '', 'requestId': '220ed41385952a', 'currency': 'EUR', @@ -116,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', @@ -127,7 +228,21 @@ describe('dspxAdapter', function () { currency: 'EUR', netRevenue: true, 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 () { @@ -142,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/e_volutionBidAdapter_spec.js b/test/spec/modules/e_volutionBidAdapter_spec.js new file mode 100644 index 00000000000..447420616d1 --- /dev/null +++ b/test/spec/modules/e_volutionBidAdapter_spec.js @@ -0,0 +1,235 @@ +import {expect} from 'chai'; +import {spec} from '../../../modules/e_volutionBidAdapter.js'; + +describe('EvolutionTechBidAdapter', function () { + let bid = { + bidId: '23fhj33i987f', + bidder: 'e_volution', + params: { + placementId: 0, + traffic: 'banner' + } + }; + + 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]); + 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://service.e-volution.ai/?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'); + let placement = data['placements'][0]; + expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'sizes'); + expect(placement.placementId).to.equal(0); + expect(placement.bidId).to.equal('23fhj33i987f'); + expect(placement.traffic).to.equal('banner'); + }); + 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 () { + if (spec.noSync) { + expect(userSync).to.be.equal(false); + } else { + 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://service.e-volution.ai/?c=o&m=sync'); + } + }); + }); +}); diff --git a/test/spec/modules/ebdrBidAdapter_spec.js b/test/spec/modules/ebdrBidAdapter_spec.js index 3cac03024c0..ba1cad475da 100644 --- a/test/spec/modules/ebdrBidAdapter_spec.js +++ b/test/spec/modules/ebdrBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; -import { spec } from 'modules/ebdrBidAdapter'; -import { VIDEO, BANNER } from 'src/mediaTypes'; -import * as utils from 'src/utils'; +import { spec } from 'modules/ebdrBidAdapter.js'; +import { VIDEO, BANNER } from 'src/mediaTypes.js'; +import * as utils from 'src/utils.js'; describe('ebdrBidAdapter', function () { let bidRequests; 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 new file mode 100644 index 00000000000..1cbc2911ef5 --- /dev/null +++ b/test/spec/modules/eids_spec.js @@ -0,0 +1,229 @@ +import {createEidsArray} from 'modules/userId/eids.js'; +import {expect} from 'chai'; + +// Note: In unit tets cases for bidders, call the createEidsArray function over userId object that is used for calling fetchBids +// this way the request will stay consistent and unit test cases will not need lots of changes. + +describe('eids array generation for known sub-modules', function() { + it('pubCommonId', function() { + const userId = { + pubcid: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'pubcid.org', + uids: [{id: 'some-random-id-value', atype: 1}] + }); + }); + + it('unifiedId: ext generation', function() { + const userId = { + tdid: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'adserver.org', + uids: [{id: 'some-random-id-value', atype: 1, ext: { rtiPartner: 'TDID' }}] + }); + }); + + it('id5Id', function() { + const userId = { + id5id: '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('parrableId', function() { + const userId = { + parrableid: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'parrable.com', + uids: [{id: 'some-random-id-value', atype: 1}] + }); + }); + + it('identityLink', function() { + const userId = { + idl_env: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'liveramp.com', + uids: [{id: 'some-random-id-value', atype: 1}] + }); + }); + + it('liveIntentId; getValue call and ext', function() { + const userId = { + lipb: { + lipbid: 'some-random-id-value', + segments: ['s1', 's2'] + } + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'liveintent.com', + uids: [{id: 'some-random-id-value', atype: 1}], + ext: {segments: ['s1', 's2']} + }); + }); + + it('liveIntentId; getValue call and NO ext', function() { + const userId = { + lipb: { + lipbid: 'some-random-id-value' + } + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'liveintent.com', + uids: [{id: 'some-random-id-value', atype: 1}] + }); + }); + + it('britepoolId', function() { + const userId = { + britepoolid: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'britepool.com', + uids: [{id: 'some-random-id-value', atype: 1}] + }); + }); + + it('lotamePanoramaId', function () { + const userId = { + lotamePanoramaId: 'some-random-id-value', + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'crwdcntrl.net', + uids: [{ id: 'some-random-id-value', atype: 1 }], + }); + }); + + it('DigiTrust; getValue call', function() { + const userId = { + digitrustid: { + data: { + id: '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}] + }); + }); + + it('criteo', function() { + const userId = { + criteoId: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'criteo.com', + uids: [{id: 'some-random-id-value', atype: 1}] + }); + }); + + it('NetId', function() { + const userId = { + netId: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(1); + expect(newEids[0]).to.deep.equal({ + source: 'netid.de', + 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 + }] + }); + }); +}); + +describe('Negative case', function() { + it('eids array generation for UN-known sub-module', function() { + // UnknownCommonId + const userId = { + unknowncid: 'some-random-id-value' + }; + const newEids = createEidsArray(userId); + expect(newEids.length).to.equal(0); + }); + + it('eids array generation for known sub-module with non-string value', function() { + // pubCommonId + let userId = { + pubcid: undefined + }; + let newEids = createEidsArray(userId); + expect(newEids.length).to.equal(0); + userId.pubcid = 123; + newEids = createEidsArray(userId); + expect(newEids.length).to.equal(0); + userId.pubcid = []; + newEids = createEidsArray(userId); + expect(newEids.length).to.equal(0); + userId.pubcid = {}; + newEids = createEidsArray(userId); + expect(newEids.length).to.equal(0); + userId.pubcid = null; + newEids = createEidsArray(userId); + expect(newEids.length).to.equal(0); + }); +}); diff --git a/test/spec/modules/emoteevBidAdapter_spec.js b/test/spec/modules/emoteevBidAdapter_spec.js index 5e22c039269..43ae62f1eb9 100644 --- a/test/spec/modules/emoteevBidAdapter_spec.js +++ b/test/spec/modules/emoteevBidAdapter_spec.js @@ -47,10 +47,10 @@ import { validateExternalId, VENDOR_ID, WALLPAPER, -} from 'modules/emoteevBidAdapter'; -import * as url from '../../../src/url'; -import * as utils from '../../../src/utils'; -import {config} from '../../../src/config'; + storage +} from 'modules/emoteevBidAdapter.js'; +import * as utils from '../../../src/utils.js'; +import {config} from '../../../src/config.js'; const cannedValidBidRequests = [{ adUnitCode: '/19968336/header-bid-tag-1', @@ -329,108 +329,108 @@ describe('emoteevBidAdapter', function () { }); describe('eventsUrl', function () { - expect(eventsUrl(null)).to.deep.equal(url.format({ + expect(eventsUrl(null)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(DEFAULT_ENV), pathname: EVENTS_PATH })); - expect(eventsUrl('anything')).to.deep.equal(url.format({ + expect(eventsUrl('anything')).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(DEFAULT_ENV), pathname: EVENTS_PATH })); - expect(eventsUrl(PRODUCTION)).to.deep.equal(url.format({ + expect(eventsUrl(PRODUCTION)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(PRODUCTION), pathname: EVENTS_PATH })); - expect(eventsUrl(STAGING)).to.deep.equal(url.format({ + expect(eventsUrl(STAGING)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(STAGING), pathname: EVENTS_PATH })); - expect(eventsUrl(DEVELOPMENT)).to.deep.equal(url.format({ + expect(eventsUrl(DEVELOPMENT)).to.deep.equal(utils.buildUrl({ hostname: domain(DEVELOPMENT), pathname: EVENTS_PATH })); }); describe('bidderUrl', function () { - expect(bidderUrl(null)).to.deep.equal(url.format({ + expect(bidderUrl(null)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(DEFAULT_ENV), pathname: BIDDER_PATH })); - expect(bidderUrl('anything')).to.deep.equal(url.format({ + expect(bidderUrl('anything')).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(DEFAULT_ENV), pathname: BIDDER_PATH })); - expect(bidderUrl(PRODUCTION)).to.deep.equal(url.format({ + expect(bidderUrl(PRODUCTION)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(PRODUCTION), pathname: BIDDER_PATH })); - expect(bidderUrl(STAGING)).to.deep.equal(url.format({ + expect(bidderUrl(STAGING)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(STAGING), pathname: BIDDER_PATH })); - expect(bidderUrl(DEVELOPMENT)).to.deep.equal(url.format({ + expect(bidderUrl(DEVELOPMENT)).to.deep.equal(utils.buildUrl({ hostname: domain(DEVELOPMENT), pathname: BIDDER_PATH })); }); describe('userSyncIframeUrl', function () { - expect(userSyncIframeUrl(null)).to.deep.equal(url.format({ + expect(userSyncIframeUrl(null)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(DEFAULT_ENV), pathname: USER_SYNC_IFRAME_PATH })); - expect(userSyncIframeUrl('anything')).to.deep.equal(url.format({ + expect(userSyncIframeUrl('anything')).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(DEFAULT_ENV), pathname: USER_SYNC_IFRAME_PATH })); - expect(userSyncIframeUrl(PRODUCTION)).to.deep.equal(url.format({ + expect(userSyncIframeUrl(PRODUCTION)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(PRODUCTION), pathname: USER_SYNC_IFRAME_PATH })); - expect(userSyncIframeUrl(STAGING)).to.deep.equal(url.format({ + expect(userSyncIframeUrl(STAGING)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(STAGING), pathname: USER_SYNC_IFRAME_PATH })); - expect(userSyncIframeUrl(DEVELOPMENT)).to.deep.equal(url.format({ + expect(userSyncIframeUrl(DEVELOPMENT)).to.deep.equal(utils.buildUrl({ hostname: domain(DEVELOPMENT), pathname: USER_SYNC_IFRAME_PATH })); }); describe('userSyncImageUrl', function () { - expect(userSyncImageUrl(null)).to.deep.equal(url.format({ + expect(userSyncImageUrl(null)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(DEFAULT_ENV), pathname: USER_SYNC_IMAGE_PATH })); - expect(userSyncImageUrl('anything')).to.deep.equal(url.format({ + expect(userSyncImageUrl('anything')).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(DEFAULT_ENV), pathname: USER_SYNC_IMAGE_PATH })); - expect(userSyncImageUrl(PRODUCTION)).to.deep.equal(url.format({ + expect(userSyncImageUrl(PRODUCTION)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(PRODUCTION), pathname: USER_SYNC_IMAGE_PATH })); - expect(userSyncImageUrl(STAGING)).to.deep.equal(url.format({ + expect(userSyncImageUrl(STAGING)).to.deep.equal(utils.buildUrl({ protocol: 'https', hostname: domain(STAGING), pathname: USER_SYNC_IMAGE_PATH })); - expect(userSyncImageUrl(DEVELOPMENT)).to.deep.equal(url.format({ + expect(userSyncImageUrl(DEVELOPMENT)).to.deep.equal(utils.buildUrl({ hostname: domain(DEVELOPMENT), pathname: USER_SYNC_IMAGE_PATH })); @@ -749,7 +749,7 @@ describe('emoteevBidAdapter', function () { }); beforeEach(function () { triggerPixelStub = sinon.stub(utils, 'triggerPixel'); - getCookieSpy = sinon.spy(utils, 'getCookie'); + getCookieSpy = sinon.spy(storage, 'getCookie'); getConfigSpy = sinon.spy(config, 'getConfig'); getParameterByNameSpy = sinon.spy(utils, 'getParameterByName'); }); @@ -776,7 +776,7 @@ describe('emoteevBidAdapter', function () { }; spec.isBidRequestValid(validBidRequest); sinon.assert.notCalled(utils.triggerPixel); - sinon.assert.notCalled(utils.getCookie); + sinon.assert.notCalled(storage.getCookie); // sinon.assert.notCalled(config.getConfig); sinon.assert.notCalled(utils.getParameterByName); }); @@ -786,7 +786,7 @@ describe('emoteevBidAdapter', function () { const invalidBidRequest = {}; spec.isBidRequestValid(invalidBidRequest); sinon.assert.notCalled(utils.triggerPixel); - sinon.assert.notCalled(utils.getCookie); + sinon.assert.notCalled(storage.getCookie); // disabling these getConfig tests as they have been flaky in browserstack testing // sinon.assert.notCalled(config.getConfig); sinon.assert.notCalled(utils.getParameterByName); @@ -796,7 +796,7 @@ describe('emoteevBidAdapter', function () { it('has intended side-effects', function () { spec.buildRequests(cannedValidBidRequests, cannedBidderRequest); sinon.assert.notCalled(utils.triggerPixel); - sinon.assert.notCalled(utils.getCookie); + sinon.assert.notCalled(storage.getCookie); // sinon.assert.callCount(config.getConfig, 3); sinon.assert.callCount(utils.getParameterByName, 2); }); @@ -805,7 +805,7 @@ describe('emoteevBidAdapter', function () { it('has intended side-effects', function () { spec.interpretResponse(serverResponse); sinon.assert.notCalled(utils.triggerPixel); - sinon.assert.notCalled(utils.getCookie); + sinon.assert.notCalled(storage.getCookie); // sinon.assert.notCalled(config.getConfig); sinon.assert.notCalled(utils.getParameterByName); }); @@ -815,7 +815,7 @@ describe('emoteevBidAdapter', function () { const bidObject = serverResponse.body[0]; spec.onBidWon(bidObject); sinon.assert.calledOnce(utils.triggerPixel); - sinon.assert.calledOnce(utils.getCookie); + sinon.assert.calledOnce(storage.getCookie); // sinon.assert.calledOnce(config.getConfig); sinon.assert.calledOnce(utils.getParameterByName); }); @@ -824,7 +824,7 @@ describe('emoteevBidAdapter', function () { it('has intended side-effects', function () { spec.onTimeout(cannedValidBidRequests[0]); sinon.assert.calledOnce(utils.triggerPixel); - sinon.assert.notCalled(utils.getCookie); + sinon.assert.notCalled(storage.getCookie); // sinon.assert.calledOnce(config.getConfig); sinon.assert.calledOnce(utils.getParameterByName); }); @@ -833,7 +833,7 @@ describe('emoteevBidAdapter', function () { it('has intended side-effects', function () { spec.getUserSyncs({}); sinon.assert.notCalled(utils.triggerPixel); - sinon.assert.notCalled(utils.getCookie); + sinon.assert.notCalled(storage.getCookie); // sinon.assert.calledOnce(config.getConfig); sinon.assert.calledOnce(utils.getParameterByName); }); diff --git a/test/spec/modules/emx_digitalBidAdapter_spec.js b/test/spec/modules/emx_digitalBidAdapter_spec.js index 7f01d3566a0..7be8a2ce5ac 100644 --- a/test/spec/modules/emx_digitalBidAdapter_spec.js +++ b/test/spec/modules/emx_digitalBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; -import { spec } from 'modules/emx_digitalBidAdapter'; -import * as utils from 'src/utils'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/emx_digitalBidAdapter.js'; +import * as utils from 'src/utils.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('emx_digital Adapter', function () { describe('callBids', function () { @@ -335,11 +335,12 @@ describe('emx_digital Adapter', function () { it('should have the right gdpr info when enabled', function () { let consentString = 'OIJSZsOAFsABAB8EMXZZZZZ+A=='; - bidderRequest.gdprConsent = { + const gdprBidderRequest = utils.deepClone(bidderRequest); + gdprBidderRequest.gdprConsent = { 'consentString': consentString, 'gdprApplies': true }; - let request = spec.buildRequests(bidderRequest.bids, bidderRequest); + let request = spec.buildRequests(gdprBidderRequest.bids, gdprBidderRequest); request = JSON.parse(request.data) expect(request.regs.ext).to.have.property('gdpr', 1); @@ -347,18 +348,21 @@ describe('emx_digital Adapter', function () { }); it('should\'t contain consent string if gdpr isn\'t applied', function () { - bidderRequest.gdprConsent = { + const nonGdprBidderRequest = utils.deepClone(bidderRequest); + nonGdprBidderRequest.gdprConsent = { 'gdprApplies': false }; - let request = spec.buildRequests(bidderRequest.bids, bidderRequest); + let request = spec.buildRequests(nonGdprBidderRequest.bids, nonGdprBidderRequest); request = JSON.parse(request.data) expect(request.regs.ext).to.have.property('gdpr', 0); expect(request).to.not.have.property('user'); }); + it('should add us privacy info to request', function() { + const uspBidderRequest = utils.deepClone(bidderRequest); let consentString = '1YNN'; - bidderRequest.uspConsent = consentString; - let request = spec.buildRequests(bidderRequest.bids, bidderRequest); + uspBidderRequest.uspConsent = consentString; + let request = spec.buildRequests(uspBidderRequest.bids, uspBidderRequest); request = JSON.parse(request.data); expect(request.us_privacy).to.exist; expect(request.us_privacy).to.exist.and.to.equal(consentString); @@ -388,6 +392,52 @@ describe('emx_digital Adapter', function () { 'auctionId': '1d1a01234a475' }; + const bid_outstream = { + 'bidderRequest': { + 'bids': [{ + 'bidder': 'emx_digital', + 'params': { + 'tagid': '25251', + 'video': {} + }, + 'mediaTypes': { + 'video': { + 'context': 'outstream', + 'playerSize': [640, 480] + } + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '987654321cba', + 'bidderRequestId': '22edbae3120bf6', + 'auctionId': '1d1a01234a475' + }, { + 'bidder': 'emx_digital', + 'params': { + 'tagid': '25252', + 'video': {} + }, + 'mediaTypes': { + 'video': { + 'context': 'instream', + 'playerSize': [640, 480] + } + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250], + [300, 600] + ], + 'bidId': '987654321dcb', + 'bidderRequestId': '22edbae3120bf6', + 'auctionId': '1d1a01234a475' + }] + } + }; + const serverResponse = { 'id': '12819a18-56e1-4256-b836-b69a10202668', 'seatbid': [{ @@ -408,7 +458,7 @@ describe('emx_digital Adapter', function () { 'adm': '', 'crid': '3434abab35', 'h': 600, - 'id': '987654321cba', + 'id': '987654321dcb', 'price': 0.5, 'ttl': 300, 'w': 300 @@ -506,25 +556,39 @@ describe('emx_digital Adapter', function () { }); it('returns a vastXml kvp for video creatives', function () { - serverResponse.seatbid[0].bid[0].adm = ''; - serverResponse.seatbid[1].bid[0].adm = ''; + const vastServerResponse = utils.deepClone(serverResponse); + vastServerResponse.seatbid[0].bid[0].adm = ''; + vastServerResponse.seatbid[1].bid[0].adm = ''; let result = spec.interpretResponse({ - body: serverResponse + body: vastServerResponse }, { bidRequest: bid } ); const ad0 = result[0]; const ad1 = result[1]; expect(ad0.mediaType).to.equal('video'); expect(ad0.ad.indexOf(' -1).to.equal(true); - expect(ad0.vastXml).to.equal(serverResponse.seatbid[0].bid[0].adm); + expect(ad0.vastXml).to.equal(vastServerResponse.seatbid[0].bid[0].adm); expect(ad0.ad).to.exist.and.to.be.a('string'); expect(ad1.mediaType).to.equal('video'); expect(ad1.ad.indexOf(' -1).to.equal(true); - expect(ad1.vastXml).to.equal(serverResponse.seatbid[1].bid[0].adm); + expect(ad1.vastXml).to.equal(vastServerResponse.seatbid[1].bid[0].adm); expect(ad1.ad).to.exist.and.to.be.a('string'); }); + it('returns a renderer for outstream video creatives', function () { + const vastServerResponse = utils.deepClone(serverResponse); + vastServerResponse.seatbid[0].bid[0].adm = ''; + vastServerResponse.seatbid[1].bid[0].adm = ''; + let result = spec.interpretResponse({body: vastServerResponse}, bid_outstream); + const ad0 = result[0]; + const ad1 = result[1]; + expect(ad0.renderer).to.exist.and.to.be.a('object'); + expect(ad0.renderer.url).to.equal('https://js.brealtime.com/outstream/1.30.0/bundle.js'); + expect(ad0.renderer.id).to.equal('987654321cba'); + expect(ad1.renderer).to.equal(undefined); + }); + it('handles nobid responses', function () { let serverResponse = { 'bids': [] @@ -537,11 +601,12 @@ describe('emx_digital Adapter', function () { }); it('should not throw an error when decoding an improperly encoded adm', function () { - serverResponse.seatbid[0].bid[0].adm = '\\<\\/script\\>'; - serverResponse.seatbid[1].bid[0].adm = '%3F%%3Demx%3C3prebid' + const badAdmServerResponse = utils.deepClone(serverResponse); + badAdmServerResponse.seatbid[0].bid[0].adm = '\\<\\/script\\>'; + badAdmServerResponse.seatbid[1].bid[0].adm = '%3F%%3Demx%3C3prebid'; assert.doesNotThrow(() => spec.interpretResponse({ - body: serverResponse + body: badAdmServerResponse })); }); }); diff --git a/test/spec/modules/envivoBidAdapter_spec.js b/test/spec/modules/envivoBidAdapter_spec.js index e3315ced921..7bd1dd1ccf1 100644 --- a/test/spec/modules/envivoBidAdapter_spec.js +++ b/test/spec/modules/envivoBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/envivoBidAdapter'; +import { spec } from 'modules/envivoBidAdapter.js'; const ENDPOINT = 'https://ad.nvivo.tv/ads/www/admin/plugins/Prebid/getAd.php'; diff --git a/test/spec/modules/eplanningAnalyticsAdapter_spec.js b/test/spec/modules/eplanningAnalyticsAdapter_spec.js index 3e72cfc1dcc..255d116a0ff 100644 --- a/test/spec/modules/eplanningAnalyticsAdapter_spec.js +++ b/test/spec/modules/eplanningAnalyticsAdapter_spec.js @@ -1,8 +1,8 @@ -import eplAnalyticsAdapter from 'modules/eplanningAnalyticsAdapter'; -import includes from 'core-js/library/fn/array/includes'; +import eplAnalyticsAdapter from 'modules/eplanningAnalyticsAdapter.js'; +import includes from 'core-js-pure/features/array/includes.js'; import { expect } from 'chai'; -import {parse as parseURL} from 'src/url'; -import { server } from 'test/mocks/xhr'; +import { parseUrl } from 'src/utils.js'; +import { server } from 'test/mocks/xhr.js'; let adapterManager = require('src/adapterManager').default; let events = require('src/events'); let constants = require('src/constants.json'); @@ -118,7 +118,7 @@ describe('eplanning analytics adapter', function () { expect(includes(['https://ads.ar.e-planning.net/hba/1/12345?d='], requests[0].url)); let info = requests[0].url; - let purl = parseURL(info); + let purl = parseUrl(info); let eplData = JSON.parse(decodeURIComponent(purl.search.d)); // Step 8 check that 6 events were sent diff --git a/test/spec/modules/eplanningBidAdapter_spec.js b/test/spec/modules/eplanningBidAdapter_spec.js index d0913ca53e8..f267680b46b 100644 --- a/test/spec/modules/eplanningBidAdapter_spec.js +++ b/test/spec/modules/eplanningBidAdapter_spec.js @@ -1,7 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/eplanningBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; -import * as utils from 'src/utils'; +import { spec, storage } from 'modules/eplanningBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('E-Planning Adapter', function () { const adapter = newBidder('spec'); @@ -13,6 +12,7 @@ describe('E-Planning Adapter', function () { const ADUNIT_CODE_VIEW3 = 'adunit-code-view3'; const CLEAN_ADUNIT_CODE2 = '300x250_1'; const CLEAN_ADUNIT_CODE = '300x250_0'; + const CLEAN_ADUNIT_CODE_ML = 'adunitco_de'; const BID_ID = '123456789'; const BID_ID2 = '987654321'; const BID_ID3 = '998877665'; @@ -32,6 +32,17 @@ describe('E-Planning Adapter', function () { 'adUnitCode': ADUNIT_CODE, 'sizes': [[300, 250], [300, 600]], }; + const ML = '1'; + const validBidMappingLinear = { + 'bidder': 'eplanning', + 'bidId': BID_ID, + 'params': { + 'ci': CI, + 'ml': ML, + }, + 'adUnitCode': ADUNIT_CODE, + 'sizes': [[300, 250], [300, 600]], + }; const validBid2 = { 'bidder': 'eplanning', 'bidId': BID_ID2, @@ -261,6 +272,12 @@ describe('E-Planning Adapter', function () { expect(e).to.equal('300x250_0:300x250,300x600'); }); + it('should return e parameter with linear mapping attribute with value according to the adunit sizes', function () { + let bidRequestsML = [validBidMappingLinear]; + const e = spec.buildRequests(bidRequestsML, bidderRequest).data.e; + expect(e).to.equal(CLEAN_ADUNIT_CODE_ML + ':300x250,300x600'); + }); + it('should return correct e parameter with more than one adunit', function () { const NEW_CODE = ADUNIT_CODE + '2'; const CLEAN_NEW_CODE = CLEAN_ADUNIT_CODE + '2'; @@ -278,6 +295,25 @@ describe('E-Planning Adapter', function () { expect(e).to.equal('300x250_0:300x250,300x600+100x100_0:100x100'); }); + it('should return correct e parameter with linear mapping attribute with more than one adunit', function () { + let bidRequestsML = [validBidMappingLinear]; + const NEW_CODE = ADUNIT_CODE + '2'; + const CLEAN_NEW_CODE = CLEAN_ADUNIT_CODE_ML + '2'; + const anotherBid = { + 'bidder': 'eplanning', + 'params': { + 'ci': CI, + 'ml': ML, + }, + 'adUnitCode': NEW_CODE, + 'sizes': [[100, 100]], + }; + bidRequestsML.push(anotherBid); + + const e = spec.buildRequests(bidRequestsML, bidderRequest).data.e; + expect(e).to.equal(CLEAN_ADUNIT_CODE_ML + ':300x250,300x600+' + CLEAN_NEW_CODE + ':100x100'); + }); + it('should return correct e parameter when the adunit has no size', function () { const noSizeBid = { 'bidder': 'eplanning', @@ -291,15 +327,29 @@ describe('E-Planning Adapter', function () { expect(e).to.equal('1x1_0:1x1'); }); + it('should return correct e parameter with linear mapping attribute when the adunit has no size', function () { + const noSizeBid = { + 'bidder': 'eplanning', + 'params': { + 'ci': CI, + 'ml': ML, + }, + 'adUnitCode': ADUNIT_CODE, + }; + + const e = spec.buildRequests([noSizeBid], bidderRequest).data.e; + expect(e).to.equal(CLEAN_ADUNIT_CODE_ML + ':1x1'); + }); + 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 () { @@ -508,10 +558,10 @@ describe('E-Planning Adapter', function () { }); } beforeEach(function () { - getLocalStorageSpy = sandbox.spy(utils, 'getDataFromLocalStorage'); - setDataInLocalStorageSpy = sandbox.spy(utils, 'setDataInLocalStorage'); + getLocalStorageSpy = sandbox.spy(storage, 'getDataFromLocalStorage'); + setDataInLocalStorageSpy = sandbox.spy(storage, 'setDataInLocalStorage'); - hasLocalStorageStub = sandbox.stub(utils, 'hasLocalStorage'); + hasLocalStorageStub = sandbox.stub(storage, 'hasLocalStorage'); hasLocalStorageStub.returns(true); clock = sandbox.useFakeTimers(); @@ -552,7 +602,7 @@ describe('E-Planning Adapter', function () { sinon.assert.calledWith(getLocalStorageSpy, storageIdRender); sinon.assert.calledWith(setDataInLocalStorageSpy, storageIdRender); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('1'); }); context('when element is fully in view', function() { @@ -566,29 +616,29 @@ describe('E-Planning Adapter', function () { expect(respuesta.data.vs).to.equal('F'); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('1'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal('1'); }); it('when you have more than four render', function() { - utils.setDataInLocalStorage(storageIdRender, 4); + storage.setDataInLocalStorage(storageIdRender, 4); respuesta = spec.buildRequests(bidRequests, bidderRequest); clock.tick(1005); expect(respuesta.data.vs).to.equal('0'); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('5'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('5'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal('1'); }); it('when you have more than four render and already record visibility', function() { - utils.setDataInLocalStorage(storageIdRender, 4); - utils.setDataInLocalStorage(storageIdView, 4); + storage.setDataInLocalStorage(storageIdRender, 4); + storage.setDataInLocalStorage(storageIdView, 4); respuesta = spec.buildRequests(bidRequests, bidderRequest); clock.tick(1005); expect(respuesta.data.vs).to.equal('a'); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('5'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal('5'); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('5'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal('5'); }); }); @@ -603,17 +653,17 @@ describe('E-Planning Adapter', function () { clock.tick(1005); expect(respuesta.data.vs).to.equal('F'); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('1'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal(null); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal(null); }); it('when you have more than four render', function() { - utils.setDataInLocalStorage(storageIdRender, 4); + storage.setDataInLocalStorage(storageIdRender, 4); respuesta = spec.buildRequests(bidRequests, bidderRequest); clock.tick(1005); expect(respuesta.data.vs).to.equal('0'); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('5'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal(null); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('5'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal(null); }); }); @@ -624,16 +674,16 @@ describe('E-Planning Adapter', function () { respuesta = spec.buildRequests(bidRequests, bidderRequest); clock.tick(1005); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('1'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal('1'); }); it('you should not register visibility with less than 50%', function() { createPartiallyInvisibleElement(); respuesta = spec.buildRequests(bidRequests, bidderRequest); clock.tick(1005); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('1'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal(null); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal(null); }); }); context('when width or height of the element is zero', function() { @@ -645,16 +695,16 @@ describe('E-Planning Adapter', function () { spec.buildRequests(bidRequests, bidderRequest) clock.tick(1005); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('1'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal(null); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal(null); }); it('if the height is zero but the width is within the range', function() { element.style.height = '0px'; spec.buildRequests(bidRequests, bidderRequest) clock.tick(1005); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('1'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal(null); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal(null); }); it('if both are zero', function() { element.style.height = '0px'; @@ -662,8 +712,8 @@ describe('E-Planning Adapter', function () { spec.buildRequests(bidRequests, bidderRequest) clock.tick(1005); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('1'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal(null); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal(null); }); }); context('when tab is inactive', function() { @@ -672,8 +722,8 @@ describe('E-Planning Adapter', function () { focusStub.returns(false); spec.buildRequests(bidRequests, bidderRequest); clock.tick(1005); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('1'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal(null); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal(null); }); }); context('segmentBeginsBeforeTheVisibleRange', function() { @@ -681,16 +731,16 @@ describe('E-Planning Adapter', function () { createElementOutOfRange(); spec.buildRequests(bidRequests, bidderRequest); clock.tick(1005); - expect(utils.getDataFromLocalStorage(storageIdRender)).to.equal('1'); - expect(utils.getDataFromLocalStorage(storageIdView)).to.equal(null); + expect(storage.getDataFromLocalStorage(storageIdRender)).to.equal('1'); + expect(storage.getDataFromLocalStorage(storageIdView)).to.equal(null); }); }); context('when there are multiple adunit', function() { let respuesta; beforeEach(function () { [ADUNIT_CODE_VIEW, ADUNIT_CODE_VIEW2, ADUNIT_CODE_VIEW3].forEach(ac => { - utils.setDataInLocalStorage('pbsr_' + ac, 5); - utils.setDataInLocalStorage('pbvi_' + ac, 5); + storage.setDataInLocalStorage('pbsr_' + ac, 5); + storage.setDataInLocalStorage('pbvi_' + ac, 5); }); }); afterEach(function () { @@ -710,8 +760,8 @@ describe('E-Planning Adapter', function () { respuesta = spec.buildRequests(bidRequestMultiple, bidderRequest); clock.tick(1005); [ADUNIT_CODE_VIEW, ADUNIT_CODE_VIEW2, ADUNIT_CODE_VIEW3].forEach(ac => { - expect(utils.getDataFromLocalStorage('pbsr_' + ac)).to.equal('6'); - expect(utils.getDataFromLocalStorage('pbvi_' + ac)).to.equal('6'); + expect(storage.getDataFromLocalStorage('pbsr_' + ac)).to.equal('6'); + expect(storage.getDataFromLocalStorage('pbvi_' + ac)).to.equal('6'); }); expect('aaa').to.equal(respuesta.data.vs); }); @@ -723,8 +773,8 @@ describe('E-Planning Adapter', function () { respuesta = spec.buildRequests(bidRequestMultiple, bidderRequest); clock.tick(1005); [ADUNIT_CODE_VIEW, ADUNIT_CODE_VIEW2, ADUNIT_CODE_VIEW3].forEach(ac => { - expect(utils.getDataFromLocalStorage('pbsr_' + ac)).to.equal('6'); - expect(utils.getDataFromLocalStorage('pbvi_' + ac)).to.equal('5'); + expect(storage.getDataFromLocalStorage('pbsr_' + ac)).to.equal('6'); + expect(storage.getDataFromLocalStorage('pbvi_' + ac)).to.equal('5'); }); expect('aaa').to.equal(respuesta.data.vs); @@ -736,11 +786,11 @@ describe('E-Planning Adapter', function () { respuesta = spec.buildRequests(bidRequestMultiple, bidderRequest); clock.tick(1005); - expect(utils.getDataFromLocalStorage('pbsr_' + ADUNIT_CODE_VIEW)).to.equal('6'); - expect(utils.getDataFromLocalStorage('pbvi_' + ADUNIT_CODE_VIEW)).to.equal('6'); + expect(storage.getDataFromLocalStorage('pbsr_' + ADUNIT_CODE_VIEW)).to.equal('6'); + expect(storage.getDataFromLocalStorage('pbvi_' + ADUNIT_CODE_VIEW)).to.equal('6'); [ADUNIT_CODE_VIEW2, ADUNIT_CODE_VIEW3].forEach(ac => { - expect(utils.getDataFromLocalStorage('pbsr_' + ac)).to.equal('6'); - expect(utils.getDataFromLocalStorage('pbvi_' + ac)).to.equal('5'); + expect(storage.getDataFromLocalStorage('pbsr_' + ac)).to.equal('6'); + expect(storage.getDataFromLocalStorage('pbvi_' + ac)).to.equal('5'); }); expect('aaa').to.equal(respuesta.data.vs); }); diff --git a/test/spec/modules/etargetBidAdapter_spec.js b/test/spec/modules/etargetBidAdapter_spec.js index ed512e55ea9..4f5e0c224ec 100644 --- a/test/spec/modules/etargetBidAdapter_spec.js +++ b/test/spec/modules/etargetBidAdapter_spec.js @@ -1,7 +1,6 @@ import {assert, expect} from 'chai'; -import * as url from 'src/url'; -import {spec} from 'modules/etargetBidAdapter'; -import { BANNER, VIDEO } from 'src/mediaTypes'; +import {spec} from 'modules/etargetBidAdapter.js'; +import { BANNER, VIDEO } from 'src/mediaTypes.js'; describe('etarget adapter', function () { let serverResponse, bidRequest, bidResponses; diff --git a/test/spec/modules/feedadBidAdapter_spec.js b/test/spec/modules/feedadBidAdapter_spec.js index d7d0f32e252..066ab6b21f6 100644 --- a/test/spec/modules/feedadBidAdapter_spec.js +++ b/test/spec/modules/feedadBidAdapter_spec.js @@ -1,7 +1,7 @@ import {expect} from 'chai'; -import {spec} from 'modules/feedadBidAdapter'; -import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes'; -import {server} from 'test/mocks/xhr'; +import {spec} from 'modules/feedadBidAdapter.js'; +import {BANNER, NATIVE, VIDEO} from '../../../src/mediaTypes.js'; +import {server} from 'test/mocks/xhr.js'; const CODE = 'feedad'; diff --git a/test/spec/modules/fidelityBidAdapter_spec.js b/test/spec/modules/fidelityBidAdapter_spec.js index 85cd0bb0c3b..304a98675b3 100644 --- a/test/spec/modules/fidelityBidAdapter_spec.js +++ b/test/spec/modules/fidelityBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/fidelityBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/fidelityBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('FidelityAdapter', function () { const adapter = newBidder(spec); @@ -67,7 +67,19 @@ describe('FidelityAdapter', function () { bidId: '2ffb201a808da7', bidderRequestId: '178e34bad3658f', requestId: 'c45dd708-a418-42ec-b8a7-b70a6c6fab0a', - transactionId: 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b' + transactionId: 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b', + schain: { + ver: '1.0', + complete: 1, + nodes: [{ + asi: 'exchange1.com', + sid: '1234', + hp: 1, + rid: 'bid-request-1', + name: 'publisher', + domain: 'publisher.com' + }] + } } ], start: 1472239426002, @@ -78,7 +90,8 @@ describe('FidelityAdapter', function () { } }; - it('should add source and verison to the tag', function () { + it('should add params to the request', function () { + let schainString = '1.0,1!exchange1.com,1234,1,bid-request-1,publisher,publisher.com'; const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); const payload = request.data; expect(payload.from).to.exist; @@ -92,9 +105,11 @@ describe('FidelityAdapter', function () { expect(payload.flashver).to.exist; expect(payload.tmax).to.exist; expect(payload.defloc).to.exist; + expect(payload.schain).to.exist.and.to.be.a('string'); + expect(payload.schain).to.equal(schainString); }); - it('should add gdpr 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 = { @@ -103,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 da575035d09..29136c85241 100644 --- a/test/spec/modules/fintezaAnalyticsAdapter_spec.js +++ b/test/spec/modules/fintezaAnalyticsAdapter_spec.js @@ -1,8 +1,8 @@ -import fntzAnalyticsAdapter from 'modules/fintezaAnalyticsAdapter'; -import includes from 'core-js/library/fn/array/includes'; +import fntzAnalyticsAdapter from 'modules/fintezaAnalyticsAdapter.js'; +import includes from 'core-js-pure/features/array/includes.js'; import { expect } from 'chai'; -import { parse as parseURL } from 'src/url'; -import { server } from 'test/mocks/xhr'; +import { parseUrl } from 'src/utils.js'; +import { server } from 'test/mocks/xhr.js'; let adapterManager = require('src/adapterManager').default; let events = require('src/events'); @@ -81,7 +81,7 @@ describe('finteza analytics adapter', function () { expect(server.requests[0].method).to.equal('GET'); expect(server.requests[0].withCredentials).to.equal(true); - const url = parseURL(server.requests[0].url); + const url = parseUrl(server.requests[0].url); expect(url.protocol).to.equal('https'); expect(url.hostname).to.equal('content.mql5.com'); @@ -124,7 +124,7 @@ describe('finteza analytics adapter', function () { expect(server.requests[0].method).to.equal('GET'); expect(server.requests[0].withCredentials).to.equal(true); - let url = parseURL(server.requests[0].url); + let url = parseUrl(server.requests[0].url); expect(url.protocol).to.equal('https'); expect(url.hostname).to.equal('content.mql5.com'); @@ -138,7 +138,7 @@ describe('finteza analytics adapter', function () { expect(server.requests[1].method).to.equal('GET'); expect(server.requests[1].withCredentials).to.equal(true); - url = parseURL(server.requests[1].url); + url = parseUrl(server.requests[1].url); expect(url.protocol).to.equal('https'); expect(url.hostname).to.equal('content.mql5.com'); @@ -178,7 +178,7 @@ describe('finteza analytics adapter', function () { expect(server.requests[0].method).to.equal('GET'); expect(server.requests[0].withCredentials).to.equal(true); - const url = parseURL(server.requests[0].url); + const url = parseUrl(server.requests[0].url); expect(url.protocol).to.equal('https'); expect(url.hostname).to.equal('content.mql5.com'); @@ -217,7 +217,7 @@ describe('finteza analytics adapter', function () { expect(server.requests[0].method).to.equal('GET'); expect(server.requests[0].withCredentials).to.equal(true); - const url = parseURL(server.requests[0].url); + const url = parseUrl(server.requests[0].url); expect(url.protocol).to.equal('https'); expect(url.hostname).to.equal('content.mql5.com'); diff --git a/test/spec/modules/fluctBidAdapter_spec.js b/test/spec/modules/fluctBidAdapter_spec.js index 54829d5323c..6530a3c36cf 100644 --- a/test/spec/modules/fluctBidAdapter_spec.js +++ b/test/spec/modules/fluctBidAdapter_spec.js @@ -1,7 +1,7 @@ import {expect} from 'chai'; -import {spec} from 'modules/fluctBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; -import {config} from 'src/config'; +import {spec} from 'modules/fluctBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; +import {config} from 'src/config.js'; describe('fluctAdapter', function () { const adapter = newBidder(spec); diff --git a/test/spec/modules/freeWheelAdserverVideo_spec.js b/test/spec/modules/freeWheelAdserverVideo_spec.js index 1026cfb9e67..0a215092e18 100644 --- a/test/spec/modules/freeWheelAdserverVideo_spec.js +++ b/test/spec/modules/freeWheelAdserverVideo_spec.js @@ -1,8 +1,8 @@ import { expect } from 'chai'; -import { adpodUtils } from 'modules/freeWheelAdserverVideo'; -import { auctionManager } from 'src/auctionManager'; -import { config } from 'src/config'; -import { server } from 'test/mocks/xhr'; +import { adpodUtils } from 'modules/freeWheelAdserverVideo.js'; +import { auctionManager } from 'src/auctionManager.js'; +import { config } from 'src/config.js'; +import { server } from 'test/mocks/xhr.js'; describe('freeWheel adserver module', function() { let amStub; @@ -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 10a232410d7..3047b635d13 100644 --- a/test/spec/modules/freewheel-sspBidAdapter_spec.js +++ b/test/spec/modules/freewheel-sspBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/freewheel-sspBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/freewheel-sspBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const ENDPOINT = '//ads.stickyadstv.com/www/delivery/swfIndex.php'; @@ -13,7 +13,7 @@ describe('freewheelSSP BidAdapter Test', () => { }); }); - describe('isBidRequestValid', () => { + describe('isBidRequestValidForBanner', () => { let bid = { 'bidder': 'freewheel-ssp', 'params': { @@ -47,7 +47,39 @@ describe('freewheelSSP BidAdapter Test', () => { }); }); - describe('buildRequests', () => { + describe('isBidRequestValidForVideo', () => { + let bid = { + 'bidder': 'freewheel-ssp', + 'params': { + 'zoneId': '277225' + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'video': { + 'playerSize': [300, 250], + } + }, + 'sizes': [[300, 250]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }; + + it('should return true when required params found', () => { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', () => { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + wrong: 'missing zone id' + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequestsForBanner', () => { let bidRequests = [ { 'bidder': 'freewheel-ssp', @@ -71,18 +103,93 @@ describe('freewheelSSP BidAdapter Test', () => { it('should add parameters to the tag', () => { const request = spec.buildRequests(bidRequests); - const payload = request.data; + const payload = request[0].data; + expect(payload.reqType).to.equal('AdsSetup'); + expect(payload.protocolVersion).to.equal('2.0'); + expect(payload.zoneId).to.equal('277225'); + expect(payload.componentId).to.equal('prebid'); + expect(payload.componentSubId).to.equal('mustang'); + expect(payload.playerSize).to.equal('300x600'); + }); + + it('sends bid request to ENDPOINT via GET', () => { + const request = spec.buildRequests(bidRequests); + expect(request[0].url).to.contain(ENDPOINT); + expect(request[0].method).to.equal('GET'); + }); + + it('should add usp consent to the request', () => { + let uspConsentString = '1FW-SSP-uspConsent-'; + let bidderRequest = {}; + bidderRequest.uspConsent = uspConsentString; + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = request[0].data; + expect(payload.reqType).to.equal('AdsSetup'); + expect(payload.protocolVersion).to.equal('2.0'); + expect(payload.zoneId).to.equal('277225'); + 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); + }); + + it('should add gdpr consent to the request', () => { + let gdprConsentString = '1FW-SSP-gdprConsent-'; + let bidderRequest = { + 'gdprConsent': { + 'consentString': gdprConsentString + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = request[0].data; + expect(payload.reqType).to.equal('AdsSetup'); + expect(payload.protocolVersion).to.equal('2.0'); + expect(payload.zoneId).to.equal('277225'); + 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); + }); + }) + + describe('buildRequestsForVideo', () => { + let bidRequests = [ + { + 'bidder': 'freewheel-ssp', + 'params': { + 'zoneId': '277225' + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'video': { + 'playerSize': [300, 600], + } + }, + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + } + ]; + + it('should add parameters to the tag', () => { + const request = spec.buildRequests(bidRequests); + const payload = request[0].data; 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'); }); it('sends bid request to ENDPOINT via GET', () => { const request = spec.buildRequests(bidRequests); - expect(request.url).to.contain(ENDPOINT); - expect(request.method).to.equal('GET'); + expect(request[0].url).to.contain(ENDPOINT); + expect(request[0].method).to.equal('GET'); }); it('should add usp consent to the request', () => { @@ -90,11 +197,12 @@ describe('freewheelSSP BidAdapter Test', () => { let bidderRequest = {}; bidderRequest.uspConsent = uspConsentString; const request = spec.buildRequests(bidRequests, bidderRequest); - const payload = request.data; + const payload = request[0].data; 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); @@ -109,18 +217,19 @@ describe('freewheelSSP BidAdapter Test', () => { }; const request = spec.buildRequests(bidRequests, bidderRequest); - const payload = request.data; + const payload = request[0].data; 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); }); }) - describe('interpretResponse', () => { + describe('interpretResponseForBanner', () => { let bidRequests = [ { 'bidder': 'freewheel-ssp', @@ -187,6 +296,8 @@ describe('freewheelSSP BidAdapter Test', () => { '' + ' ' + ' Adswizz' + + ' ' + + ' https://ads.stickyadstv.com/auto-user-sync?dealId=NRJ-PRO-00008' + ' ' + ' ' + ' ' + @@ -220,12 +331,14 @@ describe('freewheelSSP BidAdapter Test', () => { currency: 'EUR', netRevenue: true, ttl: 360, + dealId: 'NRJ-PRO-00008', ad: ad } ]; - let result = spec.interpretResponse(response, request); + let result = spec.interpretResponse(response, request[0]); expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + expect(result[0].dealId).to.equal('NRJ-PRO-00008'); }); it('should get correct bid response with formated ad', () => { @@ -241,19 +354,162 @@ describe('freewheelSSP BidAdapter Test', () => { currency: 'EUR', netRevenue: true, ttl: 360, + dealId: 'NRJ-PRO-00008', ad: formattedAd } ]; - let result = spec.interpretResponse(response, request); + let result = spec.interpretResponse(response, request[0]); expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + expect(result[0].dealId).to.equal('NRJ-PRO-00008'); }); it('handles nobid responses', () => { - var reqest = spec.buildRequests(formattedBidRequests); + var request = spec.buildRequests(formattedBidRequests); + let response = ''; + + let result = spec.interpretResponse(response, request[0]); + expect(result.length).to.equal(0); + }); + }); + describe('interpretResponseForVideo', () => { + let bidRequests = [ + { + 'bidder': 'freewheel-ssp', + 'params': { + 'zoneId': '277225' + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'video': { + 'playerSize': [300, 600], + } + }, + 'sizes': [[300, 400]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + } + ]; + + let formattedBidRequests = [ + { + 'bidder': 'freewheel-ssp', + 'params': { + 'zoneId': '277225', + 'format': 'floorad' + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'video': { + 'playerSize': [300, 600], + } + }, + 'sizes': [[300, 400]], + 'bidId': '30b3other1c1838de1e', + 'bidderRequestId': '22edbae273other3bf6', + 'auctionId': '1d1a03079test0a475', + }, + { + 'bidder': 'stickyadstv', + 'params': { + 'zoneId': '277225', + 'format': 'test' + }, + 'adUnitCode': 'adunit-code', + 'mediaTypes': { + 'video': { + 'playerSize': [300, 600], + } + }, + 'sizes': [[300, 400]], + 'bidId': '2', + 'bidderRequestId': '3', + 'auctionId': '4', + } + ]; + + let response = '' + + '' + + ' ' + + ' Adswizz' + + ' ' + + ' https://ads.stickyadstv.com/auto-user-sync?dealId=NRJ-PRO-00008' + + ' ' + + ' ' + + ' ' + + ' 00:00:09' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' 0.2000' + + ' ' + + ' ' + + ' ' + + ''; + + let ad = '
'; + let formattedAd = '
'; + + it('should get correct bid response', () => { + var request = spec.buildRequests(bidRequests); + + let expectedResponse = [ + { + requestId: '30b31c1838de1e', + cpm: '0.2000', + width: 300, + height: 600, + creativeId: '28517153', + currency: 'EUR', + netRevenue: true, + ttl: 360, + dealId: 'NRJ-PRO-00008', + vastXml: response, + mediaType: 'video', + ad: ad + } + ]; + + let result = spec.interpretResponse(response, request[0]); + expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + expect(result[0].dealId).to.equal('NRJ-PRO-00008'); + }); + + it('should get correct bid response with formated ad', () => { + var request = spec.buildRequests(formattedBidRequests); + + let expectedResponse = [ + { + requestId: '30b31c1838de1e', + cpm: '0.2000', + width: 300, + height: 600, + creativeId: '28517153', + currency: 'EUR', + netRevenue: true, + ttl: 360, + dealId: 'NRJ-PRO-00008', + vastXml: response, + mediaType: 'video', + ad: formattedAd + } + ]; + + let result = spec.interpretResponse(response, request[0]); + expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); + expect(result[0].dealId).to.equal('NRJ-PRO-00008'); + }); + + it('handles nobid responses', () => { + var request = spec.buildRequests(formattedBidRequests); let response = ''; - let result = spec.interpretResponse(response, reqest); + let result = spec.interpretResponse(response, request[0]); expect(result.length).to.equal(0); }); }); diff --git a/test/spec/modules/gammaBidAdapter_spec.js b/test/spec/modules/gammaBidAdapter_spec.js index 78e69444bfd..cdaa1b5448a 100644 --- a/test/spec/modules/gammaBidAdapter_spec.js +++ b/test/spec/modules/gammaBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/gammaBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/gammaBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('gammaBidAdapter', function() { const adapter = newBidder(spec); diff --git a/test/spec/modules/gamoshiBidAdapter_spec.js b/test/spec/modules/gamoshiBidAdapter_spec.js index 003d6887ff8..79f58470cb3 100644 --- a/test/spec/modules/gamoshiBidAdapter_spec.js +++ b/test/spec/modules/gamoshiBidAdapter_spec.js @@ -1,7 +1,7 @@ import {expect} from 'chai'; -import {spec, helper} from 'modules/gamoshiBidAdapter'; -import * as utils from 'src/utils'; -import {newBidder} from '../../../src/adapters/bidderFactory'; +import {spec, helper} from 'modules/gamoshiBidAdapter.js'; +import * as utils from 'src/utils.js'; +import {newBidder} from '../../../src/adapters/bidderFactory.js'; const supplyPartnerId = '123'; const adapter = newBidder(spec); diff --git a/test/spec/modules/gdprEnforcement_spec.js b/test/spec/modules/gdprEnforcement_spec.js new file mode 100644 index 00000000000..7f4828267a9 --- /dev/null +++ b/test/spec/modules/gdprEnforcement_spec.js @@ -0,0 +1,453 @@ +import { deviceAccessHook, setEnforcementConfig, userSyncHook, userIdHook } 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'; + +describe('gdpr enforcement', function() { + let nextFnSpy; + let logWarnSpy; + let gdprDataHandlerStub; + let staticConfig = { + cmpApi: 'static', + timeout: 7500, + allowAuctionWithoutConsent: false, + consentData: { + getTCData: { + 'tcString': 'COuqj-POu90rDBcBkBENAZCgAPzAAAPAACiQFwwBAABAA1ADEAbQC4YAYAAgAxAG0A', + 'cmpId': 92, + 'cmpVersion': 100, + 'tcfPolicyVersion': 2, + 'gdprApplies': true, + 'isServiceSpecific': true, + 'useNonStandardStacks': false, + 'purposeOneTreatment': false, + 'publisherCC': 'US', + 'cmpStatus': 'loaded', + 'eventStatus': 'tcloaded', + 'outOfBand': { + 'allowedVendors': {}, + 'discloseVendors': {} + }, + 'purpose': { + 'consents': { + '1': true, + '2': true, + '3': true + }, + 'legitimateInterests': { + '1': false, + '2': false, + '3': false + } + }, + 'vendor': { + 'consents': { + '1': true, + '2': true, + '3': false + }, + 'legitimateInterests': { + '1': false, + '2': true, + '3': false, + '4': false, + '5': false + } + }, + 'specialFeatureOptins': { + '1': false, + '2': false + }, + 'restrictions': {}, + 'publisher': { + 'consents': { + '1': false, + '2': false, + '3': false + }, + 'legitimateInterests': { + '1': false, + '2': false, + '3': false + }, + 'customPurpose': { + 'consents': {}, + 'legitimateInterests': {} + } + } + } + } + }; + + after(function() { + validateStorageEnforcement.getHooks({hook: deviceAccessHook}).remove(); + $$PREBID_GLOBAL$$.requestBids.getHooks({hook: executeStorageCallbacks}).remove(); + }) + + describe('deviceAccessHook', function() { + beforeEach(function() { + nextFnSpy = sinon.spy(); + gdprDataHandlerStub = sinon.stub(gdprDataHandler, 'getConsentData'); + logWarnSpy = sinon.spy(utils, 'logWarn'); + }); + afterEach(function() { + config.resetConfig(); + gdprDataHandler.getConsentData.restore(); + logWarnSpy.restore(); + }); + it('should not allow device access when device access flag is set to false', function() { + config.setConfig({ + deviceAccess: false, + consentManagement: { + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: false, + enforceVendor: false, + vendorExceptions: ['appnexus', 'rubicon'] + }] + } + } + }); + + deviceAccessHook(nextFnSpy); + expect(nextFnSpy.calledOnce).to.equal(true); + let result = { + hasEnforcementHook: true, + valid: false + } + expect(nextFnSpy.calledWith(undefined, result)); + }); + + it('should only check for consent for vendor exceptions when enforcePurpose and enforceVendor are false', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: false, + enforceVendor: false, + vendorExceptions: ['appnexus'] + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.gdprApplies = true; + consentData.apiVersion = 2; + gdprDataHandlerStub.returns(consentData); + + deviceAccessHook(nextFnSpy, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 5, 'rubicon'); + expect(logWarnSpy.callCount).to.equal(0); + }); + + it('should check consent for all vendors when enforcePurpose and enforceVendor are true', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: true, + enforceVendor: true, + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.gdprApplies = true; + consentData.apiVersion = 2; + gdprDataHandlerStub.returns(consentData); + + deviceAccessHook(nextFnSpy, 1, 'appnexus'); + deviceAccessHook(nextFnSpy, 3, 'rubicon'); + expect(logWarnSpy.callCount).to.equal(1); + }); + + it('should allow device access when gdprApplies is false and hasDeviceAccess flag is true', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: true, + enforceVendor: true, + vendorExceptions: [] + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.gdprApplies = false; + consentData.apiVersion = 2; + gdprDataHandlerStub.returns(consentData); + + deviceAccessHook(nextFnSpy, 1, 'appnexus'); + expect(nextFnSpy.calledOnce).to.equal(true); + let result = { + hasEnforcementHook: true, + valid: true + } + expect(nextFnSpy.calledWith(undefined, result)); + }); + }); + + describe('userSyncHook', function() { + let curBidderStub; + let adapterManagerStub; + + beforeEach(function() { + gdprDataHandlerStub = sinon.stub(gdprDataHandler, 'getConsentData'); + logWarnSpy = sinon.spy(utils, 'logWarn'); + curBidderStub = sinon.stub(config, 'getCurrentBidder'); + adapterManagerStub = sinon.stub(adapterManager, 'getBidAdapter'); + nextFnSpy = sinon.spy(); + }); + + afterEach(function() { + config.getCurrentBidder.restore(); + config.resetConfig(); + gdprDataHandler.getConsentData.restore(); + adapterManager.getBidAdapter.restore(); + logWarnSpy.restore(); + }); + + it('should allow bidder to do user sync if consent is true', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: false, + enforceVendor: true, + vendorExceptions: ['sampleBidder2'] + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.gdprApplies = true; + consentData.apiVersion = 2; + gdprDataHandlerStub.returns(consentData); + + curBidderStub.returns('sampleBidder1'); + adapterManagerStub.withArgs('sampleBidder1').returns({ + getSpec: function() { + return { + 'gvlid': 1 + } + } + }); + userSyncHook(nextFnSpy); + + curBidderStub.returns('sampleBidder2'); + adapterManagerStub.withArgs('sampleBidder2').returns({ + getSpec: function() { + return { + 'gvlid': 3 + } + } + }); + userSyncHook(nextFnSpy); + expect(nextFnSpy.calledTwice).to.equal(true); + }); + + it('should not allow bidder to do user sync if user has denied consent', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: false, + enforceVendor: true, + vendorExceptions: [] + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.apiVersion = 2; + consentData.gdprApplies = true; + gdprDataHandlerStub.returns(consentData); + + curBidderStub.returns('sampleBidder1'); + adapterManagerStub.withArgs('sampleBidder1').returns({ + getSpec: function() { + return { + 'gvlid': 1 + } + } + }); + userSyncHook(nextFnSpy); + + curBidderStub.returns('sampleBidder2'); + adapterManagerStub.withArgs('sampleBidder2').returns({ + getSpec: function() { + return { + 'gvlid': 3 + } + } + }); + userSyncHook(nextFnSpy); + expect(nextFnSpy.calledOnce).to.equal(true); + expect(logWarnSpy.callCount).to.equal(1); + }); + + it('should not check vendor consent when enforceVendor is false', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: true, + enforceVendor: false, + vendorExceptions: ['sampleBidder1'] + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.apiVersion = 2; + consentData.gdprApplies = true; + gdprDataHandlerStub.returns(consentData); + + curBidderStub.returns('sampleBidder1'); + adapterManagerStub.withArgs('sampleBidder1').returns({ + getSpec: function() { + return { + 'gvlid': 1 + } + } + }); + userSyncHook(nextFnSpy); + + curBidderStub.returns('sampleBidder2'); + adapterManagerStub.withArgs('sampleBidder2').returns({ + getSpec: function() { + return { + 'gvlid': 3 + } + } + }); + userSyncHook(nextFnSpy); + expect(nextFnSpy.calledTwice).to.equal(true); + expect(logWarnSpy.callCount).to.equal(0); + }); + }); + + describe('userIdHook', function() { + beforeEach(function() { + logWarnSpy = sinon.spy(utils, 'logWarn'); + nextFnSpy = sinon.spy(); + }); + afterEach(function() { + config.resetConfig(); + logWarnSpy.restore(); + }); + it('should allow user id module if consent is given', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: false, + enforceVendor: true, + vendorExceptions: [] + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.apiVersion = 2; + consentData.gdprApplies = true; + let submodules = [{ + submodule: { + gvlid: 1, + name: 'sampleUserId' + } + }] + 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); + }); + + it('should allow userId module if gdpr not in scope', function() { + let submodules = [{ + submodule: { + gvlid: 1, + name: 'sampleUserId' + } + }]; + 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)); + }); + + it('should not enforce if not apiVersion 2', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: false, + enforceVendor: true, + vendorExceptions: [] + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.apiVersion = 1; + consentData.gdprApplies = true; + let submodules = [{ + submodule: { + gvlid: 1, + name: 'sampleUserId' + } + }] + userIdHook(nextFnSpy, submodules, consentData); + // Should not pass back hasValidated flag since version 1 + const args = nextFnSpy.getCalls()[0].args; + expect(args[1].hasValidated).to.be.undefined; + expect(args[0]).to.deep.equal(submodules); + expect(nextFnSpy.calledOnce).to.equal(true); + }); + + it('should not allow user id module if user denied consent', function() { + setEnforcementConfig({ + gdpr: { + rules: [{ + purpose: 'storage', + enforcePurpose: false, + enforceVendor: true, + vendorExceptions: [] + }] + } + }); + let consentData = {} + consentData.vendorData = staticConfig.consentData.getTCData; + consentData.apiVersion = 2; + consentData.gdprApplies = true; + let submodules = [{ + submodule: { + gvlid: 1, + name: 'sampleUserId' + } + }, { + submodule: { + gvlid: 3, + name: 'sampleUserId1' + } + }] + userIdHook(nextFnSpy, submodules, consentData); + expect(logWarnSpy.callCount).to.equal(1); + let expectedSubmodules = [{ + submodule: { + gvlid: 1, + name: 'sampleUserId' + } + }] + expect(nextFnSpy.calledWith(undefined, expectedSubmodules, consentData)); + }); + }); +}); diff --git a/test/spec/modules/getintentBidAdapter_spec.js b/test/spec/modules/getintentBidAdapter_spec.js index e743d85972c..1959bda5c39 100644 --- a/test/spec/modules/getintentBidAdapter_spec.js +++ b/test/spec/modules/getintentBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai' -import { spec } from 'modules/getintentBidAdapter' +import { spec } from 'modules/getintentBidAdapter.js' describe('GetIntent Adapter Tests:', function () { const bidRequests = [{ 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/googleAnalyticsAdapter_spec.js b/test/spec/modules/googleAnalyticsAdapter_spec.js index 6bc0d4e192d..b801b5fe696 100644 --- a/test/spec/modules/googleAnalyticsAdapter_spec.js +++ b/test/spec/modules/googleAnalyticsAdapter_spec.js @@ -1,4 +1,4 @@ -import ga from 'modules/googleAnalyticsAdapter'; +import ga from 'modules/googleAnalyticsAdapter.js'; var assert = require('assert'); diff --git a/test/spec/modules/gridBidAdapter_spec.js b/test/spec/modules/gridBidAdapter_spec.js index a71f2c05657..c8d04113aeb 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'; -import { newBidder } from 'src/adapters/bidderFactory'; +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); @@ -68,6 +69,14 @@ describe('TheMediaGrid Adapter', function () { }, 'adUnitCode': 'adunit-code-2', 'sizes': [[728, 90]], + 'mediaTypes': { + 'video': { + 'playerSize': [400, 600] + }, + 'banner': { + 'sizes': [[728, 90]] + } + }, 'bidId': '3150ccb55da321', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', @@ -79,6 +88,14 @@ describe('TheMediaGrid Adapter', function () { }, 'adUnitCode': 'adunit-code-1', 'sizes': [[300, 250], [300, 600]], + 'mediaTypes': { + 'video': { + 'playerSize': [400, 600] + }, + 'banner': { + 'sizes': [[300, 250], [300, 600]] + } + }, 'bidId': '42dbe3a7168a6a', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', @@ -97,13 +114,23 @@ describe('TheMediaGrid Adapter', function () { expect(payload).to.have.property('wrapperVersion', '$prebid.version$'); }); + it('sizes must be added from 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.have.property('u', referrer); + expect(payload).to.have.property('auids', '1,1'); + expect(payload).to.have.property('sizes', '300x250,300x600,728x90,400x600'); + expect(payload).to.have.property('r', '22edbae2733bf6'); + }); + it('sizes must not be duplicated', function () { 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); expect(payload).to.have.property('auids', '1,1,2'); - expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); + expect(payload).to.have.property('sizes', '300x250,300x600,728x90,400x600'); expect(payload).to.have.property('r', '22edbae2733bf6'); }); @@ -139,6 +166,100 @@ describe('TheMediaGrid Adapter', function () { 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('interpretResponse', function () { diff --git a/test/spec/modules/gridNMBidAdapter_spec.js b/test/spec/modules/gridNMBidAdapter_spec.js new file mode 100644 index 00000000000..0dbaac0c526 --- /dev/null +++ b/test/spec/modules/gridNMBidAdapter_spec.js @@ -0,0 +1,461 @@ +import { expect } from 'chai'; +import { spec, resetUserSync, getSyncUrl } from 'modules/gridNMBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; + +describe('TheMediaGridNM Adapter', 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': 'gridNM', + 'params': { + 'source': 'jwp', + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4', 'video/x-ms-wmv'], + 'protocols': [1, 2, 3, 4, 5, 6] + } + }, + '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 () { + const paramsList = [ + { + 'source': 'jwp', + 'secid': '11', + 'pubid': '22', + 'video': { + 'protocols': [1, 2, 3, 4, 5, 6] + } + }, + { + 'source': 'jwp', + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4', 'video/x-ms-wmv'], + } + }, + { + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4', 'video/x-ms-wmv'], + 'protocols': [1, 2, 3, 4, 5, 6] + } + }, + { + 'source': 'jwp', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4', 'video/x-ms-wmv'], + 'protocols': [1, 2, 3, 4, 5, 6] + } + }, + { + 'source': 'jwp', + 'secid': '11', + 'video': { + 'mimes': ['video/mp4', 'video/x-ms-wmv'], + 'protocols': [1, 2, 3, 4, 5, 6] + } + } + ]; + paramsList.forEach((params) => { + const invalidBid = Object.assign({}, bid); + delete invalidBid.params; + invalidBid.params = params; + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); + }); + + it('should return false when required params has invalid values', function () { + const paramsList = [ + { + 'source': 'jwp', + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4', 'video/x-ms-wmv'], + 'protocols': '1,2,3,4,5' + } + }, + { + 'source': 'jwp', + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': [1, 2], + 'protocols': [1, 2, 3, 4, 5] + } + }, + { + 'source': 'jwp', + 'secid': 11, + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4', 'video/x-ms-wmv'], + 'protocols': [1, 2, 3, 4, 5] + } + }, + { + 'source': 111, + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4', 'video/x-ms-wmv'], + 'protocols': [1, 2, 3, 4, 5] + } + } + ]; + + paramsList.forEach((params) => { + const invalidBid = Object.assign({}, bid); + delete invalidBid.params; + invalidBid.params = params; + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); + }); + }); + + describe('buildRequests', function () { + function parseRequestUrl(url) { + const res = {}; + url.replace(/^[^\?]+\?/, '').split('&').forEach((it) => { + const couple = it.split('='); + res[couple[0]] = decodeURIComponent(couple[1]); + }); + return res; + } + const bidderRequest = {refererInfo: {referer: 'https://example.com'}}; + const referrer = bidderRequest.refererInfo.referer; + let bidRequests = [ + { + 'bidder': 'gridNM', + 'params': { + 'source': 'jwp', + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4', 'video/x-ms-wmv'], + 'protocols': [1, 2, 3, 4, 5, 6] + } + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }, + { + 'bidder': 'gridNM', + 'params': { + 'source': 'jwp', + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4'], + 'protocols': [1, 2, 3], + 'skip': 1 + } + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '3150ccb55da321', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + } + ]; + + it('should attach valid params to the tag', function () { + const requests = spec.buildRequests(bidRequests, bidderRequest); + const requestsSizes = ['300x250,300x600', '728x90']; + requests.forEach((req, i) => { + expect(req.url).to.be.an('string'); + const payload = parseRequestUrl(req.url); + expect(payload).to.have.property('u', referrer); + expect(payload).to.have.property('r', '22edbae2733bf6'); + expect(payload).to.have.property('wrapperType', 'Prebid_js'); + expect(payload).to.have.property('wrapperVersion', '$prebid.version$'); + expect(payload).to.have.property('sizes', requestsSizes[i]); + expect(req.data).to.deep.equal(bidRequests[i].params); + }); + }); + + it('if gdprConsent is present payload must have gdpr params', function () { + const [request] = spec.buildRequests([bidRequests[0]], {gdprConsent: {consentString: 'AAA', gdprApplies: true}, refererInfo: bidderRequest.refererInfo}); + expect(request.url).to.be.an('string'); + const payload = parseRequestUrl(request.url); + expect(payload).to.have.property('u', referrer); + expect(payload).to.have.property('gdpr_consent', 'AAA'); + expect(payload).to.have.property('gdpr_applies', '1'); + }); + + it('if gdprApplies is false gdpr_applies must be 0', function () { + const [request] = spec.buildRequests([bidRequests[0]], {gdprConsent: {consentString: 'AAA', gdprApplies: false}}); + expect(request.url).to.be.an('string'); + const payload = parseRequestUrl(request.url); + expect(payload).to.have.property('gdpr_consent', 'AAA'); + expect(payload).to.have.property('gdpr_applies', '0'); + }); + + it('if gdprApplies is undefined gdpr_applies must be 1', function () { + const [request] = spec.buildRequests([bidRequests[0]], {gdprConsent: {consentString: 'AAA'}}); + expect(request.url).to.be.an('string'); + const payload = parseRequestUrl(request.url); + expect(payload).to.have.property('gdpr_consent', 'AAA'); + expect(payload).to.have.property('gdpr_applies', '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[0]], bidderRequestWithUSP); + expect(request.url).to.be.an('string'); + const payload = parseRequestUrl(request.url); + expect(payload).to.have.property('us_privacy', '1YNN'); + }); + }); + + describe('interpretResponse', function () { + const responses = [ + {'bid': [{'price': 1.15, 'adm': '\n<\/Ad>\n<\/VAST>', 'content_type': 'video', 'h': 250, 'w': 300, 'dealid': 11}], 'seat': '2'}, + {'bid': [{'price': 0.5, 'adm': '\n<\/Ad>\n<\/VAST>', 'content_type': 'video', 'h': 600, 'w': 300}], 'seat': '2'}, + {'bid': [{'price': 0, 'h': 250, 'w': 300}], 'seat': '2'}, + {'bid': [{'price': 0, 'adm': '\n<\/Ad>\n<\/VAST>', 'h': 250, 'w': 300}], 'seat': '2'}, + undefined, + {'bid': [], 'seat': '2'}, + {'seat': '2'}, + ]; + + it('should get correct video bid response', function () { + const bidRequests = [ + { + 'bidder': 'gridNM', + 'params': { + 'source': 'jwp', + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4', 'video/x-ms-wmv'], + 'protocols': [1, 2, 3, 4, 5, 6] + } + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '659423fff799cb', + 'bidderRequestId': '5f2009617a7c0a', + 'auctionId': '1cbd2feafe5e8b', + 'mediaTypes': { + 'video': { + 'context': 'instream' + } + } + }, + { + 'bidder': 'gridNM', + 'params': { + 'source': 'jwp', + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4'], + 'protocols': [1, 2, 3, 4, 5], + 'skip': 1 + } + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '2bc598e42b6a', + 'bidderRequestId': '1e8b5a465f404', + 'auctionId': '1cbd2feafe5e8b', + 'mediaTypes': { + 'video': { + 'context': 'instream' + } + } + } + ]; + const requests = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '659423fff799cb', + 'cpm': 1.15, + 'creativeId': '5f2009617a7c0a', + 'dealId': 11, + 'width': 300, + 'height': 250, + 'bidderCode': 'gridNM', + 'currency': 'USD', + 'mediaType': 'video', + 'netRevenue': false, + 'ttl': 360, + 'vastXml': '\n<\/Ad>\n<\/VAST>', + 'adResponse': { + 'content': '\n<\/Ad>\n<\/VAST>' + } + }, + { + 'requestId': '2bc598e42b6a', + 'cpm': 0.5, + 'creativeId': '1e8b5a465f404', + 'dealId': undefined, + 'width': 300, + 'height': 600, + 'bidderCode': 'gridNM', + 'currency': 'USD', + 'mediaType': 'video', + 'netRevenue': false, + 'ttl': 360, + 'vastXml': '\n<\/Ad>\n<\/VAST>', + 'adResponse': { + 'content': '\n<\/Ad>\n<\/VAST>' + } + } + ]; + + requests.forEach((req, i) => { + const result = spec.interpretResponse({'body': {'seatbid': [responses[i]]}}, req); + expect(result[0]).to.deep.equal(expectedResponse[i]); + }); + }); + + it('handles wrong and nobid responses', function () { + responses.slice(2).forEach((resp) => { + const request = spec.buildRequests([{ + 'bidder': 'gridNM', + 'params': { + 'source': 'jwp', + 'secid': '11', + 'pubid': '22', + 'video': { + 'mimes': ['video/mp4'], + 'protocols': [1, 2, 3, 4, 5], + 'skip': 1 + } + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '2bc598e42b6a', + 'bidderRequestId': '39d74f5b71464', + 'auctionId': '1cbd2feafe5e8b', + 'mediaTypes': { + 'video': { + 'context': 'instream' + } + } + }]); + const result = spec.interpretResponse({'body': {'seatbid': [resp]}}, request[0]); + expect(result.length).to.equal(0); + }); + }); + }); + + describe('user sync', function () { + const syncUrl = getSyncUrl(); + + beforeEach(function () { + resetUserSync(); + }); + + it('should register the Emily iframe', function () { + let syncs = spec.getUserSyncs({ + pixelEnabled: true + }); + + expect(syncs).to.deep.equal({type: 'image', url: syncUrl}); + }); + + it('should not register the Emily iframe more than once', function () { + let syncs = spec.getUserSyncs({ + pixelEnabled: true + }); + expect(syncs).to.deep.equal({type: 'image', url: syncUrl}); + + // when called again, should still have only been called once + syncs = spec.getUserSyncs(); + expect(syncs).to.equal(undefined); + }); + + it('should pass gdpr params if consent is true', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + gdprApplies: true, consentString: 'foo' + })).to.deep.equal({ + type: 'image', url: `${syncUrl}&gdpr=1&gdpr_consent=foo` + }); + }); + + it('should pass gdpr params if consent is false', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + gdprApplies: false, consentString: 'foo' + })).to.deep.equal({ + type: 'image', url: `${syncUrl}&gdpr=0&gdpr_consent=foo` + }); + }); + + it('should pass gdpr param gdpr_consent only when gdprApplies is undefined', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: 'foo' + })).to.deep.equal({ + type: 'image', url: `${syncUrl}&gdpr_consent=foo` + }); + }); + + it('should pass no params if gdpr consentString is not defined', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {})).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr consentString is a number', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: 0 + })).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr consentString is null', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: null + })).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr consentString is a object', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, { + consentString: {} + })).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass no params if gdpr is not defined', function () { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, undefined)).to.deep.equal({ + type: 'image', url: syncUrl + }); + }); + + it('should pass usPrivacy param if it is available', function() { + expect(spec.getUserSyncs({ pixelEnabled: true }, {}, {}, '1YNN')).to.deep.equal({ + type: 'image', url: `${syncUrl}&us_privacy=1YNN` + }); + }); + }); +}); diff --git a/test/spec/modules/gumgumBidAdapter_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js index f98d8bf306e..7022f8f96dd 100644 --- a/test/spec/modules/gumgumBidAdapter_spec.js +++ b/test/spec/modules/gumgumBidAdapter_spec.js @@ -1,8 +1,9 @@ import { expect } from 'chai'; -import { newBidder } from 'src/adapters/bidderFactory'; -import { spec } from 'modules/gumgumBidAdapter'; +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); @@ -63,6 +64,20 @@ 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 () { @@ -106,7 +121,7 @@ describe('gumgumAdapter', function () { expect(request.method).to.equal('GET'); expect(request.id).to.equal('30b31c1838de1e'); }); - it('should correctly set the request paramters depending on params field', function () { + it('should set t and fp parameters in bid request if inScreen request param is found', function () { const request = Object.assign({}, bidRequests[0]); delete request.params; request.params = { @@ -129,7 +144,28 @@ describe('gumgumAdapter', function () { expect(bidRequest.data.pubId).to.equal(request.params.inScreenPubID); expect(bidRequest.data).to.not.include.any.keys('t'); }); - it('should correctly set the request paramters depending on params field', function () { + it('should send pubId if videoPubID param is specified', function () { + const mediaTypes = { + video: { + playerSize: [640, 480], + context: 'instream', + minduration: 1, + maxduration: 2, + linearity: 1, + startdelay: 1, + placement: 123456, + protocols: [1, 2] + } + }; + const request = Object.assign({}, bidRequests[0]); + request.mediaTypes = mediaTypes + request.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; request.params = { @@ -139,6 +175,68 @@ describe('gumgumAdapter', function () { expect(bidRequest.data.pi).to.equal(5); expect(bidRequest.data).to.include.any.keys('ni'); }); + it('should add parameters associated with video if video request param is found', function () { + const videoVals = { + 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: videoVals + }; + request.params = { + '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); + expect(bidRequest.data.li).to.eq(videoVals.linearity); + expect(bidRequest.data.sd).to.eq(videoVals.startdelay); + expect(bidRequest.data.pt).to.eq(videoVals.placement); + expect(bidRequest.data.pr).to.eq(videoVals.protocols.join(',')); + 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'); @@ -198,6 +296,14 @@ describe('gumgumAdapter', function () { expect(bidRequest.data).to.not.include.any.keys('ns'); } }); + 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]; + const actualKeys = Object.keys(JSON.parse(bidRequest.data.jcsi)).sort(); + expect(actualKeys).to.eq(actualKeys); + expect(bidRequest.data.jcsi).to.eq(jcsi); + }); }) describe('interpretResponse', function () { @@ -221,6 +327,7 @@ describe('gumgumAdapter', function () { 'css': 'html { overflow-y: auto }', 'js': 'console.log("environment", env);' }, + 'jcsi': { t: 0, rq: 8 }, 'thms': 10000 } let bidRequest = { @@ -272,6 +379,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, @@ -307,7 +420,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/hpmdnetworkBidAdapter_spec.js b/test/spec/modules/hpmdnetworkBidAdapter_spec.js index 8e400f20def..9023fb248e9 100644 --- a/test/spec/modules/hpmdnetworkBidAdapter_spec.js +++ b/test/spec/modules/hpmdnetworkBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/hpmdnetworkBidAdapter'; +import { spec } from 'modules/hpmdnetworkBidAdapter.js'; describe('HPMDNetwork Adapter', function() { describe('isBidRequestValid', function () { diff --git a/test/spec/modules/hybridBidAdapter_spec.js b/test/spec/modules/hybridBidAdapter_spec.js new file mode 100644 index 00000000000..e5ad878c9b1 --- /dev/null +++ b/test/spec/modules/hybridBidAdapter_spec.js @@ -0,0 +1,275 @@ +import { expect } from 'chai' +import { spec } from 'modules/hybridBidAdapter.js' + +function getSlotConfigs(mediaTypes, params) { + return { + params: params, + sizes: [], + bidId: '2df8c0733f284e', + bidder: 'hybrid', + mediaTypes: mediaTypes, + transactionId: '31a58515-3634-4e90-9c96-f86196db1459' + } +} + +describe('Hybrid.ai Adapter', function() { + const PLACE_ID = '5af45ad34d506ee7acad0c26'; + const bidderRequest = { + refererInfo: { referer: 'referer' } + } + const bannerMandatoryParams = { + placeId: PLACE_ID, + placement: 'banner' + } + const videoMandatoryParams = { + placeId: PLACE_ID, + placement: 'video' + } + const validBidRequests = [ + getSlotConfigs({ banner: {} }, bannerMandatoryParams), + getSlotConfigs({ video: {playerSize: [[640, 480]]} }, videoMandatoryParams) + ] + describe('isBidRequestValid method', function() { + describe('returns true', function() { + describe('when banner slot config has all mandatory params', () => { + describe('and placement has the correct value', function() { + const slotConfig = getSlotConfigs( + { banner: {} }, + { + placeId: PLACE_ID, + placement: 'banner' + } + ) + const isBidRequestValid = spec.isBidRequestValid(slotConfig) + expect(isBidRequestValid).to.equal(true) + }) + describe('when video slot has all mandatory params.', function() { + it('should return true, when video mediatype object are correct.', function() { + const slotConfig = getSlotConfigs( + { + video: { + context: 'instream', + playerSize: [[640, 480]] + } + }, + { + placeId: PLACE_ID, + placement: 'video' + } + ) + const isBidRequestValid = spec.isBidRequestValid(slotConfig) + expect(isBidRequestValid).to.equal(true) + }) + }) + }) + }) + describe('returns false', function() { + describe('when params are not correct', function() { + function createSlotconfig(params) { + return getSlotConfigs({ banner: {} }, params) + } + it('does not have the placeId.', function() { + const isBidRequestValid = spec.isBidRequestValid( + createSlotconfig({ + placement: 'banner' + }) + ) + expect(isBidRequestValid).to.equal(false) + }) + it('does not have the placement.', function() { + const isBidRequestValid = spec.isBidRequestValid( + createSlotconfig({ + placeId: PLACE_ID + }) + ) + expect(isBidRequestValid).to.equal(false) + }) + it('does not have a the correct placement.', function() { + const isBidRequestValid = spec.isBidRequestValid( + createSlotconfig({ + placeId: PLACE_ID, + placement: 'something' + }) + ) + expect(isBidRequestValid).to.equal(false) + }) + }) + describe('when video mediaType object is not correct.', function() { + function createVideoSlotconfig(mediaType) { + return getSlotConfigs(mediaType, { + placeId: PLACE_ID, + placement: 'video' + }) + } + it('is a void object', function() { + const isBidRequestValid = spec.isBidRequestValid( + createVideoSlotconfig({ video: {} }) + ) + expect(isBidRequestValid).to.equal(false) + }) + it('does not have playerSize.', function() { + const isBidRequestValid = spec.isBidRequestValid( + createVideoSlotconfig({ video: { context: 'instream' } }) + ) + expect(isBidRequestValid).to.equal(false) + }) + it('does not have context', function() { + const isBidRequestValid = spec.isBidRequestValid( + createVideoSlotconfig({ + video: { + playerSize: [[640, 480]] + } + }) + ) + expect(isBidRequestValid).to.equal(false) + }) + }) + }) + }) + it('Url params should be correct ', function() { + const request = spec.buildRequests(validBidRequests, bidderRequest) + expect(request.method).to.equal('POST') + expect(request.url).to.equal('https://hbe198.hybrid.ai/prebidhb') + }) + + describe('buildRequests method', function() { + it('Common data request should be correct', function() { + const request = spec.buildRequests(validBidRequests, bidderRequest) + const data = JSON.parse(request.data) + expect(Array.isArray(data.bidRequests)).to.equal(true) + expect(data.url).to.equal('referer') + data.bidRequests.forEach(bid => { + expect(bid.bidId).to.equal('2df8c0733f284e') + expect(bid.placeId).to.equal(PLACE_ID) + expect(bid.transactionId).to.equal('31a58515-3634-4e90-9c96-f86196db1459') + }) + }) + + describe('GDPR params', function() { + describe('when there are not consent management platform', function() { + it('cmp should be false', function() { + const request = spec.buildRequests(validBidRequests, bidderRequest) + const data = JSON.parse(request.data) + expect(data.cmp).to.equal(false) + }) + }) + describe('when there are consent management platform', function() { + it('cmps should be true and ga should not sended, when gdprApplies is undefined', function() { + bidderRequest['gdprConsent'] = { + gdprApplies: undefined, + consentString: 'consentString' + } + const request = spec.buildRequests(validBidRequests, bidderRequest) + const data = JSON.parse(request.data) + expect(data.cmp).to.equal(true) + expect(Object.keys(data).indexOf('data')).to.equal(-1) + expect(data.cs).to.equal('consentString') + }) + it('cmps should be true and all gdpr parameters should be sended, when there are gdprApplies', function() { + bidderRequest['gdprConsent'] = { + gdprApplies: true, + consentString: 'consentString' + } + const request = spec.buildRequests(validBidRequests, bidderRequest) + const data = JSON.parse(request.data) + expect(data.cmp).to.equal(true) + expect(data.ga).to.equal(true) + expect(data.cs).to.equal('consentString') + }) + }) + }) + + describe('BidRequests params', function() { + const request = spec.buildRequests(validBidRequests, bidderRequest) + const data = JSON.parse(request.data) + const bidRequests = data.bidRequests + it('should request a Banner', function() { + const bannerBid = bidRequests[0] + expect(bannerBid.placement).to.equal(spec.placementTypes[bannerMandatoryParams.placement]) + }) + it('should request a Video', function() { + const bannerBid = bidRequests[1] + expect(bannerBid.placement).to.equal(spec.placementTypes[videoMandatoryParams.placement]) + }) + }) + }) + + describe('interpret response method', function() { + it('should return a void array, when the server response are not correct.', function() { + const request = { data: JSON.stringify({}) } + const serverResponse = { + body: {} + } + const bids = spec.interpretResponse(serverResponse, request) + expect(typeof bids).to.equal('object') + expect(bids.length).to.equal(0) + }) + it('should return a void array, when the server response have not got bids.', function() { + const request = { data: JSON.stringify({}) } + const serverResponse = { body: { bids: [] } } + const bids = spec.interpretResponse(serverResponse, request) + expect(typeof bids).to.equal('object') + expect(bids.length).to.equal(0) + }) + describe('when the server response return a bid', function() { + describe('the bid is a banner', function() { + it('should return a banner bid', function() { + const request = spec.buildRequests([validBidRequests[0]], bidderRequest) + const serverResponse = { + body: { + bids: [ + { + bidId: '2df8c0733f284e', + price: 0.5, + currency: 'USD', + content: 'html', + width: 100, + height: 100 + } + ] + } + } + const bids = spec.interpretResponse(serverResponse, request) + expect(bids.length).to.equal(1) + expect(bids[0].requestId).to.equal('2df8c0733f284e') + expect(bids[0].mediaType).to.equal(spec.supportedMediaTypes[0]) + expect(bids[0].cpm).to.equal(0.5) + expect(bids[0].width).to.equal(100) + expect(bids[0].height).to.equal(100) + expect(bids[0].currency).to.equal('USD') + expect(bids[0].netRevenue).to.equal(true) + expect(typeof bids[0].ad).to.equal('string') + }) + }) + describe('the bid is a video', function() { + it('should return a video bid', function() { + const request = spec.buildRequests([validBidRequests[1]], bidderRequest) + const serverResponse = { + body: { + bids: [ + { + bidId: '2df8c0733f284e', + price: 0.5, + currency: 'USD', + content: 'html', + width: 100, + height: 100 + } + ] + } + } + const bids = spec.interpretResponse(serverResponse, request) + expect(bids.length).to.equal(1) + expect(bids[0].requestId).to.equal('2df8c0733f284e') + expect(bids[0].mediaType).to.equal(spec.supportedMediaTypes[1]) + expect(bids[0].cpm).to.equal(0.5) + expect(bids[0].width).to.equal(100) + expect(bids[0].height).to.equal(100) + expect(bids[0].currency).to.equal('USD') + expect(bids[0].netRevenue).to.equal(true) + expect(typeof bids[0].vastXml).to.equal('string') + }) + }) + }) + }) +}) diff --git a/test/spec/modules/iasBidAdapter_spec.js b/test/spec/modules/iasBidAdapter_spec.js index 7ac9d1906f5..1743ac947e6 100644 --- a/test/spec/modules/iasBidAdapter_spec.js +++ b/test/spec/modules/iasBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/iasBidAdapter'; +import { spec } from 'modules/iasBidAdapter.js'; describe('iasBidAdapter is an adapter that', function () { it('has the correct bidder code', function () { diff --git a/test/spec/modules/id5IdSystem_spec.js b/test/spec/modules/id5IdSystem_spec.js new file mode 100644 index 00000000000..05ecec8dc36 --- /dev/null +++ b/test/spec/modules/id5IdSystem_spec.js @@ -0,0 +1,383 @@ +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: 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).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 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).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 decodedObject = { 'id5id': ID5_STORED_ID }; + + it('should properly decode from a stored object', function() { + expect(id5IdSubmodule.decode(ID5_STORED_OBJ)).to.deep.equal(decodedObject); + }); + it('should properly decode from a legacy stored object', function() { + expect(id5IdSubmodule.decode(ID5_LEGACY_STORED_OBJ)).to.deep.equal(decodedObject); + }); + 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..0d539d5988c --- /dev/null +++ b/test/spec/modules/identityLinkIdSystem_spec.js @@ -0,0 +1,91 @@ +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 call the LiveRamp envelope endpoint with consent string', 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 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/imonomyBidAdapter_spec.js b/test/spec/modules/imonomyBidAdapter_spec.js index 91b907186c2..45b3bed6e77 100644 --- a/test/spec/modules/imonomyBidAdapter_spec.js +++ b/test/spec/modules/imonomyBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/imonomyBidAdapter'; +import { spec } from 'modules/imonomyBidAdapter.js'; describe('Imonomy Adapter Tests', function () { const bidsRequest = [ diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js index 15b7e2ff3e8..5a20944a6ed 100644 --- a/test/spec/modules/improvedigitalBidAdapter_spec.js +++ b/test/spec/modules/improvedigitalBidAdapter_spec.js @@ -1,10 +1,10 @@ import { expect } from 'chai'; -import { ImproveDigitalAdServerJSClient, spec } from 'modules/improvedigitalBidAdapter'; -import { config } from 'src/config'; -import { userSync } from 'src/userSync'; +import { ImproveDigitalAdServerJSClient, spec } from 'modules/improvedigitalBidAdapter.js'; +import { config } from 'src/config.js'; +import * as utils from 'src/utils.js'; describe('Improve Digital Adapter Tests', function () { - let idClient = new ImproveDigitalAdServerJSClient('hb'); + const idClient = new ImproveDigitalAdServerJSClient('hb'); const METHOD = 'GET'; const URL = 'https://ice.360yield.com/hb'; @@ -20,9 +20,41 @@ describe('Improve Digital Adapter Tests', function () { bidId: '33e9500b21129f', bidderRequestId: '2772c1e566670b', auctionId: '192721e36a0239', + mediaTypes: { + banner: { + sizes: [[300, 250], [160, 600], ['blah', 150], [-1, 300], [300, -5]] + } + }, sizes: [[300, 250], [160, 600], ['blah', 150], [-1, 300], [300, -5]] }; + const instreamBidRequest = utils.deepClone(simpleBidRequest); + instreamBidRequest.mediaTypes = { + video: { + context: 'instream', + playerSize: [640, 480] + } + }; + + const outstreamBidRequest = utils.deepClone(simpleBidRequest); + outstreamBidRequest.mediaTypes = { + video: { + context: 'outstream', + playerSize: [640, 480] + } + }; + + const multiFormatBidRequest = utils.deepClone(simpleBidRequest); + multiFormatBidRequest.mediaTypes = { + banner: { + sizes: [[300, 250], [160, 600], ['blah', 150], [-1, 300], [300, -5]] + }, + video: { + context: 'outstream', + playerSize: [640, 480] + } + }; + const simpleSmartTagBidRequest = { bidder: 'improvedigital', bidId: '1a2b3c', @@ -33,7 +65,24 @@ describe('Improve Digital Adapter Tests', function () { } }; + const bidderRequest = { + bids: [simpleBidRequest] + }; + + const instreamBidderRequest = { + bids: [instreamBidRequest] + }; + + const outstreamBidderRequest = { + bids: [outstreamBidRequest] + }; + + const multiFormatBidderRequest = { + bids: [multiFormatBidRequest] + }; + const bidderRequestGdpr = { + bids: [simpleBidRequest], gdprConsent: { consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', vendorData: {}, @@ -42,6 +91,7 @@ describe('Improve Digital Adapter Tests', function () { }; const bidderRequestReferrer = { + bids: [simpleBidRequest], refererInfo: { referer: 'https://blah.com/test.html', }, @@ -53,12 +103,12 @@ describe('Improve Digital Adapter Tests', function () { }); it('should return false when no bid.params', function () { - let bid = {}; + const bid = {}; expect(spec.isBidRequestValid(bid)).to.equal(false); }); it('should return false when both placementId and placementKey + publisherId are missing', function () { - let bid = { 'params': {} }; + const bid = { 'params': {} }; expect(spec.isBidRequestValid(bid)).to.equal(false); }); @@ -78,31 +128,59 @@ describe('Improve Digital Adapter Tests', function () { }); it('should return true when placementId is passed', function () { - let bid = { 'params': {} }; expect(spec.isBidRequestValid(simpleBidRequest)).to.equal(true); }); it('should return true when both placementKey and publisherId are passed', function () { - let bid = { 'params': {} }; expect(spec.isBidRequestValid(simpleSmartTagBidRequest)).to.equal(true); }); }); describe('buildRequests', function () { it('should make a well-formed request objects', function () { - const requests = spec.buildRequests([simpleBidRequest]); + const requests = spec.buildRequests([simpleBidRequest], bidderRequest); expect(requests).to.be.an('array'); expect(requests.length).to.equal(1); const request = requests[0]; expect(request.method).to.equal(METHOD); expect(request.url).to.equal(URL); + expect(request.bidderRequest).to.deep.equal(bidderRequest); expect(request.data.substring(0, PARAM_PREFIX.length)).to.equal(PARAM_PREFIX); const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); expect(params.bid_request).to.be.an('object'); expect(params.bid_request.id).to.be.a('string'); expect(params.bid_request.version).to.equal(`${spec.version}-${idClient.CONSTANTS.CLIENT_VERSION}`); + expect(params.bid_request.gdpr).to.not.exist; + expect(params.bid_request.us_privacy).to.not.exist; + expect(params.bid_request.imp).to.deep.equal([ + { + id: '33e9500b21129f', + pid: 1053688, + tid: 'f183e871-fbed-45f0-a427-c8a63c4c01eb', + banner: {} + } + ]); + }); + + it('should make a well-formed request object for multi-format ad unit', function () { + const requests = spec.buildRequests([multiFormatBidRequest], multiFormatBidderRequest); + expect(requests).to.be.an('array'); + expect(requests.length).to.equal(1); + + const request = requests[0]; + expect(request.method).to.equal(METHOD); + expect(request.url).to.equal(URL); + expect(request.bidderRequest).to.deep.equal(multiFormatBidderRequest); + expect(request.data.substring(0, PARAM_PREFIX.length)).to.equal(PARAM_PREFIX); + + const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); + expect(params.bid_request).to.be.an('object'); + expect(params.bid_request.id).to.be.a('string'); + expect(params.bid_request.version).to.equal(`${spec.version}-${idClient.CONSTANTS.CLIENT_VERSION}`); + expect(params.bid_request.gdpr).to.not.exist; + expect(params.bid_request.us_privacy).to.not.exist; expect(params.bid_request.imp).to.deep.equal([ { id: '33e9500b21129f', @@ -114,33 +192,33 @@ describe('Improve Digital Adapter Tests', function () { }); it('should set placementKey and publisherId for smart tags', function () { - const requests = spec.buildRequests([simpleSmartTagBidRequest]); + const requests = spec.buildRequests([simpleSmartTagBidRequest], bidderRequest); const params = JSON.parse(decodeURIComponent(requests[0].data.substring(PARAM_PREFIX.length))); expect(params.bid_request.imp[0].pubid).to.equal(1032); expect(params.bid_request.imp[0].pkey).to.equal('data_team_test_hb_smoke_test'); }); it('should add keyValues', function () { - let bidRequest = Object.assign({}, simpleBidRequest); + const bidRequest = Object.assign({}, simpleBidRequest); const keyValues = { testKey: [ 'testValue' ] }; bidRequest.params.keyValues = keyValues; - const request = spec.buildRequests([bidRequest])[0]; + const request = spec.buildRequests([bidRequest], bidderRequest)[0]; const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); expect(params.bid_request.imp[0].kvw).to.deep.equal(keyValues); }); it('should add single size filter', function () { - let bidRequest = Object.assign({}, simpleBidRequest); + const bidRequest = Object.assign({}, simpleBidRequest); const size = { w: 800, h: 600 }; bidRequest.params.size = size; - const request = spec.buildRequests([bidRequest])[0]; + const request = spec.buildRequests([bidRequest], bidderRequest)[0]; const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); expect(params.bid_request.imp[0].banner).to.deep.equal(size); // When single size filter is set, format shouldn't be populated. This @@ -151,7 +229,7 @@ describe('Improve Digital Adapter Tests', function () { it('should add currency', function () { const bidRequest = Object.assign({}, simpleBidRequest); const getConfigStub = sinon.stub(config, 'getConfig').returns('JPY'); - const request = spec.buildRequests([bidRequest])[0]; + const request = spec.buildRequests([bidRequest], bidderRequest)[0]; const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); expect(params.bid_request.imp[0].currency).to.equal('JPY'); getConfigStub.restore(); @@ -159,14 +237,14 @@ describe('Improve Digital Adapter Tests', function () { it('should add bid floor', function () { const bidRequest = Object.assign({}, simpleBidRequest); - let request = spec.buildRequests([bidRequest])[0]; + let request = spec.buildRequests([bidRequest], bidderRequest)[0]; let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); // Floor price currency shouldn't be populated without a floor price expect(params.bid_request.imp[0].bidfloorcur).to.not.exist; // Default floor price currency bidRequest.params.bidFloor = 0.05; - request = spec.buildRequests([bidRequest])[0]; + request = spec.buildRequests([bidRequest], bidderRequest)[0]; params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); expect(params.bid_request.imp[0].bidfloor).to.equal(0.05); expect(params.bid_request.imp[0].bidfloorcur).to.equal('USD'); @@ -186,6 +264,13 @@ describe('Improve Digital Adapter Tests', function () { expect(params.bid_request.gdpr).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A=='); }); + it('should add CCPA consent string', function () { + const bidRequest = Object.assign({}, simpleBidRequest); + const request = spec.buildRequests([bidRequest], { uspConsent: '1YYY' })[0]; + const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); + expect(params.bid_request.us_privacy).to.equal('1YYY'); + }); + it('should add referrer', function () { const bidRequest = Object.assign({}, simpleBidRequest); const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0]; @@ -196,7 +281,7 @@ describe('Improve Digital Adapter Tests', function () { it('should add ad type for instream video', function () { let bidRequest = Object.assign({}, simpleBidRequest); bidRequest.mediaType = 'video'; - let request = spec.buildRequests([bidRequest])[0]; + let request = spec.buildRequests([bidRequest], bidderRequest)[0]; let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); expect(params.bid_request.imp[0].ad_types).to.deep.equal(['video']); @@ -207,38 +292,48 @@ describe('Improve Digital Adapter Tests', function () { playerSize: [640, 480] } }; - request = spec.buildRequests([bidRequest])[0]; + request = spec.buildRequests([bidRequest], bidderRequest)[0]; params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); expect(params.bid_request.imp[0].ad_types).to.deep.equal(['video']); }); + it('should not set ad type for outstream video', function() { + const request = spec.buildRequests([outstreamBidRequest])[0]; + const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); + expect(params.bid_request.imp[0].ad_types).to.not.exist; + }); + + it('should not set ad type for multi-format bids', function() { + const request = spec.buildRequests([multiFormatBidRequest], bidderRequest)[0]; + const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); + expect(params.bid_request.imp[0].ad_types).to.not.exist; + }); + it('should not set Prebid sizes in bid request for instream video', function () { const getConfigStub = sinon.stub(config, 'getConfig'); getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true); - const bidRequest = Object.assign({}, simpleBidRequest); - bidRequest.mediaTypes = { - video: { - context: 'instream', - playerSize: [640, 480] - } - }; - const request = spec.buildRequests([bidRequest])[0]; + const request = spec.buildRequests([instreamBidRequest], bidderRequest)[0]; const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); expect(params.bid_request.imp[0].banner.format).to.not.exist; getConfigStub.restore(); }); - it('should not set ad type for outstream video', function() { - const bidRequest = Object.assign({}, simpleBidRequest); - bidRequest.mediaTypes = { - video: { - context: 'outstream', - playerSize: [640, 480] - } - }; - const request = spec.buildRequests([bidRequest])[0]; + it('should not set Prebid sizes in bid request for outstream video', function () { + const getConfigStub = sinon.stub(config, 'getConfig'); + getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true); + const request = spec.buildRequests([outstreamBidRequest], bidderRequest)[0]; const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); - expect(params.bid_request.imp[0].ad_types).to.not.exist; + expect(params.bid_request.imp[0].banner.format).to.not.exist; + getConfigStub.restore(); + }); + + it('should not set Prebid sizes in multi-format bid request', function () { + const getConfigStub = sinon.stub(config, 'getConfig'); + getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true); + const request = spec.buildRequests([multiFormatBidRequest], bidderRequest)[0]; + const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); + expect(params.bid_request.imp[0].banner.format).to.not.exist; + getConfigStub.restore(); }); it('should add schain', function () { @@ -254,9 +349,11 @@ describe('Improve Digital Adapter Tests', function () { const requests = spec.buildRequests([ simpleBidRequest, simpleSmartTagBidRequest - ]); + ], bidderRequest); expect(requests).to.be.an('array'); expect(requests.length).to.equal(2); + expect(requests[0].bidderRequest).to.deep.equal(bidderRequest); + expect(requests[1].bidderRequest).to.deep.equal(bidderRequest); }); it('should return one request in a single request mode', function () { @@ -265,7 +362,7 @@ describe('Improve Digital Adapter Tests', function () { const requests = spec.buildRequests([ simpleBidRequest, simpleSmartTagBidRequest - ]); + ], bidderRequest); expect(requests).to.be.an('array'); expect(requests.length).to.equal(1); getConfigStub.restore(); @@ -274,7 +371,7 @@ describe('Improve Digital Adapter Tests', function () { it('should set Prebid sizes in bid request', function () { const getConfigStub = sinon.stub(config, 'getConfig'); getConfigStub.withArgs('improvedigital.usePrebidSizes').returns(true); - const request = spec.buildRequests([simpleBidRequest])[0]; + const request = spec.buildRequests([simpleBidRequest], bidderRequest)[0]; const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); expect(params.bid_request.imp[0].banner).to.deep.equal({ format: [ @@ -294,7 +391,7 @@ describe('Improve Digital Adapter Tests', function () { h: 600 }; bidRequest.params.size = size; - const request = spec.buildRequests([bidRequest])[0]; + const request = spec.buildRequests([bidRequest], bidderRequest)[0]; const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length))); expect(params.bid_request.imp[0].banner).to.deep.equal({ format: [ @@ -546,7 +643,7 @@ describe('Improve Digital Adapter Tests', function () { ]; describe('interpretResponse', function () { - let expectedBid = [ + const expectedBid = [ { 'ad': '', 'adId': '33e9500b21129f', @@ -562,7 +659,7 @@ describe('Improve Digital Adapter Tests', function () { } ]; - let expectedTwoBids = [ + const expectedTwoBids = [ expectedBid[0], { 'ad': '', @@ -579,7 +676,7 @@ describe('Improve Digital Adapter Tests', function () { } ]; - let expectedBidNative = [ + const expectedBidNative = [ { mediaType: 'native', adId: '33e9500b21129f', @@ -628,7 +725,7 @@ describe('Improve Digital Adapter Tests', function () { } ]; - let expectedBidVideo = [ + const expectedBidInstreamVideo = [ { 'vastXml': '', 'adId': '33e9500b21129f', @@ -644,60 +741,77 @@ describe('Improve Digital Adapter Tests', function () { } ]; - it('should return a well-formed bid', function () { - const bids = spec.interpretResponse(serverResponse); + const expectedBidOutstreamVideo = utils.deepClone(expectedBidInstreamVideo); + expectedBidOutstreamVideo[0].adResponse = { + content: expectedBidOutstreamVideo[0].vastXml, + height: expectedBidOutstreamVideo[0].height, + width: expectedBidOutstreamVideo[0].width + }; + + it('should return a well-formed display bid', function () { + const bids = spec.interpretResponse(serverResponse, {bidderRequest}); + expect(bids).to.deep.equal(expectedBid); + }); + + it('should return a well-formed display bid for multi-format ad unit', function () { + const bids = spec.interpretResponse(serverResponse, {bidderRequest: multiFormatBidderRequest}); expect(bids).to.deep.equal(expectedBid); }); it('should return two bids', function () { - const bids = spec.interpretResponse(serverResponseTwoBids); + const bids = spec.interpretResponse(serverResponseTwoBids, {bidderRequest}); expect(bids).to.deep.equal(expectedTwoBids); }); it('should set dealId correctly', function () { - let response = JSON.parse(JSON.stringify(serverResponse)); + const response = JSON.parse(JSON.stringify(serverResponse)); let bids; delete response.body.bid[0].lid; response.body.bid[0].buying_type = 'deal_id'; - bids = spec.interpretResponse(response); + bids = spec.interpretResponse(response, {bidderRequest}); expect(bids[0].dealId).to.not.exist; response.body.bid[0].lid = 268515; delete response.body.bid[0].buying_type; - bids = spec.interpretResponse(response); + 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); + 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); + bids = spec.interpretResponse(response, {bidderRequest}); expect(bids[0].dealId).to.equal(268515); response.body.bid[0].lid = [ 268515, 12456, 34567 ]; response.body.bid[0].buying_type = 'deal_id'; - bids = spec.interpretResponse(response); + bids = spec.interpretResponse(response, {bidderRequest}); expect(bids[0].dealId).to.not.exist; response.body.bid[0].lid = [ 268515, 12456, 34567 ]; response.body.bid[0].buying_type = [ 'deal_id', 'classic' ]; - bids = spec.interpretResponse(response); + bids = spec.interpretResponse(response, {bidderRequest}); 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' ]; - bids = spec.interpretResponse(response); + response.body.bid[0].buying_type = [ 'rtb', 'deal_id', 'deal_id' ]; + bids = spec.interpretResponse(response, {bidderRequest}); expect(bids[0].dealId).to.equal(12456); }); it('should set currency', function () { - let response = JSON.parse(JSON.stringify(serverResponse)); + const response = JSON.parse(JSON.stringify(serverResponse)); response.body.bid[0].currency = 'eur'; - const bids = spec.interpretResponse(response); + const bids = spec.interpretResponse(response, {bidderRequest}); expect(bids[0].currency).to.equal('EUR'); }); @@ -707,41 +821,41 @@ describe('Improve Digital Adapter Tests', function () { // Price missing or 0 response.body.bid[0].price = 0; - bids = spec.interpretResponse(response); + bids = spec.interpretResponse(response, {bidderRequest}); expect(bids).to.deep.equal([]); delete response.body.bid[0].price; - bids = spec.interpretResponse(response); + bids = spec.interpretResponse(response, {bidderRequest}); expect(bids).to.deep.equal([]); response.body.bid[0].price = null; - bids = spec.interpretResponse(response); + bids = spec.interpretResponse(response, {bidderRequest}); expect(bids).to.deep.equal([]); // errorCode present response = JSON.parse(JSON.stringify(serverResponse)); response.body.bid[0].errorCode = undefined; - bids = spec.interpretResponse(response); + bids = spec.interpretResponse(response, {bidderRequest}); expect(bids).to.deep.equal([]); // adm and native missing response = JSON.parse(JSON.stringify(serverResponse)); delete response.body.bid[0].adm; - bids = spec.interpretResponse(response); + bids = spec.interpretResponse(response, {bidderRequest}); expect(bids).to.deep.equal([]); response.body.bid[0].adm = null; - bids = spec.interpretResponse(response); + bids = spec.interpretResponse(response, {bidderRequest}); expect(bids).to.deep.equal([]); }); it('should set netRevenue', function () { - let response = JSON.parse(JSON.stringify(serverResponse)); + const response = JSON.parse(JSON.stringify(serverResponse)); response.body.bid[0].isNet = true; - const bids = spec.interpretResponse(response); + const bids = spec.interpretResponse(response, {bidderRequest}); expect(bids[0].netRevenue).to.equal(true); }); // Native ads it('should return a well-formed native ad bid', function () { - let bids = spec.interpretResponse(serverResponseNative); + let bids = spec.interpretResponse(serverResponseNative, {bidderRequest}); expect(bids[0].ortbNative).to.deep.equal(serverResponseNative.body.bid[0].native); delete bids[0].ortbNative; expect(bids).to.deep.equal(expectedBidNative); @@ -755,15 +869,29 @@ describe('Improve Digital Adapter Tests', function () { 'https://www.mytracker.com/imptracker' ]; expectedBids[0].native.javascriptTrackers = ''; - bids = spec.interpretResponse(response); + bids = spec.interpretResponse(response, {bidderRequest}); delete bids[0].ortbNative; expect(bids).to.deep.equal(expectedBids); }); // Video - it('should return a well-formed video bid', function () { - const bids = spec.interpretResponse(serverResponseVideo); - expect(bids).to.deep.equal(expectedBidVideo); + it('should return a well-formed instream video bid', function () { + const bids = spec.interpretResponse(serverResponseVideo, {bidderRequest: instreamBidderRequest}); + expect(bids).to.deep.equal(expectedBidInstreamVideo); + }); + + it('should return a well-formed outstream video bid', function () { + const bids = spec.interpretResponse(serverResponseVideo, {bidderRequest: outstreamBidderRequest}); + expect(bids[0].renderer).to.exist; + delete (bids[0].renderer); + expect(bids).to.deep.equal(expectedBidOutstreamVideo); + }); + + it('should return a well-formed outstream video bid for multi-format ad unit', function () { + const bids = spec.interpretResponse(serverResponseVideo, {bidderRequest: multiFormatBidderRequest}); + expect(bids[0].renderer).to.exist; + delete (bids[0].renderer); + expect(bids).to.deep.equal(expectedBidOutstreamVideo); }); }); diff --git a/test/spec/modules/innityBidAdapter_spec.js b/test/spec/modules/innityBidAdapter_spec.js index 653fd762709..80c00252632 100644 --- a/test/spec/modules/innityBidAdapter_spec.js +++ b/test/spec/modules/innityBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/innityBidAdapter'; +import { spec } from 'modules/innityBidAdapter.js'; describe('innityAdapterTest', () => { describe('bidRequestValidity', () => { diff --git a/test/spec/modules/inskinBidAdapter_spec.js b/test/spec/modules/inskinBidAdapter_spec.js new file mode 100644 index 00000000000..e817b3e3b81 --- /dev/null +++ b/test/spec/modules/inskinBidAdapter_spec.js @@ -0,0 +1,376 @@ +import { expect } from 'chai'; +import { spec } from 'modules/inskinBidAdapter.js'; +import { createBid } from 'src/bidfactory.js'; + +const ENDPOINT = 'https://mfad.inskinad.com/api/v2'; + +const REQUEST = { + 'bidderCode': 'inskin', + 'requestId': 'a4713c32-3762-4798-b342-4ab810ca770d', + 'bidderRequestId': '109f2a181342a9', + 'bidRequest': [{ + 'bidder': 'inskin', + 'params': { + 'networkId': 9874, + 'siteId': 730181 + }, + 'placementCode': 'div-gpt-ad-1487778092495-0', + 'sizes': [ + [728, 90], + [970, 90] + ], + 'bidId': '2b0f82502298c9', + 'bidderRequestId': '109f2a181342a9', + 'requestId': 'a4713c32-3762-4798-b342-4ab810ca770d' + }, + { + 'bidder': 'inskin', + 'params': { + 'networkId': 9874, + 'siteId': 730181 + }, + 'placementCode': 'div-gpt-ad-1487778092495-0', + 'sizes': [ + [728, 90], + [970, 90] + ], + 'bidId': '123', + 'bidderRequestId': '109f2a181342a9', + 'requestId': 'a4713c32-3762-4798-b342-4ab810ca770d' + }], + 'start': 1487883186070, + 'auctionStart': 1487883186069, + 'timeout': 3000 +}; + +const RESPONSE = { + 'headers': null, + 'body': { + 'user': { 'key': 'ue1-2d33e91b71e74929b4aeecc23f4376f1' }, + 'decisions': { + '2b0f82502298c9': { + 'adId': 2364764, + 'creativeId': 1950991, + 'flightId': 2788300, + 'campaignId': 542982, + 'clickUrl': 'https://mfad.inskinad.com/r', + 'impressionUrl': 'https://mfad.inskinad.com/i.gif', + 'contents': [{ + 'type': 'html', + 'body': '', + 'data': { + 'height': 90, + 'width': 728, + 'imageUrl': 'https://static.adzerk.net/Advertisers/b0ab77db8a7848c8b78931aed022a5ef.gif', + 'fileName': 'b0ab77db8a7848c8b78931aed022a5ef.gif' + }, + 'template': 'image' + }], + 'height': 90, + 'width': 728, + 'events': [], + 'pricing': {'price': 0.5, 'clearPrice': 0.5, 'revenue': 0.0005, 'rateType': 2, 'eCPM': 0.5} + }, + '123': { + 'adId': 2364764, + 'creativeId': 1950991, + 'flightId': 2788300, + 'campaignId': 542982, + 'clickUrl': 'https://mfad.inskinad.com/r', + 'impressionUrl': 'https://mfad.inskinad.com/i.gif', + 'contents': [{ + 'type': 'html', + 'body': '', + 'data': { + 'customData': { + 'pubCPM': 1 + }, + 'height': 90, + 'width': 728, + 'imageUrl': 'https://static.adzerk.net/Advertisers/b0ab77db8a7848c8b78931aed022a5ef.gif', + 'fileName': 'b0ab77db8a7848c8b78931aed022a5ef.gif' + }, + 'template': 'image' + }], + 'height': 90, + 'width': 728, + 'events': [], + 'pricing': {'price': 0.5, 'clearPrice': 0.5, 'revenue': 0.0005, 'rateType': 2, 'eCPM': 0.5} + } + } + } +}; + +const consentString = 'BOJ8RZsOJ8RZsABAB8AAAAAZ+A=='; +const bidderRequest = { + bidderCode: 'inskin', + gdprConsent: { + consentString: consentString, + gdprApplies: true + }, + refererInfo: { + referer: 'https://www.inskinmedia.com' + } +}; + +describe('InSkin BidAdapter', function () { + let bidRequests; + let adapter = spec; + + beforeEach(function () { + bidRequests = [ + { + bidder: 'inskin', + params: { + networkId: '9874', + siteId: 'xxxxx' + }, + placementCode: 'header-bid-tag-1', + sizes: [[300, 250], [300, 600]], + bidId: '23acc48ad47af5', + requestId: '0fb4905b-9456-4152-86be-c6f6d259ba99', + bidderRequestId: '1c56ad30b9b8ca8', + transactionId: '92489f71-1bf2-49a0-adf9-000cea934729' + } + ]; + }); + + describe('bid request validation', function () { + it('should accept valid bid requests', function () { + let bid = { + bidder: 'inskin', + params: { + networkId: '9874', + siteId: 'xxxxx' + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should accept valid bid requests with extra fields', function () { + let bid = { + bidder: 'inskin', + params: { + networkId: '9874', + siteId: 'xxxxx', + zoneId: 'xxxxx' + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should reject bid requests without siteId', function () { + let bid = { + bidder: 'inskin', + params: { + networkId: '9874' + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should reject bid requests without networkId', function () { + let bid = { + bidder: 'inskin', + params: { + siteId: '9874' + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests validation', function () { + it('creates request data', function () { + let request = spec.buildRequests(bidRequests, bidderRequest); + + expect(request).to.exist.and.to.be.a('object'); + }); + + it('request to inskin should contain a url', function () { + let request = spec.buildRequests(bidRequests, bidderRequest); + + expect(request.url).to.have.string('inskinad.com'); + }); + + it('requires valid bids to make request', function () { + let request = spec.buildRequests([], bidderRequest); + expect(request.bidRequest).to.be.empty; + }); + + it('sends bid request to ENDPOINT via POST', function () { + let request = spec.buildRequests(bidRequests, bidderRequest); + + expect(request.method).to.have.string('POST'); + }); + + it('should add gdpr consent information to the request', function () { + bidderRequest.bids = bidRequests; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.consent.gdprConsentString).to.exist; + expect(payload.consent.gdprConsentRequired).to.exist; + 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 () { + let bidRequest = spec.buildRequests(REQUEST.bidRequest, bidderRequest); + let bid = createBid(1, bidRequest.bidRequest[0]); + + expect(bid.bidderCode).to.equal('inskin'); + }); + + it('response should include objects for all bids', function () { + let bids = spec.interpretResponse(RESPONSE, REQUEST); + + expect(bids.length).to.equal(2); + }); + + it('registers bids', function () { + let bids = spec.interpretResponse(RESPONSE, REQUEST); + bids.forEach(b => { + expect(b).to.have.property('cpm'); + expect(b.cpm).to.be.above(0); + expect(b).to.have.property('requestId'); + expect(b).to.have.property('cpm'); + expect(b).to.have.property('width'); + expect(b).to.have.property('height'); + expect(b).to.have.property('ad'); + expect(b).to.have.property('currency', 'USD'); + expect(b).to.have.property('creativeId'); + expect(b).to.have.property('ttl', 360); + expect(b).to.have.property('netRevenue', true); + }); + }); + + it('cpm is correctly set', function () { + let bids = spec.interpretResponse(RESPONSE, REQUEST); + + expect(bids[0].cpm).to.equal(0.5); + expect(bids[1].cpm).to.equal(1); + }); + + it('handles nobid responses', function () { + let EMPTY_RESP = Object.assign({}, RESPONSE, {'body': {'decisions': null}}) + let bids = spec.interpretResponse(EMPTY_RESP, REQUEST); + + expect(bids).to.be.empty; + }); + + it('handles no server response', function () { + let bids = spec.interpretResponse(null, REQUEST); + + expect(bids).to.be.empty; + }); + }); + describe('getUserSyncs', function () { + it('handles empty sync options', function () { + let opts = spec.getUserSyncs({}); + + expect(opts).to.be.empty; + }); + + it('should return two sync urls if pixel syncs are enabled', function () { + let syncOptions = {'pixelEnabled': true}; + let opts = spec.getUserSyncs(syncOptions); + + expect(opts.length).to.equal(2); + }); + + it('should return three sync urls if pixel and iframe syncs are enabled', function () { + let syncOptions = {'iframeEnabled': true, 'pixelEnabled': true}; + let opts = spec.getUserSyncs(syncOptions); + + expect(opts.length).to.equal(3); + }); + }); +}); diff --git a/test/spec/modules/invibesBidAdapter_spec.js b/test/spec/modules/invibesBidAdapter_spec.js index 3ca31c0abb4..b75c6a4578f 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'; +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; @@ -137,37 +138,37 @@ describe('invibesBidAdapter:', function () { it('has capped ids if local storage variable is correctly formatted', function () { 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 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; }); @@ -191,65 +192,401 @@ describe('invibesBidAdapter:', function () { 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 } } } }; + let bidderRequest = {gdprConsent: {vendorData: {vendorConsents: {436: true}}}}; let request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data.lId).to.not.exist; }); it('try to graduate but not old enough - doesnt send the domain id', function () { - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } }; + let bidderRequest = {gdprConsent: {vendorData: {vendorConsents: {436: true}}}}; global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":' + Date.now() + ',"hc":5}'; let request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data.lId).to.not.exist; }); it('graduate and send the domain id', function () { - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } }; - stubDomainOptions(new StubbedPersistence('{"id":"dvdjkams6nkq","cr":1521818537626,"hc":7}')); + let bidderRequest = {gdprConsent: {vendorData: {vendorConsents: {436: true}}}}; + stubDomainOptions(new StubbedPersistence('{"id":"dvdjkams6nkq","cr":1521818537626,"hc":7}')); let request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data.lId).to.exist; }); it('send the domain id if already graduated', function () { - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: true } } } }; - stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi"}')); + let bidderRequest = {gdprConsent: {vendorData: {vendorConsents: {436: true}}}}; + stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi"}')); let request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data.lId).to.exist; expect(top.window.invibes.dom.tempId).to.exist; }); 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"}')); + let bidderRequest = {gdprConsent: {vendorData: {vendorConsents: {436: true}}}}; + stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}')); let request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data.lId).to.exist; expect(top.window.invibes.dom.tempId).to.exist; }); - it('dont send the domain id if consent declined', function () { - let bidderRequest = { gdprConsent: { vendorData: { vendorConsents: { 436: false } } } }; + it('dont send the domain id if consent declined on tcf v1', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendorConsents: {436: false} + } + } + }; + stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}')); + 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(0); + }); + + it('dont send the domain id if consent declined on tcf v2', function () { + let bidderRequest = { + gdprConsent: { + vendorData: { + gdprApplies: true, + hasGlobalConsent: false, + vendor: {consents: {436: false}} + } + } + }; stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}')); 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(0); }); it('dont send the domain id if no consent', function () { - let bidderRequest = { }; - stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}')); + let bidderRequest = {}; + stubDomainOptions(new StubbedPersistence('{"id":"f8zoh044p9oi.8537626"}')); let request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data.lId).to.not.exist; expect(top.window.invibes.dom.tempId).to.not.exist; }); 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 } } } }; + let bidderRequest = {gdprConsent: {vendorData: {vendorConsents: {436: true}}}}; global.document.cookie = 'ivbsdid={"id":"dvdjkams6nkq","cr":1521818537626,"hc":0}'; 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; }); + + it('should send oi = 0 when vendorData is null', function () { + let bidderRequest = { + gdprConsent: { + vendorData: null + } + }; + let request = spec.buildRequests(bidRequests, bidderRequest); + 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('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.oi).to.equal(0); + }); + + it('should send oi = 0 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(0); + }); + + it('should send oi = 0 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(0); + }); + + 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('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.oi).to.equal(2); + }); + + it('should send oi = 0 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.oi).to.equal(0); + }); + + it('should send oi = 0 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); + expect(request.data.oi).to.equal(0); + }); + + 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); + }); }); describe('interpretResponse', function () { @@ -285,37 +622,47 @@ 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; }); }); @@ -324,20 +671,20 @@ describe('invibesBidAdapter:', 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 }); + 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 +700,7 @@ 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'); @@ -362,7 +709,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/invisiblyAnalyticsAdapter_spec.js b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js index 8338476f770..e13b16661b0 100644 --- a/test/spec/modules/invisiblyAnalyticsAdapter_spec.js +++ b/test/spec/modules/invisiblyAnalyticsAdapter_spec.js @@ -1,10 +1,11 @@ -import invisiblyAdapter from 'modules/invisiblyAnalyticsAdapter'; +import invisiblyAdapter from 'modules/invisiblyAnalyticsAdapter.js'; import { expect } from 'chai'; -import { server } from 'test/mocks/xhr'; let events = require('src/events'); let constants = require('src/constants.json'); -describe('Invisibly Analytics Adapter test suite', function() { +describe('Invisibly Analytics Adapter test suite', function () { + let xhr; + let requests = []; const BID1 = { width: 980, height: 240, @@ -20,11 +21,11 @@ describe('Invisibly Analytics Adapter test suite', function() { hb_adid: '2ecff0db240757', hb_pb: 1.2, hb_size: '640x480', - hb_source: 'client' + hb_source: 'client', }, getStatusCode() { return CONSTANTS.STATUS.GOOD; - } + }, }; const BID2 = Object.assign({}, BID1, { @@ -34,7 +35,7 @@ describe('Invisibly Analytics Adapter test suite', function() { timeToRespond: 300, bidId: '3ecff0db240757', requestId: '3ecff0db240757', - adId: '3ecff0db240757' + adId: '3ecff0db240757', }); const BID3 = { @@ -48,11 +49,11 @@ describe('Invisibly Analytics Adapter test suite', function() { hb_adid: '3bd4ebb1c900e2', hb_pb: '1.500', hb_size: '728x90', - hb_source: 'server' + hb_source: 'server', }, getStatusCode() { return CONSTANTS.STATUS.NO_BID; - } + }, }; const MOCK = { @@ -60,11 +61,11 @@ describe('Invisibly Analytics Adapter test suite', function() { provider: 'invisiblyAnalytics', options: { bundleId: '', - account: 'invisibly' - } + account: 'invisibly', + }, }, AUCTION_INIT: { - auctionId: '25c6d7f5-699a-4bfc-87c9-996f915341fa' + auctionId: '25c6d7f5-699a-4bfc-87c9-996f915341fa', }, BID_REQUESTED: { bidder: 'mockBidder', @@ -74,27 +75,27 @@ describe('Invisibly Analytics Adapter test suite', function() { { bidder: 'mockBidder', adUnitCode: 'panorama_d_1', - bidId: '2ecff0db240757' + bidId: '2ecff0db240757', }, { bidder: 'mockBidder', adUnitCode: 'box_d_1', - bidId: '3ecff0db240757' + bidId: '3ecff0db240757', }, { bidder: 'mockBidder', adUnitCode: 'box_d_2', - bidId: '4ecff0db240757' - } + bidId: '4ecff0db240757', + }, ], - start: 1519149562216 + start: 1519149562216, }, BID_RESPONSE: [BID1, BID2], AUCTION_END: { auctionId: 'test_timeout_auction_id', timestamp: 1234567890, timeout: 3000, - auctionEnd: 1234567990 + auctionEnd: 1234567990, }, BID_WON: { bidderCode: 'appnexus', @@ -119,17 +120,17 @@ describe('Invisibly Analytics Adapter test suite', function() { status: 'rendered', eventType: 'bidWon', ad: 'some ad', - adUrl: 'ad url' + adUrl: 'ad url', }, BIDDER_DONE: { bidderCode: 'mockBidder', - bids: [BID1, BID2, BID3] + bids: [BID1, BID2, BID3], }, BID_TIMEOUT: [ { bidId: '2ecff0db240757', - auctionId: '25c6d7f5-699a-4bfc-87c9-996f915341fa' - } + auctionId: '25c6d7f5-699a-4bfc-87c9-996f915341fa', + }, ], BID_ADJUSTMENT: { ad: 'html', @@ -146,346 +147,437 @@ describe('Invisibly Analytics Adapter test suite', function() { statusMessage: 'Bid available', timeToRespond: 421, ttl: 300, - width: 300 + width: 300, }, NO_BID: { - testKey: false + testKey: false, }, SET_TARGETING: { [BID1.adUnitCode]: BID1.adserverTargeting, - [BID3.adUnitCode]: BID3.adserverTargeting + [BID3.adUnitCode]: BID3.adserverTargeting, }, REQUEST_BIDS: { - call: 'request' + call: 'request', }, ADD_AD_UNITS: { call: 'addAdUnits' }, AD_RENDER_FAILED: { call: 'adRenderFailed' }, INVALID_EVENT: { - mockKey: 'this event should not emit' - } + mockKey: 'this event should not emit', + }, }; - describe('Invisibly Analytic tests specs', function() { - beforeEach(function() { + describe('Invisibly Analytic tests specs', function () { + beforeEach(function () { + xhr = sinon.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = (xhr) => { + requests.push(xhr); + }; sinon.stub(events, 'getEvents').returns([]); sinon.spy(invisiblyAdapter, 'track'); }); - afterEach(function() { + afterEach(function () { invisiblyAdapter.disableAnalytics(); events.getEvents.restore(); invisiblyAdapter.track.restore(); + xhr.restore(); }); - // specs to test invisibly account input to enableAnaylitcs - describe('monitor enableAnalytics method', function() { - it('should catch all events triggered with invisibly account config', function() { - invisiblyAdapter.enableAnalytics({ - provider: 'invisiblyAnalytics', - options: { - account: 'invisibly' - } + describe('Send all events as & when they are captured', function () { + beforeEach(function () { + invisiblyAdapter.weightedFilter.filter = true; + }); + // specs to test invisibly account input to enableAnaylitcs + describe('monitor enableAnalytics method', function () { + it('should catch all events triggered with invisibly account config', function () { + invisiblyAdapter.enableAnalytics({ + provider: 'invisiblyAnalytics', + options: { + account: 'invisibly', + }, + }); + events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); + events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); + sinon.assert.callCount(invisiblyAdapter.track, 5); + }); + + it('should not catch events triggered without invisibly account config', function () { + invisiblyAdapter.enableAnalytics({ + provider: 'invisiblyAnalytics', + options: {}, + }); + + events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); + events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); + invisiblyAdapter.flush(); + sinon.assert.callCount(invisiblyAdapter.track, 0); + }); + // spec to test custom api endpoint + it('support custom endpoint', function () { + let custom_url = 'custom url'; + invisiblyAdapter.enableAnalytics({ + provider: 'invisiblyAnalytics', + options: { + url: custom_url, + bundleId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', + account: 'invisibly', + }, + }); + expect(invisiblyAdapter.getOptions().url).to.equal(custom_url); }); + }); + // spec for auction init event + it('auction init event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); - events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); - sinon.assert.callCount(invisiblyAdapter.track, 5); + invisiblyAdapter.flush(); + + const invisiblyEvents = JSON.parse( + requests[1].requestBody.substring(0) + ); + // pageView is default event initially hence expecting 2 requests + expect(requests.length).to.equal(2); + expect(requests[1].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.auctionId).to.equal( + MOCK.AUCTION_INIT.auctionId + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_type).to.equal('PREBID_auctionInit'); + expect(invisiblyEvents.event_data.ver).to.equal(1); }); - it('should not catch events triggered without invisibly account config', function() { - invisiblyAdapter.enableAnalytics({ - provider: 'invisiblyAnalytics', - options: {} - }); + // spec for bid adjustment event + it('bid adjustment event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); + events.emit(constants.EVENTS.BID_ADJUSTMENT, MOCK.BID_ADJUSTMENT); + invisiblyAdapter.flush(); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_bidAdjustment'); + expect(invisiblyEvents.event_data.bidders.cpm).to.equal( + MOCK.BID_ADJUSTMENT.cpm + ); + sinon.assert.callCount(invisiblyAdapter.track, 1); + }); + + // spec for bid timeout event + it('bid timeout event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); + events.emit(constants.EVENTS.BID_TIMEOUT, MOCK.BID_TIMEOUT); + invisiblyAdapter.flush(); + + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_bidTimeout'); + expect(invisiblyEvents.event_data.bidders.bidId).to.equal( + MOCK.BID_TIMEOUT.bidId + ); + sinon.assert.callCount(invisiblyAdapter.track, 1); + }); + + // spec for bid requested event + it('bid requested event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); + invisiblyAdapter.flush(); + + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_bidRequested'); + expect(invisiblyEvents.event_data.auctionId).to.equal( + MOCK.BID_REQUESTED.auctionId + ); + sinon.assert.callCount(invisiblyAdapter.track, 1); + }); + + // spec for bid response event + it('bid response event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); + invisiblyAdapter.flush(); + + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_bidResponse'); + expect(invisiblyEvents.event_data.cpm).to.equal(MOCK.BID_REQUESTED.cpm); + sinon.assert.callCount(invisiblyAdapter.track, 1); + }); + + // spec for no bid event + it('no bid event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); + events.emit(constants.EVENTS.NO_BID, MOCK.NO_BID); + invisiblyAdapter.flush(); + + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_noBid'); + expect(invisiblyEvents.event_data.noBid.testKey).to.equal( + MOCK.NO_BID.testKey + ); + sinon.assert.callCount(invisiblyAdapter.track, 1); + }); + + // spec for bid won event + it('bid won event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); invisiblyAdapter.flush(); - sinon.assert.callCount(invisiblyAdapter.track, 0); + + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_bidWon'); + sinon.assert.callCount(invisiblyAdapter.track, 1); }); - // spec to test custom api endpoint - it('support custom endpoint', function() { - let custom_url = 'custom url'; - invisiblyAdapter.enableAnalytics({ - provider: 'invisiblyAnalytics', - options: { - url: custom_url, - bundleId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', - account: 'invisibly' - } - }); - expect(invisiblyAdapter.getOptions().url).to.equal(custom_url); + + // spec for bidder done event + it('bidder done event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); + events.emit(constants.EVENTS.BIDDER_DONE, MOCK.BIDDER_DONE); + invisiblyAdapter.flush(); + + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_bidderDone'); + expect(invisiblyEvents.event_data.bidderCode).to.equal( + MOCK.BIDDER_DONE.bidderCode + ); + expect(invisiblyEvents.event_data.bids.length).to.equal( + MOCK.BIDDER_DONE.bids.length + ); + sinon.assert.callCount(invisiblyAdapter.track, 1); }); - }); - // spec for auction init event - it('auction init event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[1].requestBody.substring(0)); - // pageView is default event initially hence expecting 2 requests - expect(server.requests.length).to.equal(2); - expect(server.requests[1].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.auctionId).to.equal( - MOCK.AUCTION_INIT.auctionId - ); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_type).to.equal('PREBID_auctionInit'); - expect(invisiblyEvents.event_data.ver).to.equal(1); - }); + // spec for set targeting event + it('set targeting event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); + events.emit(constants.EVENTS.SET_TARGETING, MOCK.SET_TARGETING); + invisiblyAdapter.flush(); - // spec for bid adjustment event - it('bid adjustment event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BID_ADJUSTMENT, MOCK.BID_ADJUSTMENT); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_bidAdjustment'); - expect(invisiblyEvents.event_data.bidders.cpm).to.equal( - MOCK.BID_ADJUSTMENT.cpm - ); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_setTargeting'); + expect( + invisiblyEvents.event_data.targetings[BID1.adUnitCode] + ).to.deep.equal(BID1.adserverTargeting); + expect( + invisiblyEvents.event_data.targetings[BID3.adUnitCode] + ).to.deep.equal(BID3.adserverTargeting); + sinon.assert.callCount(invisiblyAdapter.track, 1); + }); - // spec for bid timeout event - it('bid timeout event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BID_TIMEOUT, MOCK.BID_TIMEOUT); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_bidTimeout'); - expect(invisiblyEvents.event_data.bidders.bidId).to.equal( - MOCK.BID_TIMEOUT.bidId - ); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + // spec for request bids event + it('request bids event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); + events.emit(constants.EVENTS.REQUEST_BIDS, MOCK.REQUEST_BIDS); + invisiblyAdapter.flush(); - // spec for bid requested event - it('bid requested event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_bidRequested'); - expect(invisiblyEvents.event_data.auctionId).to.equal( - MOCK.BID_REQUESTED.auctionId - ); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_requestBids'); + expect(invisiblyEvents.event_data.call).to.equal( + MOCK.REQUEST_BIDS.call + ); + sinon.assert.callCount(invisiblyAdapter.track, 1); + }); - // spec for bid response event - it('bid response event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_bidResponse'); - expect(invisiblyEvents.event_data.cpm).to.equal(MOCK.BID_REQUESTED.cpm); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + // spec for add ad units event + it('add ad units event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); + events.emit(constants.EVENTS.ADD_AD_UNITS, MOCK.ADD_AD_UNITS); + invisiblyAdapter.flush(); - // spec for no bid event - it('no bid event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.NO_BID, MOCK.NO_BID); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_noBid'); - expect(invisiblyEvents.event_data.noBid.testKey).to.equal( - MOCK.NO_BID.testKey - ); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_addAdUnits'); + expect(invisiblyEvents.event_data.call).to.equal( + MOCK.ADD_AD_UNITS.call + ); + sinon.assert.callCount(invisiblyAdapter.track, 1); + }); - // spec for bid won event - it('bid won event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_bidWon'); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + // spec for ad render failed event + it('ad render failed event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); + events.emit(constants.EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED); + invisiblyAdapter.flush(); - // spec for bidder done event - it('bidder done event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.BIDDER_DONE, MOCK.BIDDER_DONE); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_bidderDone'); - expect(invisiblyEvents.event_data.bidderCode).to.equal( - MOCK.BIDDER_DONE.bidderCode - ); - expect(invisiblyEvents.event_data.bids.length).to.equal( - MOCK.BIDDER_DONE.bids.length - ); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_adRenderFailed'); + expect(invisiblyEvents.event_data.call).to.equal( + MOCK.AD_RENDER_FAILED.call + ); + sinon.assert.callCount(invisiblyAdapter.track, 1); + }); - // spec for set targeting event - it('set targeting event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.SET_TARGETING, MOCK.SET_TARGETING); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_setTargeting'); - expect( - invisiblyEvents.event_data.targetings[BID1.adUnitCode] - ).to.deep.equal(BID1.adserverTargeting); - expect( - invisiblyEvents.event_data.targetings[BID3.adUnitCode] - ).to.deep.equal(BID3.adserverTargeting); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + // spec for auction end event + it('auction end event', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); + events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); + invisiblyAdapter.flush(); - // spec for request bids event - it('request bids event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.REQUEST_BIDS, MOCK.REQUEST_BIDS); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_requestBids'); - expect(invisiblyEvents.event_data.call).to.equal(MOCK.REQUEST_BIDS.call); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + const invisiblyEvents = JSON.parse( + requests[0].requestBody.substring(0) + ); + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal( + 'https://api.pymx5.com/v1/sites/events' + ); + expect(invisiblyEvents.event_data.pageViewId).to.exist; + expect(invisiblyEvents.event_data.ver).to.equal(1); + expect(invisiblyEvents.event_type).to.equal('PREBID_auctionEnd'); + expect(invisiblyEvents.event_data.auctionId).to.equal( + MOCK.AUCTION_END.auctionId + ); + sinon.assert.callCount(invisiblyAdapter.track, 1); + }); - // spec for add ad units event - it('add ad units event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.ADD_AD_UNITS, MOCK.ADD_AD_UNITS); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_addAdUnits'); - expect(invisiblyEvents.event_data.call).to.equal(MOCK.ADD_AD_UNITS.call); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + // should not call sendEvent for events not supported by the adapter + it('it should not call sendEvent for this event emit', function () { + sinon.spy(invisiblyAdapter, 'sendEvent'); + invisiblyAdapter.enableAnalytics(MOCK.config); + events.emit(constants.EVENTS.INVALID_EVENT, MOCK.INVALID_EVENT); + invisiblyAdapter.flush(); - // spec for ad render failed event - it('ad render failed event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_adRenderFailed'); - expect(invisiblyEvents.event_data.call).to.equal( - MOCK.AD_RENDER_FAILED.call - ); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + expect(requests.length).to.equal(0); + sinon.assert.callCount(invisiblyAdapter.track, 0); + sinon.assert.callCount(invisiblyAdapter.sendEvent, 0); + }); - // spec for auction end event - it('auction end event', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); - invisiblyAdapter.flush(); - - const invisiblyEvents = JSON.parse(server.requests[0].requestBody.substring(0)); - expect(server.requests.length).to.equal(1); - expect(server.requests[0].url).to.equal('https://api.pymx5.com/v1/sites/events'); - expect(invisiblyEvents.event_data.pageViewId).to.exist; - expect(invisiblyEvents.event_data.ver).to.equal(1); - expect(invisiblyEvents.event_type).to.equal('PREBID_auctionEnd'); - expect(invisiblyEvents.event_data.auctionId).to.equal( - MOCK.AUCTION_END.auctionId - ); - sinon.assert.callCount(invisiblyAdapter.track, 1); - }); + // spec to emit all events + it('track all event without errors', function () { + invisiblyAdapter.enableAnalytics(MOCK.config); - // should not call sendEvent for events not supported by the adapter - it('it should not call sendEvent for this event emit', function() { - sinon.spy(invisiblyAdapter, 'sendEvent'); - invisiblyAdapter.enableAnalytics(MOCK.config); - events.emit(constants.EVENTS.INVALID_EVENT, MOCK.INVALID_EVENT); - invisiblyAdapter.flush(); + events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); + events.emit(constants.EVENTS.BID_ADJUSTMENT, MOCK.BID_ADJUSTMENT); + events.emit(constants.EVENTS.BID_TIMEOUT, MOCK.BID_TIMEOUT); + events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(constants.EVENTS.NO_BID, MOCK.NO_BID); + events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); + events.emit(constants.EVENTS.BIDDER_DONE, MOCK.BIDDER_DONE); + events.emit(constants.EVENTS.SET_TARGETING, MOCK.SET_TARGETING); + events.emit(constants.EVENTS.REQUEST_BIDS, MOCK.REQUEST_BIDS); + events.emit(constants.EVENTS.ADD_AD_UNITS, MOCK.ADD_AD_UNITS); + events.emit(constants.EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED); - expect(server.requests.length).to.equal(0); - sinon.assert.callCount(invisiblyAdapter.track, 0); - sinon.assert.callCount(invisiblyAdapter.sendEvent, 0); + sinon.assert.callCount(invisiblyAdapter.track, 13); + }); }); - // spec to emit all events - it('track all event without errors', function() { - invisiblyAdapter.enableAnalytics(MOCK.config); - - events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); - events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); - events.emit(constants.EVENTS.BID_ADJUSTMENT, MOCK.BID_ADJUSTMENT); - events.emit(constants.EVENTS.BID_TIMEOUT, MOCK.BID_TIMEOUT); - events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); - events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); - events.emit(constants.EVENTS.NO_BID, MOCK.NO_BID); - events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); - events.emit(constants.EVENTS.BIDDER_DONE, MOCK.BIDDER_DONE); - events.emit(constants.EVENTS.SET_TARGETING, MOCK.SET_TARGETING); - events.emit(constants.EVENTS.REQUEST_BIDS, MOCK.REQUEST_BIDS); - events.emit(constants.EVENTS.ADD_AD_UNITS, MOCK.ADD_AD_UNITS); - events.emit(constants.EVENTS.AD_RENDER_FAILED, MOCK.AD_RENDER_FAILED); - - sinon.assert.callCount(invisiblyAdapter.track, 13); + describe('Should not send any event even if they are caputured', function () { + beforeEach(function () { + invisiblyAdapter.weightedFilter.filter = false; + }); + it('it should not send any event', function () { + invisiblyAdapter.enableAnalytics({ + provider: 'invisiblyAnalytics', + options: { + account: 'invisibly', + }, + }); + + events.emit(constants.EVENTS.AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(constants.EVENTS.AUCTION_END, MOCK.AUCTION_END); + events.emit(constants.EVENTS.BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(constants.EVENTS.BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(constants.EVENTS.BID_WON, MOCK.BID_WON); + invisiblyAdapter.flush(); + + sinon.assert.callCount(invisiblyAdapter.sendEvent, 0); + sinon.assert.callCount(invisiblyAdapter.track, 0); + expect(requests.length).to.equal(0); + }); }); }); }); diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index bff93d4ef61..680ffdc0fcc 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -1,14 +1,32 @@ -import * as utils from 'src/utils'; -import { config } from 'src/config'; +import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; import { expect } from 'chai'; -import { newBidder } from 'src/adapters/bidderFactory'; -import { spec } from 'modules/ixBidAdapter'; +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 VIDEO_ENDPOINT_VERSION = 8.1; const BANNER_ENDPOINT_VERSION = 7.2; + const SAMPLE_SCHAIN = { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'indirectseller.com', + 'sid': '00001', + 'hp': 1 + }, + + { + 'asi': 'indirectseller-2.com', + 'sid': '00002', + 'hp': 2 + } + ] + }; + const DEFAULT_BANNER_VALID_BID = [ { bidder: 'ix', @@ -26,7 +44,8 @@ describe('IndexexchangeAdapter', function () { transactionId: '173f49a8-7549-4218-a23c-e7ba59b47229', bidId: '1a2b3c4d', bidderRequestId: '11a22b33c44d', - auctionId: '1aa2bb3cc4dd' + auctionId: '1aa2bb3cc4dd', + schain: SAMPLE_SCHAIN } ]; @@ -56,7 +75,8 @@ describe('IndexexchangeAdapter', function () { transactionId: '173f49a8-7549-4218-a23c-e7ba59b47230', bidId: '1a2b3c4e', bidderRequestId: '11a22b33c44e', - auctionId: '1aa2bb3cc4de' + auctionId: '1aa2bb3cc4de', + schain: SAMPLE_SCHAIN } ]; @@ -170,6 +190,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); @@ -177,6 +213,26 @@ describe('IndexexchangeAdapter', function () { }); }); + describe('getUserSync tests', function () { + it('UserSync test : check type = iframe, check usermatch URL', function () { + const syncOptions = { + 'iframeEnabled': true + } + let userSync = spec.getUserSyncs(syncOptions); + expect(userSync[0].type).to.equal('iframe'); + const USER_SYNC_URL = 'https://js-sec.indexww.com/um/ixmatch.html'; + expect(userSync[0].url).to.equal(USER_SYNC_URL); + }); + + it('When iframeEnabled is false, no userSync should be returned', function () { + const syncOptions = { + 'iframeEnabled': false + } + let userSync = spec.getUserSyncs(syncOptions); + expect(userSync).to.be.an('array').that.is.empty; + }); + }); + describe('isBidRequestValid', function () { it('should return true when required params found for a banner or video ad', function () { expect(spec.isBidRequestValid(DEFAULT_BANNER_VALID_BID[0])).to.equal(true); @@ -317,21 +373,24 @@ describe('IndexexchangeAdapter', function () { let query; let testCopy; - beforeEach(function() { + beforeEach(function () { window.headertag = {}; - window.headertag.getIdentityInfo = function() { + window.headertag.getIdentityInfo = function () { return testCopy; }; request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; query = request.data; }); - afterEach(function() { + + afterEach(function () { delete window.headertag; }); - describe('buildRequestSingleRTI', function() { - before(function() { + + 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); @@ -348,16 +407,19 @@ describe('IndexexchangeAdapter', function () { }); }); - describe('buildRequestMultipleIds', function() { - before(function() { + describe('buildRequestMultipleIds', function () { + before(function () { testCopy = JSON.parse(JSON.stringify(DEFAULT_IDENTITY_RESPONSE)); - testCopy.IdentityIp.data.uids.push({ - id: '1234567' - }, - { - id: '2019-04-01TF2:34:41' - }); + testCopy.IdentityIp.data.uids.push( + { + id: '1234567' + }, + { + id: '2019-04-01TF2:34:41' + } + ); }); + it('payload should have correct format and value (single identity w/ multi ids)', function () { const payload = JSON.parse(query.r); @@ -375,8 +437,8 @@ describe('IndexexchangeAdapter', function () { }); }); - describe('buildRequestMultipleRTI', function() { - before(function() { + describe('buildRequestMultipleRTI', function () { + before(function () { testCopy = JSON.parse(JSON.stringify(DEFAULT_IDENTITY_RESPONSE)); testCopy.JackIp = { responsePending: false, @@ -401,6 +463,7 @@ describe('IndexexchangeAdapter', function () { } } }); + it('payload should have correct format and value (multiple identity partners)', function () { const payload = JSON.parse(query.r); @@ -424,13 +487,13 @@ describe('IndexexchangeAdapter', function () { }); }); - describe('buildRequestNoData', function() { - beforeEach(function() { + describe('buildRequestNoData', function () { + beforeEach(function () { testCopy = JSON.parse(JSON.stringify(DEFAULT_IDENTITY_RESPONSE)); }); it('payload should not have any user eids with an undefined identity data response', function () { - window.headertag.getIdentityInfo = function() { + window.headertag.getIdentityInfo = function () { return undefined; }; request = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION)[0]; @@ -477,12 +540,188 @@ 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; const requestMethod = request.method; const query = request.data; + const bidWithoutSchain = utils.deepClone(DEFAULT_BANNER_VALID_BID); + delete bidWithoutSchain[0].schain; + const requestWithoutSchain = spec.buildRequests(bidWithoutSchain, DEFAULT_OPTION)[0]; + const queryWithoutSchain = requestWithoutSchain.data; + const bidWithoutMediaType = utils.deepClone(DEFAULT_BANNER_VALID_BID); delete bidWithoutMediaType[0].mediaTypes; bidWithoutMediaType[0].sizes = [[300, 250], [300, 600]]; @@ -505,16 +744,21 @@ describe('IndexexchangeAdapter', function () { it('payload should have correct format and value', function () { const payload = JSON.parse(query.r); - expect(payload.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidderRequestId); expect(payload.site).to.exist; expect(payload.site.page).to.equal(DEFAULT_OPTION.refererInfo.referer); expect(payload.site.ref).to.equal(document.referrer); expect(payload.ext).to.exist; expect(payload.ext.source).to.equal('prebid'); + 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 () { + const payload = JSON.parse(queryWithoutSchain.r); + expect(payload.source).to.not.exist; // source object currently only written for schain }); it('impression should have correct format and value', function () { @@ -683,6 +927,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); @@ -697,6 +942,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 () { @@ -777,7 +1096,7 @@ describe('IndexexchangeAdapter', function () { mediaType: 'banner', ad: '', currency: 'USD', - ttl: 35, + ttl: 300, netRevenue: true, dealId: undefined, meta: { @@ -804,7 +1123,7 @@ describe('IndexexchangeAdapter', function () { mediaType: 'banner', ad: '', currency: 'USD', - ttl: 35, + ttl: 300, netRevenue: true, dealId: undefined, meta: { @@ -830,7 +1149,7 @@ describe('IndexexchangeAdapter', function () { mediaType: 'banner', ad: '', currency: 'JPY', - ttl: 35, + ttl: 300, netRevenue: true, dealId: undefined, meta: { @@ -857,7 +1176,7 @@ describe('IndexexchangeAdapter', function () { mediaType: 'banner', ad: '', currency: 'USD', - ttl: 35, + ttl: 300, netRevenue: true, dealId: 'deal', meta: { @@ -930,7 +1249,7 @@ describe('IndexexchangeAdapter', function () { }); }); - describe('bidrequest consent', function() { + describe('bidrequest consent', function () { it('should have consent info if gdprApplies and consentString exist', function () { const validBidWithConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, DEFAULT_OPTION); const requestWithConsent = JSON.parse(validBidWithConsent[0].data.r); @@ -976,7 +1295,7 @@ describe('IndexexchangeAdapter', function () { expect(requestWithConsent.user).to.be.undefined; }); - it('should have us_privacy if uspConsent is defined', function() { + it('should have us_privacy if uspConsent is defined', function () { const options = { uspConsent: '1YYN' }; @@ -986,7 +1305,7 @@ describe('IndexexchangeAdapter', function () { expect(requestWithUspConsent.regs.ext.us_privacy).to.equal('1YYN'); }); - it('should not have us_privacy if uspConsent undefined', function() { + it('should not have us_privacy if uspConsent undefined', function () { const options = {}; const validBidWithUspConsent = spec.buildRequests(DEFAULT_BANNER_VALID_BID, options); const requestWithUspConsent = JSON.parse(validBidWithUspConsent[0].data.r); @@ -994,7 +1313,7 @@ describe('IndexexchangeAdapter', function () { expect(requestWithUspConsent.regs).to.be.undefined; }); - it('should have both gdpr and us_privacy if both are defined', function() { + it('should have both gdpr and us_privacy if both are defined', function () { const options = { gdprConsent: { gdprApplies: true, diff --git a/test/spec/modules/jcmBidAdapter_spec.js b/test/spec/modules/jcmBidAdapter_spec.js index fa6791674bc..9d84bca5513 100644 --- a/test/spec/modules/jcmBidAdapter_spec.js +++ b/test/spec/modules/jcmBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/jcmBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/jcmBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const ENDPOINT = 'https://media.adfrontiers.com/'; diff --git a/test/spec/modules/justpremiumBidAdapter_spec.js b/test/spec/modules/justpremiumBidAdapter_spec.js index 3b34799f36d..c162b785aed 100644 --- a/test/spec/modules/justpremiumBidAdapter_spec.js +++ b/test/spec/modules/justpremiumBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai' -import { spec } from 'modules/justpremiumBidAdapter' +import { spec } from 'modules/justpremiumBidAdapter.js' describe('justpremium adapter', function () { let sandbox; diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index 3136e612595..be73e140839 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect, assert} from 'chai'; -import {spec} from 'modules/kargoBidAdapter'; -import {config} from 'src/config'; +import {spec} from 'modules/kargoBidAdapter.js'; +import {config} from 'src/config.js'; describe('kargo adapter tests', function () { var sandbox, clock, frozenNow = new Date(); @@ -50,6 +50,7 @@ describe('kargo adapter tests', function () { return {adServerCurrency: 'USD'}; } if (key === 'debug') return true; + if (key === 'deviceAccess') return true; throw new Error(`Config stub incomplete! Missing key "${key}"`) }); @@ -440,7 +441,8 @@ describe('kargo adapter tests', function () { cpm: 3, adm: '
', width: 320, - height: 50 + height: 50, + metadata: {} }, 2: { id: 'bar', @@ -448,7 +450,10 @@ describe('kargo adapter tests', function () { adm: '
', width: 300, height: 250, - targetingCustom: 'dmpmptest1234' + targetingCustom: 'dmpmptest1234', + metadata: { + landingPageDomain: 'https://foobar.com' + } }, 3: { id: 'bar', @@ -486,7 +491,8 @@ describe('kargo adapter tests', function () { creativeId: 'foo', dealId: undefined, netRevenue: true, - currency: 'USD' + currency: 'USD', + meta: undefined }, { requestId: '2', cpm: 2.5, @@ -497,7 +503,10 @@ describe('kargo adapter tests', function () { creativeId: 'bar', dealId: 'dmpmptest1234', netRevenue: true, - currency: 'USD' + currency: 'USD', + meta: { + clickUrl: 'https://foobar.com' + } }, { requestId: '3', cpm: 2.5, @@ -508,7 +517,8 @@ describe('kargo adapter tests', function () { creativeId: 'bar', dealId: undefined, netRevenue: true, - currency: 'USD' + currency: 'USD', + meta: undefined }]; expect(resp).to.deep.equal(expectation); }); diff --git a/test/spec/modules/komoonaBidAdapter_spec.js b/test/spec/modules/komoonaBidAdapter_spec.js index ed84155b28d..3d62f91cae6 100644 --- a/test/spec/modules/komoonaBidAdapter_spec.js +++ b/test/spec/modules/komoonaBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/komoonaBidAdapter'; +import { spec } from 'modules/komoonaBidAdapter.js'; describe('Komoona.com Adapter Tests', function () { const bidsRequest = [ diff --git a/test/spec/modules/konduitAnalyticsAdapter_spec.js b/test/spec/modules/konduitAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..ac557d27f90 --- /dev/null +++ b/test/spec/modules/konduitAnalyticsAdapter_spec.js @@ -0,0 +1,126 @@ +import konduitAnalyticsAdapter from 'modules/konduitAnalyticsAdapter'; +import { expect } from 'chai'; +import { config } from '../../../src/config.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'); + +const eventsData = { + [CONSTANTS.EVENTS.AUCTION_INIT]: { + 'auctionId': 'test_auction_id', + 'timestamp': Date.now(), + 'auctionStatus': 'inProgress', + 'adUnitCodes': ['video-test'], + 'timeout': 700 + }, + [CONSTANTS.EVENTS.BID_REQUESTED]: { + 'bidderCode': 'test_bidder_code', + 'time': Date.now(), + 'bids': [{ + 'transactionId': 'test_transaction_id', + 'adUnitCode': 'video-test', + 'bidId': 'test_bid_id', + 'sizes': '640x480', + 'params': { 'testParam': 'test_param' } + }] + }, + [CONSTANTS.EVENTS.NO_BID]: { + 'bidderCode': 'test_bidder_code2', + 'transactionId': 'test_transaction_id', + 'adUnitCode': 'video-test', + 'bidId': 'test_bid_id' + }, + [CONSTANTS.EVENTS.BID_RESPONSE]: { + 'bidderCode': 'test_bidder_code', + 'adUnitCode': 'video-test', + 'statusMessage': 'Bid available', + 'mediaType': 'video', + 'renderedSize': '640x480', + 'cpm': 0.5, + 'currency': 'USD', + 'netRevenue': true, + 'timeToRespond': 124, + 'requestId': 'test_request_id', + 'creativeId': 144876543 + }, + [CONSTANTS.EVENTS.AUCTION_END]: { + 'auctionId': 'test_auction_id', + 'timestamp': Date.now(), + 'auctionEnd': Date.now() + 400, + 'auctionStatus': 'completed', + 'adUnitCodes': ['video-test'], + 'timeout': 700 + }, + [CONSTANTS.EVENTS.BID_WON]: { + 'bidderCode': 'test_bidder_code', + 'adUnitCode': 'video-test', + 'statusMessage': 'Bid available', + 'mediaType': 'video', + 'renderedSize': '640x480', + 'cpm': 0.5, + 'currency': 'USD', + 'netRevenue': true, + 'timeToRespond': 124, + 'requestId': 'test_request_id', + 'creativeId': 144876543 + }, +}; + +describe(`Konduit Analytics Adapter`, () => { + const konduitId = 'test'; + + beforeEach(function () { + sinon.spy(konduitAnalyticsAdapter, 'track'); + sinon.stub(events, 'getEvents').returns([]); + config.setConfig({ konduit: { konduitId } }); + }); + + afterEach(function () { + events.getEvents.restore(); + konduitAnalyticsAdapter.track.restore(); + konduitAnalyticsAdapter.disableAnalytics(); + }); + + it(`should add all events to an aggregatedEvents queue + inside konduitAnalyticsAdapter.context and send a request with correct data`, function () { + server.respondWith(JSON.stringify({ key: 'test' })); + + adapterManager.registerAnalyticsAdapter({ + code: 'konduit', + adapter: konduitAnalyticsAdapter + }); + + adapterManager.enableAnalytics({ + provider: 'konduit', + }); + + expect(konduitAnalyticsAdapter.context).to.be.an('object'); + expect(konduitAnalyticsAdapter.context.aggregatedEvents).to.be.an('array'); + + const eventTypes = [ + CONSTANTS.EVENTS.AUCTION_INIT, + CONSTANTS.EVENTS.BID_REQUESTED, + CONSTANTS.EVENTS.NO_BID, + CONSTANTS.EVENTS.BID_RESPONSE, + CONSTANTS.EVENTS.BID_WON, + CONSTANTS.EVENTS.AUCTION_END, + ]; + const args = eventTypes.map(eventType => eventsData[eventType]); + + eventTypes.forEach((eventType, i) => { + events.emit(eventType, args[i]); + }); + + server.respond(); + + expect(konduitAnalyticsAdapter.context.aggregatedEvents.length).to.be.equal(6); + expect(server.requests[0].url).to.match(/http(s):\/\/\w*\.konduit\.me\/analytics-initial-event/); + + const requestBody = JSON.parse(server.requests[0].requestBody); + expect(requestBody.konduitId).to.be.equal(konduitId); + expect(requestBody.prebidVersion).to.be.equal('$prebid.version$'); + expect(requestBody.environment).to.be.an('object'); + sinon.assert.callCount(konduitAnalyticsAdapter.track, 6); + }); +}); diff --git a/test/spec/modules/konduitWrapper_spec.js b/test/spec/modules/konduitWrapper_spec.js index bcc65ddd683..c88287c7066 100644 --- a/test/spec/modules/konduitWrapper_spec.js +++ b/test/spec/modules/konduitWrapper_spec.js @@ -1,72 +1,237 @@ import { expect } from 'chai'; -import parse from 'url-parse'; -import { buildVastUrl } from 'modules/konduitWrapper'; -import { parseQS } from 'src/url'; -import { config } from 'src/config'; +import { processBids, errorMessages } from 'modules/konduitWrapper.js'; +import { config } from 'src/config.js'; +import { server } from 'test/mocks/xhr.js'; describe('The Konduit vast wrapper module', function () { - it('should make a wrapped request url when `bid` passed', function () { - const bid = createBid(10, 'video1', 15, '10.00_15s', '123', '395'); + const konduitId = 'test'; + beforeEach(function() { + config.setConfig({ konduit: { konduitId } }); + }); - const url = parse(buildVastUrl({ - bid, - params: { 'konduit_id': 'testId' }, - })); + describe('processBids function (send one bid)', () => { + beforeEach(function() { + config.setConfig({ enableSendAllBids: false }); + }); - expect(url.protocol).to.equal('https:'); - expect(url.host).to.equal('p.konduit.me'); + 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'); - const queryParams = parseQS(url.query); - expect(queryParams).to.have.property('konduit_url', encodeURIComponent('http://some-vast-url.com')); - expect(queryParams).to.have.property('konduit_header_bidding', '1'); - expect(queryParams).to.have.property('konduit_id', 'testId'); - }); + server.respondWith(JSON.stringify({ + kCpmData: { [`${bid.bidderCode}:${bid.creativeId}`]: bid.cpm }, + cacheData: { [`${bid.bidderCode}:${bid.creativeId}`]: 'test_cache_key' }, + })); - it('should return null when no `konduit_id` (required param) passed', function () { - const bid = createBid(10, 'video1', 15, '10.00_15s', '123', '395'); + processBids({ bid }); + server.respond(); - const url = buildVastUrl({ bid }); + expect(server.requests.length).to.equal(1); - expect(url).to.equal(null); - }); + const requestBody = JSON.parse(server.requests[0].requestBody); - it('should return null when either bid or adUnit is not passed', function () { - const url = buildVastUrl({ params: { 'konduit_id': 'testId' } }); + expect(requestBody.clientId).to.equal(konduitId); - expect(url).to.equal(null); - }); + 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_cache_key).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({ 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); - it('should return null when bid does not contain vastUrl', function () { - const bid = createBid(10, 'video1', 15, '10.00_15s', '123', '395'); + expect(bid.konduitCacheKey).to.be.undefined; + expect(bid.kCpm).to.equal(bid.cpm); - delete bid.vastUrl; + expect(bid.adserverTargeting.k_cpm).to.equal(bid.pbCg || bid.pbAg); + expect(bid.adserverTargeting.k_cache_key).to.be.undefined; + expect(bid.adserverTargeting.konduit_id).to.be.undefined; - const url = buildVastUrl({ - bid, - params: { 'konduit_id': 'testId' }, + expect(callback.firstCall.args[0]).to.be.an('error'); }); - expect(url).to.equal(null); + 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({ + 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({ + 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({ + 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_BIDS); + }); }); + describe('processBids function (send all bids)', () => { + beforeEach(function() { + config.setConfig({ enableSendAllBids: true }); + }); - it('should return wrapped vastUrl based on cached url in params', function () { - config.setConfig({ cache: { url: 'https://cached.url.com' } }); - const bid = createBid(10, 'video1', 15, '10.00_15s', '123', '395'); + 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'); - delete bid.vastUrl; + server.respondWith(JSON.stringify({ + kCpmData: { [`${bid.bidderCode}:${bid.creativeId}`]: bid.cpm }, + cacheData: { [`${bid.bidderCode}:${bid.creativeId}`]: 'test_cache_key' }, + })); - const expectedUrl = encodeURIComponent(`https://cached.url.com?uuid=${bid.videoCacheKey}`); + processBids({ adUnitCode: 'video1', bids: [bid] }); + server.respond(); - const url = parse(buildVastUrl({ - bid, - params: { 'konduit_id': 'testId' }, - })); - const queryParams = parseQS(url.query); + expect(server.requests.length).to.equal(1); - expect(queryParams).to.have.property('konduit_url', expectedUrl); + const requestBody = JSON.parse(server.requests[0].requestBody); - config.resetConfig(); + 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_BIDS); + }); }); }); @@ -101,9 +266,9 @@ function createBid(cpm, adUnitCode, durationBucket, priceIndustryDuration, uuid, 'bidder': 'appnexus', 'timeToRespond': 61, 'pbLg': '5.00', - 'pbMg': '5.00', + 'pbMg': `${cpm}.00`, 'pbHg': '5.00', - 'pbAg': '5.00', + 'pbAg': `${cpm}.00`, 'pbDg': '5.00', 'pbCg': '', 'size': '640x360', @@ -119,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/lemmaBidAdapter_spec.js b/test/spec/modules/lemmaBidAdapter_spec.js new file mode 100644 index 00000000000..a236ac17d71 --- /dev/null +++ b/test/spec/modules/lemmaBidAdapter_spec.js @@ -0,0 +1,335 @@ +import { expect } from 'chai'; +import { spec } from 'modules/lemmaBidAdapter.js'; +import * as utils from 'src/utils.js'; +const constants = require('src/constants.json'); + +describe('lemmaBidAdapter', function() { + var bidRequests; + var videoBidRequests; + var bidResponses; + beforeEach(function() { + bidRequests = [{ + bidder: 'lemma', + mediaType: 'banner', + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [300, 600] + ], + } + }, + params: { + pubId: 1001, + adunitId: 1, + currency: 'AUD', + geo: { + lat: '12.3', + lon: '23.7', + } + }, + sizes: [ + [300, 250], + [300, 600] + ] + }]; + videoBidRequests = [{ + code: 'video1', + mediaType: 'video', + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'instream' + } + }, + bidder: 'lemma', + params: { + pubId: 1001, + adunitId: 1, + video: { + mimes: ['video/mp4', 'video/x-flv'], + skippable: true, + minduration: 5, + maxduration: 30 + } + } + }]; + bidResponses = { + 'body': { + 'id': '93D3BAD6-E2E2-49FB-9D89-920B1761C865', + 'seatbid': [{ + 'bid': [{ + 'id': '74858439-49D7-4169-BA5D-44A046315B2F', + 'impid': '22bddb28db77d', + 'price': 1.3, + 'adm': '

lemma"Connecting Advertisers and Publishers directly"

', + 'adomain': ['amazon.com'], + 'iurl': 'https://thetradedesk-t-general.s3.amazonaws.com/AdvertiserLogos/vgl908z.png', + 'cid': '22918', + 'crid': 'v55jutrh', + 'h': 250, + 'w': 300, + 'ext': {} + }] + }] + } + }; + }); + describe('implementation', function() { + describe('Bid validations', function() { + it('valid bid case', function() { + var validBid = { + bidder: 'lemma', + params: { + pubId: 1001, + adunitId: 1 + } + }, + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(true); + }); + it('invalid bid case', function() { + var isValid = spec.isBidRequestValid(); + expect(isValid).to.equal(false); + }); + it('invalid bid case: pubId not passed', function() { + var validBid = { + bidder: 'lemma', + params: { + adunitId: 1 + } + }, + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(false); + }); + it('invalid bid case: pubId is not number', function() { + var validBid = { + bidder: 'lemma', + params: { + pubId: '301', + adunitId: 1 + } + }, + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(false); + }); + it('invalid bid case: adunitId is not passed', function() { + var validBid = { + bidder: 'lemma', + params: { + pubId: 1001 + } + }, + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(false); + }); + it('invalid bid case: video bid request mimes is not passed', function() { + var validBid = { + bidder: 'lemma', + params: { + pubId: 1001, + adunitId: 1, + video: { + skippable: true, + minduration: 5, + maxduration: 30 + } + } + }, + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(false); + validBid.params.video.mimes = []; + isValid = spec.isBidRequestValid(validBid); + expect(isValid).to.equal(false); + }); + }); + describe('Request formation', function() { + it('buildRequests function should not modify original bidRequests object', function() { + var originalBidRequests = utils.deepClone(bidRequests); + var request = spec.buildRequests(bidRequests); + expect(bidRequests).to.deep.equal(originalBidRequests); + }); + it('Endpoint checking', function() { + var request = spec.buildRequests(bidRequests); + expect(request.url).to.equal('https://ads.lemmatechnologies.com/lemma/servad?pid=1001&aid=1'); + expect(request.method).to.equal('POST'); + }); + it('Request params check', function() { + var request = spec.buildRequests(bidRequests); + var data = JSON.parse(request.data); + expect(data.site.domain).to.be.a('string'); // domain should be set + expect(data.site.publisher.id).to.equal(bidRequests[0].params.pubId.toString()); // publisher Id + expect(data.imp[0].tagid).to.equal('1'); // tagid + expect(data.imp[0].bidfloorcur).to.equal(bidRequests[0].params.currency); + }); + it('Request params check without mediaTypes object', function() { + var bidRequests = [{ + bidder: 'lemma', + params: { + pubId: 1001, + adunitId: 1, + currency: 'AUD' + }, + sizes: [ + [300, 250], + [300, 600] + ] + }]; + var request = spec.buildRequests(bidRequests); + var data = JSON.parse(request.data); + expect(data.imp[0].banner.w).to.equal(300); // width + expect(data.imp[0].banner.h).to.equal(250); // height + expect(data.imp[0].banner.format).exist.and.to.be.an('array'); + expect(data.imp[0].banner.format[0]).exist.and.to.be.an('object'); + expect(data.imp[0].banner.format[0].w).to.equal(300); // width + expect(data.imp[0].banner.format[0].h).to.equal(600); // height + }); + it('Request params check: without tagId', function() { + delete bidRequests[0].params.adunitId; + var request = spec.buildRequests(bidRequests); + var data = JSON.parse(request.data); + expect(data.site.domain).to.be.a('string'); // domain should be set + expect(data.site.publisher.id).to.equal(bidRequests[0].params.pubId.toString()); // publisher Id + expect(data.imp[0].tagid).to.equal(undefined); // tagid + expect(data.imp[0].bidfloorcur).to.equal(bidRequests[0].params.currency); + }); + it('Request params multi size format object check', function() { + var bidRequests = [{ + bidder: 'lemma', + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [300, 600] + ], + } + }, + params: { + pubId: 1001, + adunitId: 1, + currency: 'AUD' + }, + sizes: [ + [300, 250], + [300, 600] + ] + }]; + /* case 1 - size passed in adslot */ + var request = spec.buildRequests(bidRequests); + var data = JSON.parse(request.data); + expect(data.imp[0].banner.w).to.equal(300); // width + expect(data.imp[0].banner.h).to.equal(250); // height + /* case 2 - size passed in adslot as well as in sizes array */ + bidRequests[0].sizes = [ + [300, 600], + [300, 250] + ]; + bidRequests[0].mediaTypes = { + banner: { + sizes: [ + [300, 600], + [300, 250] + ] + } + }; + request = spec.buildRequests(bidRequests); + data = JSON.parse(request.data); + expect(data.imp[0].banner.w).to.equal(300); // width + expect(data.imp[0].banner.h).to.equal(600); // height + /* case 3 - size passed in sizes but not in adslot */ + bidRequests[0].params.adunitId = 1; + bidRequests[0].sizes = [ + [300, 250], + [300, 600] + ]; + bidRequests[0].mediaTypes = { + banner: { + sizes: [ + [300, 250], + [300, 600] + ] + } + }; + request = spec.buildRequests(bidRequests); + data = JSON.parse(request.data); + expect(data.imp[0].banner.w).to.equal(300); // width + expect(data.imp[0].banner.h).to.equal(250); // height + expect(data.imp[0].banner.format).exist.and.to.be.an('array'); + expect(data.imp[0].banner.format[0]).exist.and.to.be.an('object'); + expect(data.imp[0].banner.format[0].w).to.equal(300); // width + expect(data.imp[0].banner.format[0].h).to.equal(250); // height + }); + it('Request params currency check', function() { + var bidRequest = [{ + bidder: 'lemma', + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [300, 600] + ], + } + }, + params: { + pubId: 1001, + adunitId: 1, + currency: 'AUD' + }, + sizes: [ + [300, 250], + [300, 600] + ] + }]; + /* case 1 - + currency specified in adunits + output: imp[0] use currency specified in bidRequests[0].params.currency + */ + var request = spec.buildRequests(bidRequest); + var data = JSON.parse(request.data); + expect(data.imp[0].bidfloorcur).to.equal(bidRequests[0].params.currency); + /* case 2 - + currency specified in adunit + output: imp[0] use default currency - USD + */ + delete bidRequest[0].params.currency; + request = spec.buildRequests(bidRequest); + data = JSON.parse(request.data); + expect(data.imp[0].bidfloorcur).to.equal('USD'); + }); + it('Request params check for video ad', function() { + var request = spec.buildRequests(videoBidRequests); + var data = JSON.parse(request.data); + expect(data.imp[0].video).to.exist; + expect(data.imp[0].tagid).to.equal('1'); + expect(data.imp[0]['video']['mimes']).to.exist.and.to.be.an('array'); + expect(data.imp[0]['video']['mimes'][0]).to.equal(videoBidRequests[0].params.video['mimes'][0]); + expect(data.imp[0]['video']['mimes'][1]).to.equal(videoBidRequests[0].params.video['mimes'][1]); + expect(data.imp[0]['video']['minduration']).to.equal(videoBidRequests[0].params.video['minduration']); + expect(data.imp[0]['video']['maxduration']).to.equal(videoBidRequests[0].params.video['maxduration']); + expect(data.imp[0]['video']['w']).to.equal(videoBidRequests[0].mediaTypes.video.playerSize[0]); + expect(data.imp[0]['video']['h']).to.equal(videoBidRequests[0].mediaTypes.video.playerSize[1]); + }); + describe('Response checking', function() { + it('should check for valid response values', function() { + var request = spec.buildRequests(bidRequests); + var data = JSON.parse(request.data); + var response = spec.interpretResponse(bidResponses, request); + expect(response).to.be.an('array').with.length.above(0); + expect(response[0].requestId).to.equal(bidResponses.body.seatbid[0].bid[0].impid); + expect(response[0].cpm).to.equal((bidResponses.body.seatbid[0].bid[0].price).toFixed(2)); + expect(response[0].width).to.equal(bidResponses.body.seatbid[0].bid[0].w); + expect(response[0].height).to.equal(bidResponses.body.seatbid[0].bid[0].h); + if (bidResponses.body.seatbid[0].bid[0].crid) { + expect(response[0].creativeId).to.equal(bidResponses.body.seatbid[0].bid[0].crid); + } else { + expect(response[0].creativeId).to.equal(bidResponses.body.seatbid[0].bid[0].id); + } + expect(response[0].dealId).to.equal(bidResponses.body.seatbid[0].bid[0].dealid); + expect(response[0].currency).to.equal('USD'); + expect(response[0].netRevenue).to.equal(false); + expect(response[0].ttl).to.equal(300); + }); + }); + }); + }); +}); diff --git a/test/spec/modules/lifestreetBidAdapter_spec.js b/test/spec/modules/lifestreetBidAdapter_spec.js new file mode 100644 index 00000000000..d66727da644 --- /dev/null +++ b/test/spec/modules/lifestreetBidAdapter_spec.js @@ -0,0 +1,232 @@ +import { expect } from 'chai'; +import { BANNER, VIDEO } from 'src/mediaTypes.js'; +import { spec } from 'modules/lifestreetBidAdapter.js'; + +describe('lifestreetBidAdapter', function() { + let bidRequests; + let videoBidRequests; + let bidResponses; + let videoBidResponses; + beforeEach(function() { + bidRequests = [ + { + bidder: 'lifestreet', + params: { + slot: 'slot166704', + adkey: '78c', + ad_size: '160x600' + }, + mediaTypes: { + banner: { + sizes: [ + [160, 600], + [300, 600] + ] + } + }, + sizes: [ + [160, 600], + [300, 600] + ] + } + ]; + + bidResponses = { + body: { + cpm: 0.1, + netRevenue: true, + content_type: 'display_flash', + width: 160, + currency: 'USD', + ttl: 86400, + content: '', + 'adid': '56380110', + 'cid': '44724710', + 'crid': '443801010', + 'w': 300, + 'h': 250, + 'ext': { + 'prebid': { + 'targeting': { + 'hb_bidder': 'luponmedia', + 'hb_pb': '0.40', + 'hb_size': '300x250' + }, + 'type': 'banner' + } + } + } + ], + 'seat': 'luponmedia' + } + ], + 'cur': 'USD', + 'ext': { + 'responsetimemillis': { + 'luponmedia': 233 + }, + 'tmaxrequest': 1500, + 'usersyncs': { + 'status': 'ok', + 'bidder_status': [] + } + } + }; + + let expectedResponse = [ + { + 'requestId': '2a122246ef72ea', + 'cpm': '0.43', + 'width': 300, + 'height': 250, + 'creativeId': '443801010', + 'currency': 'USD', + 'dealId': '23425', + 'netRevenue': false, + 'ttl': 300, + 'referrer': '', + 'ad': ' ' + } + ]; + + let bidderRequest = { + 'data': '{"site":{"page":"https://novi.ba/clanak/176067/fast-car-beginner-s-guide-to-tuning-turbo-engines"}}' + }; + + 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 noBidResponse = []; + + let noBidBidderRequest = { + 'data': '{"site":{"page":""}}' + } + let noBidResult = spec.interpretResponse({ body: noBidResponse }, noBidBidderRequest); + expect(noBidResult.length).to.equal(0); + }); + }); + + describe('getUserSyncs', function () { + const bidResponse1 = { + 'body': { + 'ext': { + 'responsetimemillis': { + 'luponmedia': 233 + }, + 'tmaxrequest': 1500, + 'usersyncs': { + 'status': 'ok', + 'bidder_status': [ + { + 'bidder': 'luponmedia', + 'no_cookie': true, + 'usersync': { + 'url': 'https://adxpremium.services/api/usersync', + 'type': 'redirect' + } + }, + { + 'bidder': 'luponmedia', + 'no_cookie': true, + 'usersync': { + 'url': 'https://adxpremium.services/api/iframeusersync', + 'type': 'iframe' + } + } + ] + } + } + } + }; + + const bidResponse2 = { + 'body': { + 'ext': { + 'responsetimemillis': { + 'luponmedia': 233 + }, + 'tmaxrequest': 1500, + 'usersyncs': { + 'status': 'no_cookie', + 'bidder_status': [] + } + } + } + }; + + it('should use a sync url from first response (pixel and iframe)', function () { + const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: true }, [bidResponse1, bidResponse2]); + expect(syncs).to.deep.equal([ + { + type: 'image', + url: 'https://adxpremium.services/api/usersync' + }, + { + type: 'iframe', + url: 'https://adxpremium.services/api/iframeusersync' + } + ]); + }); + + it('handle empty response (e.g. timeout)', function () { + const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: true }, []); + expect(syncs).to.deep.equal([]); + }); + + it('returns empty syncs when not pixel enabled and not iframe enabled', function () { + const syncs = spec.getUserSyncs({ pixelEnabled: false, iframeEnabled: false }, [bidResponse1]); + expect(syncs).to.deep.equal([]); + }); + + it('returns pixel syncs when pixel enabled and not iframe enabled', function() { + resetUserSync(); + + const syncs = spec.getUserSyncs({ pixelEnabled: true, iframeEnabled: false }, [bidResponse1]); + expect(syncs).to.deep.equal([ + { + type: 'image', + url: 'https://adxpremium.services/api/usersync' + } + ]); + }); + + it('returns iframe syncs when not pixel enabled and iframe enabled', function() { + resetUserSync(); + + const syncs = spec.getUserSyncs({ pixelEnabled: false, iframeEnabled: true }, [bidResponse1]); + expect(syncs).to.deep.equal([ + { + type: 'iframe', + url: 'https://adxpremium.services/api/iframeusersync' + } + ]); + }); + }); + + describe('hasValidSupplyChainParams', function () { + it('returns true if schain is valid', function () { + const schain = { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'novi.ba', + 'sid': '199424', + 'hp': 1 + } + ] + }; + + const checkSchain = hasValidSupplyChainParams(schain); + expect(checkSchain).to.equal(true); + }); + + it('returns false if schain is invalid', function () { + const schain = { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'invalid': 'novi.ba' + } + ] + }; + + const checkSchain = hasValidSupplyChainParams(schain); + expect(checkSchain).to.equal(false); + }); + }); +}); diff --git a/test/spec/modules/madvertiseBidAdapter_spec.js b/test/spec/modules/madvertiseBidAdapter_spec.js index e10a192355a..041b49ef69e 100644 --- a/test/spec/modules/madvertiseBidAdapter_spec.js +++ b/test/spec/modules/madvertiseBidAdapter_spec.js @@ -1,7 +1,7 @@ import {expect} from 'chai'; -import {config} from 'src/config'; -import * as utils from 'src/utils'; -import {spec} from 'modules/madvertiseBidAdapter'; +import {config} from 'src/config.js'; +import * as utils from 'src/utils.js'; +import {spec} from 'modules/madvertiseBidAdapter.js'; describe('madvertise adapater', function () { describe('Test validate req', function () { diff --git a/test/spec/modules/mantisBidAdapter_spec.js b/test/spec/modules/mantisBidAdapter_spec.js index 7caa9b29f6f..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'; -import {newBidder} from 'src/adapters/bidderFactory'; +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 72329330713..b4c2fe68f34 100644 --- a/test/spec/modules/marsmediaBidAdapter_spec.js +++ b/test/spec/modules/marsmediaBidAdapter_spec.js @@ -1,5 +1,5 @@ -import {spec} from '../../../modules/marsmediaBidAdapter'; -import * as utils from '../../../src/utils'; +import {spec} from '../../../modules/marsmediaBidAdapter.js'; +import * as utils from '../../../src/utils.js'; import * as sinon from 'sinon'; var r1adapter = spec; @@ -38,7 +38,7 @@ describe('marsmedia adapter tests', function () { var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); - expect(bidRequest.url).to.have.string('https://bid306.rtbsrv.com/bidder/?bid=3mhdom&zoneId=9999&hbv='); + expect(bidRequest.url).to.have.string('https://hb.go2speed.media/bidder/?bid=3mhdom&zoneId=9999&hbv='); expect(bidRequest.method).to.equal('POST'); const openrtbRequest = JSON.parse(bidRequest.data); expect(openrtbRequest.site).to.not.equal(null); @@ -61,7 +61,8 @@ describe('marsmedia adapter tests', function () { 'h': 250, 'adm': '
My Compelling Ad
', 'price': 1, - 'crid': 'cr-cfy24' + 'crid': 'cr-cfy24', + 'nurl': '' } ] }; @@ -108,7 +109,7 @@ describe('marsmedia adapter tests', function () { var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); - expect(bidRequest.url).to.have.string('https://bid306.rtbsrv.com/bidder/?bid=3mhdom&zoneId=9999&hbv='); + expect(bidRequest.url).to.have.string('https://hb.go2speed.media/bidder/?bid=3mhdom&zoneId=9999&hbv='); expect(bidRequest.method).to.equal('POST'); const openrtbRequest = JSON.parse(bidRequest.data); expect(openrtbRequest.site).to.not.equal(null); @@ -127,7 +128,7 @@ describe('marsmedia adapter tests', function () { expect(openrtbRequest.imp[0].video.api).to.eql([1, 2, 5]); }); - it('interpretResponse works', function() { + it('interpretResponse with vast url works', function() { var bidList = { 'body': [ { @@ -140,7 +141,8 @@ describe('marsmedia adapter tests', function () { 'cid': '467415', 'crid': 'cr-vid', 'w': 800, - 'h': 600 + 'h': 600, + 'nurl': '' } ] }; @@ -159,6 +161,40 @@ describe('marsmedia adapter tests', function () { expect(bid.cpm).to.equal(1.0); expect(bid.ttl).to.equal(600); }); + + it('interpretResponse with xml works', function() { + var bidList = { + 'body': [ + { + 'impid': 'div-gpt-ad-1438287399331-1', + 'price': 1, + 'adm': '', + 'adomain': [ + 'test.com' + ], + 'cid': '467415', + 'crid': 'cr-vid', + 'w': 800, + 'h': 600, + 'nurl': '' + } + ] + }; + + var videoBids = r1adapter.interpretResponse(bidList); + + expect(videoBids.length).to.equal(1); + const bid = videoBids[0]; + expect(bid.width).to.equal(800); + expect(bid.height).to.equal(600); + expect(bid.vastXml).to.equal(''); + expect(bid.mediaType).to.equal('video'); + expect(bid.creativeId).to.equal('cr-vid'); + expect(bid.currency).to.equal('USD'); + expect(bid.netRevenue).to.equal(true); + expect(bid.cpm).to.equal(1.0); + expect(bid.ttl).to.equal(600); + }); }); describe('misc buildRequests', function() { @@ -571,4 +607,55 @@ describe('marsmedia adapter tests', function () { expect(r1adapter.getUserSyncs()).to.deep.equal([]); }); }); + + 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/meazyBidAdapter_spec.js b/test/spec/modules/meazyBidAdapter_spec.js index 123d53f2fa1..2c24791f515 100644 --- a/test/spec/modules/meazyBidAdapter_spec.js +++ b/test/spec/modules/meazyBidAdapter_spec.js @@ -1,7 +1,7 @@ -import * as utils from 'src/utils'; +import * as utils from 'src/utils.js'; import { expect } from 'chai'; -import { spec } from 'modules/meazyBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/meazyBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const MEAZY_PID = '6910b7344ae566a1' const VALID_ENDPOINT = `https://rtb-filter.meazy.co/pbjs?host=${utils.getOrigin()}&api_key=${MEAZY_PID}`; diff --git a/test/spec/modules/mediaforceBidAdapter_spec.js b/test/spec/modules/mediaforceBidAdapter_spec.js new file mode 100644 index 00000000000..09d997e9349 --- /dev/null +++ b/test/spec/modules/mediaforceBidAdapter_spec.js @@ -0,0 +1,240 @@ +import {assert} from 'chai'; +import {spec} from 'modules/mediaforceBidAdapter.js'; +import * as utils from '../../../src/utils.js'; + +describe('mediaforce bid adapter', function () { + let sandbox; + + beforeEach(function () { + sandbox = sinon.sandbox.create(); + }); + + afterEach(function () { + sandbox.restore(); + }); + + function getLanguage() { + let language = navigator.language ? 'language' : 'userLanguage'; + return navigator[language].split('-')[0]; + } + + const language = getLanguage(); + const baseUrl = 'https://rtb.mfadsrvr.com' + + describe('isBidRequestValid()', function () { + const defaultBid = { + bidder: 'mediaforce', + params: { + property: '10433394', + bidfloor: 0.3, + }, + }; + + it('should not accept bid without required params', function () { + assert.equal(spec.isBidRequestValid(defaultBid), false); + }); + + it('should return false when params are not passed', function () { + let bid = utils.deepClone(defaultBid); + delete bid.params; + assert.equal(spec.isBidRequestValid(bid), false); + }); + + it('should return false when valid params are not passed', function () { + let bid = utils.deepClone(defaultBid); + bid.params = {placement_id: '', publisher_id: ''}; + assert.equal(spec.isBidRequestValid(bid), false); + }); + + it('should return true when valid params are passed', function () { + let bid = utils.deepClone(defaultBid); + bid.mediaTypes = { + banner: { + sizes: [[300, 250]] + } + }; + 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 () { + const defaultBid = { + bidder: 'mediaforce', + params: { + publisher_id: 'pub123', + placement_id: '202', + }, + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + transactionId: 'd45dd707-a418-42ec-b8a7-b70a6c6fab0b', + }; + + const refererInfo = { + referer: 'https://www.prebid.org', + reachedTop: true, + stack: [ + 'https://www.prebid.org/page.html', + 'https://www.prebid.org/iframe1.html', + ] + }; + + const requestUrl = `${baseUrl}/header_bid`; + const dnt = utils.getDNT() ? 1 : 0; + const secure = 1 + + it('should return undefined if no validBidRequests passed', function () { + assert.equal(spec.buildRequests([]), undefined); + }); + + it('should return proper request url: no refererInfo', function () { + let [request] = spec.buildRequests([defaultBid]); + assert.equal(request.url, requestUrl); + }); + + it('should return proper banner imp', function () { + let bid = utils.deepClone(defaultBid); + bid.params.bidfloor = 0.5; + + let bidRequests = [bid]; + let bidderRequest = {bids: bidRequests, refererInfo: refererInfo}; + + let [request] = spec.buildRequests(bidRequests, bidderRequest); + + let data = JSON.parse(request.data); + assert.deepEqual(data, { + id: bid.transactionId, + site: { + id: bid.params.publisher_id, + publisher: {id: bid.params.publisher_id}, + ref: encodeURIComponent(refererInfo.referer), + page: encodeURIComponent(refererInfo.referer), + }, + device: { + ua: navigator.userAgent, + dnt: dnt, + js: 1, + language: language, + }, + imp: [{ + tagid: bid.params.placement_id, + secure: secure, + bidfloor: bid.params.bidfloor, + banner: {w: 300, h: 250}, + }], + }); + + 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}}]}', + }); + }); + + it('multiple sizes', function () { + let bid = utils.deepClone(defaultBid); + bid.mediaTypes = { + banner: { + sizes: [[300, 600], [300, 250]], + } + }; + + let [request] = spec.buildRequests([bid]); + let data = JSON.parse(request.data); + assert.deepEqual(data.imp[0].banner, {w: 300, h: 600, format: [{w: 300, h: 250}]}); + }); + }); + + describe('interpretResponse() banner', function () { + it('not successfull response', function () { + assert.deepEqual(spec.interpretResponse(), []); + }); + + it('successfull response', function () { + let bid = { + price: 3, + w: 100, + id: '65599d0a-42d2-446a-9d39-6086c1433ffe', + burl: `${baseUrl}/burl/\${AUCTION_PRICE}`, + cid: '2_ssl', + h: 100, + cat: ['IAB1-1'], + crid: '2_ssl', + impid: '2b3c9d103723a7', + adid: '2_ssl', + adm: `` + }; + + let response = { + body: { + seatbid: [{ + bid: [bid] + }], + cur: 'USD', + id: '620190c2-7eef-42fa-91e2-f5c7fbc2bdd3' + } + }; + + let bids = spec.interpretResponse(response); + assert.deepEqual(bids, ([{ + ad: bid.adm, + cpm: bid.price, + creativeId: bid.adid, + currency: response.body.cur, + height: bid.h, + netRevenue: true, + burl: bid.burl, + requestId: bid.impid, + ttl: 300, + width: bid.w, + }])); + }); + }); + + describe('onBidWon()', function () { + beforeEach(function() { + sinon.stub(utils, 'triggerPixel'); + }); + afterEach(function() { + utils.triggerPixel.restore(); + }); + it('should expand price macros in burl', function () { + let burl = 'burl&s=${AUCTION_PRICE}'; + let bid = { + bidder: 'mediaforce', + width: 300, + height: 250, + adId: '330a22bdea4cac', + mediaType: 'banner', + cpm: 0.28, + ad: '...', + requestId: '418b37f85e772c', + adUnitCode: 'div-gpt-ad-1460505748561-0', + size: '350x250', + burl: burl, + adserverTargeting: { + hb_bidder: 'mediaforce', + hb_adid: '330a22bdea4cac', + hb_pb: '0.20', + hb_size: '350x250' + } + } + spec.onBidWon(bid); + assert.equal(bid.burl, 'burl&s=0.20'); + }); + }); +}); diff --git a/test/spec/modules/medianetAnalyticsAdapter_spec.js b/test/spec/modules/medianetAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..dcec1050652 --- /dev/null +++ b/test/spec/modules/medianetAnalyticsAdapter_spec.js @@ -0,0 +1,185 @@ +import { expect } from 'chai'; +import medianetAnalytics from 'modules/medianetAnalyticsAdapter.js'; +import * as utils from 'src/utils.js'; +import CONSTANTS from 'src/constants.json'; +import events from 'src/events.js'; + +const { + EVENTS: { AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, NO_BID, BID_TIMEOUT, AUCTION_END, SET_TARGETING, BID_WON } +} = CONSTANTS; + +const MOCK = { + AUCTION_INIT: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'timestamp': 1584563605739}, + 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'}]}, + 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'}}, + 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 performStandardAuctionWithWinner() { + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + 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 performStandardAuctionWithNoBid() { + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + 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); +} + +function performStandardAuctionWithTimeout() { + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + 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); +} + +function getQueryData(url) { + const queryArgs = url.split('?')[1].split('&'); + return queryArgs.reduce((data, arg) => { + const [key, val] = arg.split('='); + if (data[key] !== undefined) { + if (!Array.isArray(data[key])) { + data[key] = [data[key]]; + } + data[key].push(val); + } else { + data[key] = val; + } + return data; + }, {}); +} + +describe('Media.net Analytics Adapter', function() { + let sandbox; + let CUSTOMER_ID = 'test123'; + let VALID_CONFIGURATION = { + options: { + cid: CUSTOMER_ID + } + } + beforeEach(function () { + sandbox = sinon.sandbox.create(); + }); + + afterEach(function () { + sandbox.restore(); + }); + + describe('Configuration', function() { + it('should log error if publisher id is not passed', function() { + sandbox.stub(utils, 'logError'); + + medianetAnalytics.enableAnalytics(); + expect( + utils.logError.calledWith( + 'Media.net Analytics adapter: cid is required.' + ) + ).to.be.true; + }); + + it('should not log error if valid config is passed', function() { + sandbox.stub(utils, 'logError'); + + medianetAnalytics.enableAnalytics(VALID_CONFIGURATION); + expect(utils.logError.called).to.equal(false); + medianetAnalytics.disableAnalytics(); + }); + }); + + describe('Events', function() { + beforeEach(function () { + medianetAnalytics.enableAnalytics({ + options: { + cid: 'test123' + } + }); + }); + afterEach(function () { + medianetAnalytics.disableAnalytics(); + }); + + it('should not log if only Auction Init', function() { + medianetAnalytics.clearlogsQueue(); + medianetAnalytics.track({ AUCTION_INIT }) + expect(medianetAnalytics.getlogsQueue().length).to.equal(0); + }); + + it('should have winner log in standard auction', function() { + medianetAnalytics.clearlogsQueue(); + performStandardAuctionWithWinner(); + let winnerLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter((log) => log.winner); + medianetAnalytics.clearlogsQueue(); + + expect(winnerLog.length).to.equal(1); + }); + + it('should have correct values in winner log', function() { + medianetAnalytics.clearlogsQueue(); + performStandardAuctionWithWinner(); + let winnerLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter((log) => log.winner); + medianetAnalytics.clearlogsQueue(); + + expect(winnerLog[0]).to.include({ + winner: '1', + pvnm: 'medianet', + curr: 'USD', + src: 'client', + size: '300x250', + mtype: 'banner', + cid: 'test123', + lper: '1', + ogbdp: '1.1495', + flt: '1', + supcrid: 'div-gpt-ad-1460505748561-0', + mpvid: '123' + }); + }); + + it('should have no bid status', function() { + medianetAnalytics.clearlogsQueue(); + performStandardAuctionWithNoBid(); + let noBidLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)); + noBidLog = noBidLog[0]; + + medianetAnalytics.clearlogsQueue(); + expect(noBidLog.pvnm).to.have.ordered.members(['-2', 'medianet']); + expect(noBidLog.iwb).to.have.ordered.members(['0', '0']); + 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.ogbdp).to.have.ordered.members(['', '']); + expect(noBidLog.mpvid).to.have.ordered.members(['', '']); + expect(noBidLog.crid).to.have.ordered.members(['', '451466393']); + }); + + it('should have timeout status', function() { + medianetAnalytics.clearlogsQueue(); + performStandardAuctionWithTimeout(); + let timeoutLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)); + timeoutLog = timeoutLog[0]; + + medianetAnalytics.clearlogsQueue(); + expect(timeoutLog.pvnm).to.have.ordered.members(['-2', 'medianet']); + expect(timeoutLog.iwb).to.have.ordered.members(['0', '0']); + 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.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 afe91ce3166..fcfdcdf8c2f 100644 --- a/test/spec/modules/medianetBidAdapter_spec.js +++ b/test/spec/modules/medianetBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; -import {spec} from 'modules/medianetBidAdapter'; -import { config } from 'src/config'; +import {spec} from 'modules/medianetBidAdapter.js'; +import { config } from 'src/config.js'; let VALID_BID_REQUEST = [{ 'bidder': 'medianet', @@ -87,6 +87,52 @@ let VALID_BID_REQUEST = [{ 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', 'bidRequestsCount': 1 }], + VALID_BID_REQUEST_WITH_USERID = [{ + 'bidder': 'medianet', + 'params': { + 'crid': 'crid', + 'cid': 'customer_id', + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'isTop': true + } + }, + userId: { + britepoolid: '82efd5e1-816b-4f87-97f8-044f407e2911' + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'transactionId': '277b631f-92f5-4844-8b19-ea13c095d3f1', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]], + } + }, + 'bidId': '28f8f8130a583e', + 'bidderRequestId': '1e9b1f07797c1c', + 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'bidRequestsCount': 1 + }, { + 'bidder': 'medianet', + 'params': { + 'crid': 'crid', + 'cid': 'customer_id', + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'isTop': true + } + }, + 'adUnitCode': 'div-gpt-ad-1460505748561-123', + 'transactionId': 'c52a5c62-3c2b-4b90-9ff8-ec1487754822', + 'sizes': [[300, 251]], + 'bidId': '3f97ca71b1e5c2', + 'bidderRequestId': '1e9b1f07797c1c', + 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'bidRequestsCount': 1 + }], VALID_BID_REQUEST_INVALID_BIDFLOOR = [{ 'bidder': 'medianet', @@ -263,6 +309,7 @@ let VALID_BID_REQUEST = [{ 'prebid_version': $$PREBID_GLOBAL$$.version, 'gdpr_applies': false, 'usp_applies': false, + 'coppa_applies': false, 'screen': { 'w': 1000, 'h': 1000 @@ -347,6 +394,7 @@ let VALID_BID_REQUEST = [{ 'prebid_version': $$PREBID_GLOBAL$$.version, 'gdpr_applies': false, 'usp_applies': false, + 'coppa_applies': false, 'screen': { 'w': 1000, 'h': 1000 @@ -432,6 +480,94 @@ let VALID_BID_REQUEST = [{ 'prebid_version': $$PREBID_GLOBAL$$.version, 'gdpr_applies': false, 'usp_applies': false, + 'coppa_applies': false, + 'screen': { + 'w': 1000, + 'h': 1000 + } + }, + 'id': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', + 'imp': [{ + 'id': '28f8f8130a583e', + 'ext': { + 'dfp_id': 'div-gpt-ad-1460505748561-0', + 'visibility': 1, + 'viewability': 1, + 'coordinates': { + 'top_left': { + x: 50, + y: 50 + }, + 'bottom_right': { + x: 100, + y: 100 + } + }, + 'display_count': 1 + }, + 'banner': [{ + 'w': 300, + 'h': 250 + }], + 'all': { + 'cid': 'customer_id', + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'isTop': true + } + } + }, { + 'id': '3f97ca71b1e5c2', + 'ext': { + 'dfp_id': 'div-gpt-ad-1460505748561-123', + 'visibility': 1, + 'viewability': 1, + 'coordinates': { + 'top_left': { + x: 50, + y: 50 + }, + 'bottom_right': { + x: 100, + y: 100 + } + }, + 'display_count': 1 + }, + 'banner': [{ + 'w': 300, + 'h': 251 + }], + 'all': { + 'cid': 'customer_id', + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'isTop': true + } + } + }], + 'tmax': config.getConfig('bidderTimeout') + }, + VALID_PAYLOAD_WITH_USERID = { + 'site': { + 'page': 'http://media.net/prebidtest', + 'domain': 'media.net', + 'ref': 'http://media.net/prebidtest', + 'isTop': true + }, + 'ext': { + 'customer_id': 'customer_id', + 'prebid_version': $$PREBID_GLOBAL$$.version, + 'gdpr_applies': false, + 'user_id': { + britepoolid: '82efd5e1-816b-4f87-97f8-044f407e2911' + }, + 'usp_applies': false, + 'coppa_applies': false, 'screen': { 'w': 1000, 'h': 1000 @@ -440,6 +576,7 @@ let VALID_BID_REQUEST = [{ 'id': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', 'imp': [{ 'id': '28f8f8130a583e', + 'tagid': 'crid', 'ext': { 'dfp_id': 'div-gpt-ad-1460505748561-0', 'visibility': 1, @@ -462,6 +599,7 @@ let VALID_BID_REQUEST = [{ }], 'all': { 'cid': 'customer_id', + 'crid': 'crid', 'site': { 'page': 'http://media.net/prebidtest', 'domain': 'media.net', @@ -471,6 +609,7 @@ let VALID_BID_REQUEST = [{ } }, { 'id': '3f97ca71b1e5c2', + 'tagid': 'crid', 'ext': { 'dfp_id': 'div-gpt-ad-1460505748561-123', 'visibility': 1, @@ -493,6 +632,7 @@ let VALID_BID_REQUEST = [{ }], 'all': { 'cid': 'customer_id', + 'crid': 'crid', 'site': { 'page': 'http://media.net/prebidtest', 'domain': 'media.net', @@ -515,6 +655,7 @@ let VALID_BID_REQUEST = [{ 'prebid_version': $$PREBID_GLOBAL$$.version, 'gdpr_applies': false, 'usp_applies': false, + 'coppa_applies': true, 'screen': { 'w': 1000, 'h': 1000 @@ -856,6 +997,7 @@ let VALID_BID_REQUEST = [{ 'gdpr_consent_string': 'consentString', 'gdpr_applies': true, 'usp_applies': true, + 'coppa_applies': false, 'usp_consent_string': '1NYN', 'screen': { 'w': 1000, @@ -967,6 +1109,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, @@ -1013,10 +1157,21 @@ describe('Media.net bid adapter', function () { }); it('should have valid crid present in bid request', function() { + sandbox.stub(config, 'getConfig').callsFake((key) => { + const config = { + 'coppa': true + }; + return config[key]; + }); let bidreq = spec.buildRequests(VALID_BID_REQUEST_WITH_CRID, VALID_AUCTIONDATA); expect(JSON.parse(bidreq.data)).to.deep.equal(VALID_PAYLOAD_WITH_CRID); }); + it('should have userid in bid request', function () { + let bidReq = spec.buildRequests(VALID_BID_REQUEST_WITH_USERID, VALID_AUCTIONDATA); + expect(JSON.parse(bidReq.data)).to.deep.equal(VALID_PAYLOAD_WITH_USERID); + }); + describe('build requests: when page meta-data is available', () => { beforeEach(() => { spec.clearMnData(); diff --git a/test/spec/modules/mediasquareBidAdapter_spec.js b/test/spec/modules/mediasquareBidAdapter_spec.js new file mode 100644 index 00000000000..351fbb40228 --- /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': '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/mgidBidAdapter_spec.js b/test/spec/modules/mgidBidAdapter_spec.js index fbf58254d39..16f4f0b4607 100644 --- a/test/spec/modules/mgidBidAdapter_spec.js +++ b/test/spec/modules/mgidBidAdapter_spec.js @@ -1,7 +1,6 @@ import {assert, expect} from 'chai'; -import {spec} from 'modules/mgidBidAdapter'; -import * as utils from '../../../src/utils'; -import * as urlUtils from '../../../src/url'; +import {spec} from 'modules/mgidBidAdapter.js'; +import * as utils from '../../../src/utils.js'; describe('Mgid bid adapter', function () { let sandbox; @@ -361,7 +360,7 @@ describe('Mgid bid adapter', function () { }; let bidRequests = [bid]; const page = top.location.href; - const domain = urlUtils.parse(page).hostname; + const domain = utils.parseUrl(page).hostname; const request = spec.buildRequests(bidRequests); expect(request.url).deep.equal('https://prebid.mgid.com/prebid/1'); expect(request.method).deep.equal('POST'); @@ -409,7 +408,7 @@ describe('Mgid bid adapter', function () { let bidRequests = [bid]; const page = top.location.href; - const domain = urlUtils.parse(page).hostname; + const domain = utils.parseUrl(page).hostname; const request = spec.buildRequests(bidRequests); expect(request).to.be.a('object'); expect(request.url).deep.equal('https://prebid.mgid.com/prebid/1'); @@ -446,7 +445,7 @@ describe('Mgid bid adapter', function () { let bidRequests = [bid]; const page = top.location.href; - const domain = urlUtils.parse(page).hostname; + const domain = utils.parseUrl(page).hostname; const request = spec.buildRequests(bidRequests); expect(request).to.be.a('object'); expect(request.url).deep.equal('https://prebid.mgid.com/prebid/1'); @@ -482,7 +481,7 @@ describe('Mgid bid adapter', function () { let bidRequests = [bid]; const page = top.location.href; - const domain = urlUtils.parse(page).hostname; + const domain = utils.parseUrl(page).hostname; const request = spec.buildRequests(bidRequests); expect(request).to.be.a('object'); expect(request.url).deep.equal('https://prebid.mgid.com/prebid/1'); @@ -516,7 +515,7 @@ describe('Mgid bid adapter', function () { const request = spec.buildRequests(bidRequests); const page = top.location.href; - const domain = urlUtils.parse(page).hostname; + const domain = utils.parseUrl(page).hostname; expect(request.url).deep.equal('https://prebid.mgid.com/prebid/1'); expect(request.method).deep.equal('POST'); const data = JSON.parse(request.data); diff --git a/test/spec/modules/microadBidAdapter_spec.js b/test/spec/modules/microadBidAdapter_spec.js index b80a6938425..8298e2bd559 100644 --- a/test/spec/modules/microadBidAdapter_spec.js +++ b/test/spec/modules/microadBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/microadBidAdapter'; -import * as utils from 'src/utils'; +import { spec } from 'modules/microadBidAdapter.js'; +import * as utils from 'src/utils.js'; describe('microadBidAdapter', () => { const bidRequestTemplate = { diff --git a/test/spec/modules/mobsmartBidAdapter_spec.js b/test/spec/modules/mobsmartBidAdapter_spec.js index 7c1128276ab..b48878adff6 100644 --- a/test/spec/modules/mobsmartBidAdapter_spec.js +++ b/test/spec/modules/mobsmartBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/mobsmartBidAdapter'; +import { spec } from 'modules/mobsmartBidAdapter.js'; describe('mobsmartBidAdapter', function () { describe('isBidRequestValid', function () { diff --git a/test/spec/modules/my6senseBidAdapter_spec.js b/test/spec/modules/my6senseBidAdapter_spec.js index d2c875dad07..5e51280d70b 100644 --- a/test/spec/modules/my6senseBidAdapter_spec.js +++ b/test/spec/modules/my6senseBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/my6senseBidAdapter'; +import { spec } from 'modules/my6senseBidAdapter.js'; describe('My6sense Bid adapter test', function () { let bidRequests, serverResponses; diff --git a/test/spec/modules/mytargetBidAdapter_spec.js b/test/spec/modules/mytargetBidAdapter_spec.js index 01a94e76d60..ea998303fe3 100644 --- a/test/spec/modules/mytargetBidAdapter_spec.js +++ b/test/spec/modules/mytargetBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { config } from 'src/config'; -import { spec } from 'modules/mytargetBidAdapter'; +import { config } from 'src/config.js'; +import { spec } from 'modules/mytargetBidAdapter.js'; describe('MyTarget Adapter', function() { describe('isBidRequestValid', function () { diff --git a/test/spec/modules/nafdigitalBidAdapter_spec.js b/test/spec/modules/nafdigitalBidAdapter_spec.js index ca486c632c7..c8ffb9fbbaf 100644 --- a/test/spec/modules/nafdigitalBidAdapter_spec.js +++ b/test/spec/modules/nafdigitalBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; -import * as utils from 'src/utils'; -import { spec } from 'modules/nafdigitalBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import * as utils from 'src/utils.js'; +import { spec } from 'modules/nafdigitalBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const URL = 'https://nafdigitalbidder.com/hb'; diff --git a/test/spec/modules/nanointeractiveBidAdapter_spec.js b/test/spec/modules/nanointeractiveBidAdapter_spec.js index f999c2a4656..715a26a4597 100644 --- a/test/spec/modules/nanointeractiveBidAdapter_spec.js +++ b/test/spec/modules/nanointeractiveBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import * as utils from 'src/utils'; +import * as utils from 'src/utils.js'; import * as sinon from 'sinon'; import { @@ -13,7 +13,7 @@ import { REF, spec, SUB_ID -} from '../../../modules/nanointeractiveBidAdapter'; +} from '../../../modules/nanointeractiveBidAdapter.js'; describe('nanointeractive adapter tests', function () { const SIZES_PARAM = 'sizes'; diff --git a/test/spec/modules/nasmediaAdmixerBidAdapter_spec.js b/test/spec/modules/nasmediaAdmixerBidAdapter_spec.js index 969c819ebef..4731b1a77d3 100644 --- a/test/spec/modules/nasmediaAdmixerBidAdapter_spec.js +++ b/test/spec/modules/nasmediaAdmixerBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; -import {spec} from 'modules/nasmediaAdmixerBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; +import {spec} from 'modules/nasmediaAdmixerBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; describe('nasmediaAdmixerBidAdapter', function () { const adapter = newBidder(spec); diff --git a/test/spec/modules/newborntownWebBidAdapter_spec.js b/test/spec/modules/newborntownWebBidAdapter_spec.js index d7cf4a7dd95..3d3285328fe 100644 --- a/test/spec/modules/newborntownWebBidAdapter_spec.js +++ b/test/spec/modules/newborntownWebBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import {spec} from 'modules/newborntownWebBidAdapter'; +import {spec} from 'modules/newborntownWebBidAdapter.js'; describe('NewborntownWebAdapter', function() { describe('isBidRequestValid', function () { let bid = { @@ -54,8 +54,8 @@ describe('NewborntownWebAdapter', function() { 'timeout': 9000, 'start': 1573123289383 } - const request = spec.buildRequests(bidderRequest['bids'], bidderRequest); it('Returns POST method', function () { + const request = spec.buildRequests(bidderRequest['bids'], bidderRequest); expect(request[0].method).to.equal('POST'); expect(request[0].url.indexOf('//us-west.solortb.com/adx/api/rtb?from=4') !== -1).to.equal(true); expect(request[0].data).to.exist; diff --git a/test/spec/modules/nextMillenniumBidAdapter_spec.js b/test/spec/modules/nextMillenniumBidAdapter_spec.js index 087f06d7e8e..f4d929b439c 100644 --- a/test/spec/modules/nextMillenniumBidAdapter_spec.js +++ b/test/spec/modules/nextMillenniumBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/nextMillenniumBidAdapter'; +import { spec } from 'modules/nextMillenniumBidAdapter.js'; describe('nextMillenniumBidAdapterTests', function() { let bidRequestData = { diff --git a/test/spec/modules/nextrollBidAdapter_spec.js b/test/spec/modules/nextrollBidAdapter_spec.js new file mode 100644 index 00000000000..7722443e584 --- /dev/null +++ b/test/spec/modules/nextrollBidAdapter_spec.js @@ -0,0 +1,268 @@ +import { expect } from 'chai'; +import { spec, tryGetPubtag, hasCCPAConsent } from 'modules/nextrollBidAdapter.js'; +import * as utils from 'src/utils.js'; + +describe('nextrollBidAdapter', function() { + let utilsMock; + beforeEach(function () { + utilsMock = sinon.mock(utils); + }); + + afterEach(function() { + global.NextRoll = undefined; + utilsMock.restore(); + }); + + let validBid = { + bidder: 'nextroll', + adUnitCode: 'adunit-code', + bidId: 'bid_id', + sizes: [[300, 200]], + params: { + bidfloor: 1, + zoneId: 'zone1', + publisherId: 'publisher_id' + } + }; + 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; + }); + + it('validates the bids correcly when the bid does not have an id', function() { + expect(spec.isBidRequestValid(bidWithoutValidId)).to.be.false; + expect(spec.isBidRequestValid(bidWithoutId)).to.be.false; + }); + }); + + describe('buildRequests', function() { + it('builds the same amount of requests as valid requests it takes', function() { + expect(spec.buildRequests([validBid, validBid], {})).to.be.lengthOf(2); + }); + + it('doest not build a request when there is no valid requests', function () { + expect(spec.buildRequests([], {})).to.be.lengthOf(0); + }); + + it('builds a request with POST method', function () { + expect(spec.buildRequests([validBid], {})[0].method).to.equal('POST'); + }); + + it('builds a request with cookies method', function () { + expect(spec.buildRequests([validBid], {})[0].options.withCredentials).to.be.true; + }); + + it('builds a request with id, url and imp object', function () { + const request = spec.buildRequests([validBid], {})[0]; + expect(request.data.id).to.be.an('string').that.is.not.empty; + expect(request.url).to.equal('https://d.adroll.com/bid/prebid/'); + expect(request.data.imp).to.exist.and.to.be.a('object'); + }); + + it('builds a request with site and device information', function () { + const request = spec.buildRequests([validBid], {})[0]; + + expect(request.data.site).to.exist.and.to.be.a('object'); + expect(request.data.device).to.exist.and.to.be.a('object'); + }); + + it('builds a request with a complete imp object', function () { + const request = spec.buildRequests([validBid], {})[0]; + + expect(request.data.imp.id).to.equal('bid_id'); + expect(request.data.imp.bidfloor).to.be.equal(1); + expect(request.data.imp.banner).to.exist.and.to.be.a('object'); + expect(request.data.imp.ext.zone.id).to.be.equal('zone1'); + }); + + it('includes the sizes into the request correctly', function () { + const bannerObject = spec.buildRequests([validBid], {})[0].data.imp.banner; + + expect(bannerObject.format).to.exist; + expect(bannerObject.format).to.be.lengthOf(1); + 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 () { + let responseBody = { + id: 'bidresponse_id', + dealId: 'deal_id', + seatbid: [ + { + bid: [ + { + price: 1.2, + w: 300, + h: 200, + crid: 'crid1', + adm: 'adm1' + } + ] + }, + { + bid: [ + { + price: 2.1, + w: 250, + h: 300, + crid: 'crid2', + adm: 'adm2' + } + ] + } + ] + }; + + it('returns an empty list when there is no response body', function () { + expect(spec.interpretResponse({}, {})).to.be.eql([]); + }); + + it('builds the same amount of responses as server responses it receives', function () { + expect(spec.interpretResponse({body: responseBody}, {})).to.be.lengthOf(2); + }); + + it('builds a response with the expected fields', function () { + const response = spec.interpretResponse({body: responseBody}, {})[0]; + + expect(response.requestId).to.be.equal('bidresponse_id'); + expect(response.cpm).to.be.equal(1.2); + expect(response.width).to.be.equal(300); + expect(response.height).to.be.equal(200); + expect(response.creativeId).to.be.equal('crid1'); + expect(response.dealId).to.be.equal('deal_id'); + expect(response.currency).to.be.equal('USD'); + expect(response.netRevenue).to.be.equal(true); + expect(response.ttl).to.be.equal(300); + expect(response.ad).to.be.equal('adm1'); + }); + }); + + 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' + + 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] + } + }] + }] + } + }; + + 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: [] + } + + expect(response[0].native).to.be.deep.equal(expectedResponse) + }) + + 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 fef2fefdfc4..3b8fd32160b 100644 --- a/test/spec/modules/nobidBidAdapter_spec.js +++ b/test/spec/modules/nobidBidAdapter_spec.js @@ -1,7 +1,8 @@ import { expect } from 'chai'; -import { spec } from 'modules/nobidBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; -import { deepClone } from 'src/utils'; +import * as utils from 'src/utils.js'; +import { spec } from 'modules/nobidBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import * as bidderFactory from 'src/adapters/bidderFactory.js'; describe('Nobid Adapter', function () { const adapter = newBidder(spec); @@ -49,6 +50,184 @@ describe('Nobid Adapter', function () { }); }); + 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: 'instream' + } + } + }; + 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: 'instream' + } + } + } + ]; + + 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); + 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; + 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); + 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; + 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('buildRequests', function () { const SITE_ID = 2; const REFERER = 'https://www.examplereferer.com'; @@ -70,7 +249,7 @@ describe('Nobid Adapter', function () { refererInfo: {referer: REFERER} } - it('should add source and verison to the tag', function () { + 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); @@ -281,6 +460,109 @@ describe('Nobid Adapter', function () { }); }); + describe('buildRequestsWithSupplyChain', function () { + const SITE_ID = 2; + let bidRequests = [ + { + bidder: 'nobid', + params: { + siteId: SITE_ID + }, + adUnitCode: 'adunit-code', + sizes: [[300, 250]], + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + coppa: true, + schain: { + validation: 'strict', + config: { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + name: 'name.com', + hp: 1 + } + ] + } + } + } + ]; + + it('schain exist', function () { + const request = spec.buildRequests(bidRequests); + const payload = JSON.parse(request.data); + expect(payload.schain).to.exist; + expect(payload.schain.validation).to.exist.and.to.equal('strict'); + expect(payload.schain.config.ver).to.exist.and.to.equal('1.0'); + expect(payload.schain.config.complete).to.exist.and.to.equal(1); + expect(payload.schain.config.nodes[0].asi).to.exist.and.to.equal('indirectseller.com'); + expect(payload.schain.config.nodes[0].sid).to.exist.and.to.equal('00001'); + expect(payload.schain.config.nodes[0].name).to.exist.and.to.equal('name.com'); + expect(payload.schain.config.nodes[0].hp).to.exist.and.to.equal(1); + expect(payload.coppa).to.exist; + expect(payload.coppa).to.exist.and.to.be.true; + expect(payload.a).to.be.lengthOf(1); + expect(request.method).to.equal('POST'); + }); + }); + + describe('interpretResponseWithUserLimit', function () { + const CREATIVE_ID_300x250 = 'CREATIVE-100'; + const ADUNIT_300x250 = 'ADUNIT-1'; + const ADMARKUP_300x250 = 'ADMARKUP-300x250'; + const PRICE_300x250 = 0.51; + const REQUEST_ID = '3db3773286ee59'; + const DEAL_ID = 'deal123'; + const ULIMIT = 1; + let response = { + country: 'US', + ip: '68.83.15.75', + device: 'COMPUTER', + site: 2, + ublock: ULIMIT, + bids: [ + {id: 1, + bdrid: 101, + divid: ADUNIT_300x250, + dealid: DEAL_ID, + creativeid: CREATIVE_ID_300x250, + size: {'w': 300, 'h': 250}, + adm: ADMARKUP_300x250, + price: '' + PRICE_300x250 + } + ] + }; + + it('should ULimit be respected', function () { + const bidderRequest = { + bids: [{ + bidId: REQUEST_ID, + adUnitCode: ADUNIT_300x250 + }] + } + const bidRequests = [ + { + 'bidder': 'nobid', + 'params': { + 'siteId': 2 + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + } + ]; + spec.interpretResponse({ body: response }, {bidderRequest: bidderRequest}); + let request = spec.buildRequests(bidRequests, bidderRequest); + expect(request).to.equal(undefined); + }); + }); + describe('getUserSyncs', function () { const GDPR_CONSENT_STRING = 'GDPR_CONSENT_STRING'; it('should get correct user sync when iframeEnabled', function () { @@ -306,6 +588,13 @@ describe('Nobid Adapter', function () { expect(pixel.length).to.equal(0); }); + it('should get correct user sync when !iframeEnabled and pixelEnabled', function () { + let pixel = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [{body: {syncs: ['sync_url']}}]) + expect(pixel.length).to.equal(1); + expect(pixel[0].type).to.equal('image'); + expect(pixel[0].url).to.equal('sync_url'); + }); + it('should get correct user sync when !iframeEnabled', function () { let pixel = spec.getUserSyncs({}) expect(pixel.length).to.equal(0); diff --git a/test/spec/modules/oneVideoBidAdapter_spec.js b/test/spec/modules/oneVideoBidAdapter_spec.js index 82f7ca91091..a91e9ac27e8 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'; -import * as utils from 'src/utils'; -import {config} from 'src/config'; +import { spec } from 'modules/oneVideoBidAdapter.js'; +import * as utils from 'src/utils.js'; describe('OneVideoBidAdapter', function () { let bidRequest; @@ -47,6 +46,7 @@ describe('OneVideoBidAdapter', function () { sid: 134, rewarded: 1, placement: 1, + hp: 1, inventoryid: 123 }, site: { @@ -90,7 +90,7 @@ describe('OneVideoBidAdapter', function () { }; expect(spec.isBidRequestValid(bidRequest)).to.equal(false); }); - it('should return true when the "pubId" param is missing', function () { + it('should return true when the "pubId" param exists', function () { bidRequest.params = { video: { playerWidth: 480, @@ -115,6 +115,87 @@ describe('OneVideoBidAdapter', function () { bidRequest.params = {}; expect(spec.isBidRequestValid(bidRequest)).to.equal(false); }); + + it('should return false when the mediaType is "banner" and display="undefined" (DAP 3P)', function () { + bidRequest = { + mediaTypes: { + banner: { + sizes: [640, 480] + } + } + } + expect(spec.isBidRequestValid(bidRequest)).to.equal(false); + }) + + it('should return true when the mediaType is "banner" and display=1 (DAP 3P)', function () { + bidRequest = { + mediaTypes: { + banner: { + sizes: [640, 480] + } + }, + bidder: 'oneVideo', + sizes: [640, 480], + bidId: '30b3efwfwe1e', + adUnitCode: 'video1', + params: { + video: { + playerWidth: 640, + playerHeight: 480, + mimes: ['video/mp4', 'application/javascript'], + protocols: [2, 5], + api: [2], + position: 1, + delivery: [2], + playbackmethod: [1, 5], + sid: 134, + rewarded: 1, + placement: 1, + inventoryid: 123, + display: 1 + }, + site: { + id: 1, + page: 'https://news.yahoo.com/portfolios', + referrer: 'http://www.yahoo.com' + }, + pubId: 'brxd' + } + }; + expect(spec.isBidRequestValid(bidRequest)).to.equal(true); + }) + + it('should return false when the mediaType is "video" and context="outstream" and display=1 (DAP 3P)', function () { + bidRequest = { + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480] + } + }, + params: { + video: { + display: 1 + } + } + } + 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 () { @@ -136,12 +217,15 @@ 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.3'; 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); expect(data.imp[0].ext.rewarded).to.equal(rewarded); expect(data.imp[0].video.placement).to.equal(placement); expect(data.imp[0].ext.inventoryid).to.equal(inventoryid); + expect(data.imp[0].ext.prebidver).to.equal('$prebid.version$'); + expect(data.imp[0].ext.adapterver).to.equal(VERSION); }); it('must parse bid size from a nested array', function () { @@ -153,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 () { @@ -173,7 +335,7 @@ describe('OneVideoBidAdapter', function () { expect(bidResponse.length).to.equal(0); }); - it('should return a valid bid response with just "adm"', function () { + it('should return a valid video bid response with just "adm"', function () { const serverResponse = {seatbid: [{bid: [{id: 1, adid: 123, crid: 2, price: 6.01, adm: ''}]}], cur: 'USD'}; const bidResponse = spec.interpretResponse({ body: serverResponse }, { bidRequest }); let o = { @@ -194,6 +356,26 @@ describe('OneVideoBidAdapter', function () { }; expect(bidResponse).to.deep.equal(o); }); + // @abrowning14 check that banner DAP response is appended to o.ad + mediaType: 'banner' + it('should return a valid DAP banner bid-response', function () { + bidRequest = { + mediaTypes: { + banner: { + sizes: [640, 480] + } + }, + params: { + video: { + display: 1 + } + } + } + const serverResponse = {seatbid: [{bid: [{id: 1, adid: 123, crid: 2, price: 6.01, adm: '
DAP UNIT HERE
'}]}], cur: 'USD'}; + const bidResponse = spec.interpretResponse({ body: serverResponse }, { bidRequest }); + expect(bidResponse.ad).to.equal('
DAP UNIT HERE
'); + expect(bidResponse.mediaType).to.equal('banner'); + expect(bidResponse.renderer).to.be.undefined; + }); }); describe('when GDPR and uspConsent applies', function () { @@ -255,16 +437,10 @@ 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', function () { + it('should send banner object when display is 1 and context="instream" (DAP O&O)', function () { bidRequest = { mediaTypes: { video: { @@ -289,7 +465,9 @@ describe('OneVideoBidAdapter', function () { placement: 1, inventoryid: 123, sid: 134, - display: 1 + display: 1, + minduration: 10, + maxduration: 30 }, site: { id: 1, @@ -311,9 +489,11 @@ describe('OneVideoBidAdapter', function () { expect(data.imp[0].ext.inventoryid).to.equal(bidRequest.params.video.inventoryid); expect(data.imp[0].banner.mimes).to.equal(bidRequest.params.video.mimes); expect(data.imp[0].banner.placement).to.equal(bidRequest.params.video.placement); + expect(data.imp[0].banner.ext.minduration).to.equal(bidRequest.params.video.minduration); + expect(data.imp[0].banner.ext.maxduration).to.equal(bidRequest.params.video.maxduration); expect(data.site.id).to.equal(bidRequest.params.site.id); }); - it('should send video object when display is other than 1', function () { + it('should send video object when display is other than 1 (VAST for All)', function () { bidRequest = { mediaTypes: { video: { @@ -358,7 +538,7 @@ describe('OneVideoBidAdapter', function () { expect(data.imp[0].video.pos).to.equal(position); expect(data.imp[0].video.mimes).to.equal(bidRequest.params.video.mimes); }); - it('should send video object when display is not passed', function () { + it('should send video object when display is not passed (VAST for All)', function () { bidRequest = { mediaTypes: { video: { @@ -381,7 +561,9 @@ describe('OneVideoBidAdapter', function () { delivery: [2], playbackmethod: [1, 5], placement: 123, - sid: 134 + sid: 134, + minduration: 10, + maxduration: 30 }, site: { id: 1, @@ -401,6 +583,10 @@ describe('OneVideoBidAdapter', function () { expect(data.imp[0].video.h).to.equal(height); expect(data.imp[0].video.pos).to.equal(position); expect(data.imp[0].video.mimes).to.equal(bidRequest.params.video.mimes); + expect(data.imp[0].video.protocols).to.equal(bidRequest.params.video.protocols); + expect(data.imp[0].video.linearity).to.equal(1); + expect(data.imp[0].video.maxduration).to.equal(bidRequest.params.video.maxduration); + expect(data.imp[0].video.minduration).to.equal(bidRequest.params.video.minduration); }); describe('getUserSyncs', function () { const GDPR_CONSENT_STRING = 'GDPR_CONSENT_STRING'; @@ -410,6 +596,11 @@ describe('OneVideoBidAdapter', function () { 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)); }); + + 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='); + }); }); }); }); diff --git a/test/spec/modules/onetagBidAdapter_spec.js b/test/spec/modules/onetagBidAdapter_spec.js index 93284566069..a951c74b20b 100644 --- a/test/spec/modules/onetagBidAdapter_spec.js +++ b/test/spec/modules/onetagBidAdapter_spec.js @@ -1,40 +1,119 @@ -import { spec } from 'modules/onetagBidAdapter'; +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 () { - let bid = { - 'bidder': 'onetag', - 'params': { - 'pubId': '386276e072', - }, - 'adUnitCode': 'adunit-code', - 'sizes': [[300, 250]], - 'bidId': '30b31c1838de1e', - 'bidderRequestId': '22edbae2733bf6', - 'auctionId': '1d1a030790a475', - 'transactionId': 'qwerty123' - }; + function createBid() { + return { + 'bidder': 'onetag', + 'params': { + 'pubId': '386276e072', + }, + 'adUnitCode': 'adunit-code', + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'transactionId': 'qwerty123' + }; + } + + function createBannerBid(bidRequest) { + const bid = bidRequest || createBid(); + bid.mediaTypes = bid.mediaTypes || {}; + bid.mediaTypes.banner = { + sizes: [[300, 250]] + }; + return bid; + } + + function createInstreamVideoBid(bidRequest) { + const bid = bidRequest || createBid(); + bid.mediaTypes = bid.mediaTypes || {}; + bid.mediaTypes.video = { + context: 'instream', + mimes: ['video/mp4', 'video/webm', 'application/javascript', 'video/ogg'], + playerSize: [640, 480] + }; + return bid; + } + + function createOutstreamVideoBid(bidRequest) { + const bid = bidRequest || createBid(); + bid.mediaTypes = bid.mediaTypes || {}; + bid.mediaTypes.video = { + context: 'outstream', + mimes: ['video/mp4', 'video/webm', 'application/javascript', 'video/ogg'], + playerSize: [640, 480] + }; + return bid; + } + + function createMultiFormatBid() { + return createInstreamVideoBid(createBannerBid()); + } + + const bannerBid = createBannerBid(); + const instreamVideoBid = createInstreamVideoBid(); + const outstreamVideoBid = createOutstreamVideoBid(); describe('isBidRequestValid', function () { it('Should return true when required params are found', function () { - expect(spec.isBidRequestValid(bid)).to.be.true; + expect(spec.isBidRequestValid(bannerBid)).to.be.true; }); it('Should return false when pubId is not a string', function () { - bid.params.pubId = 30; - expect(spec.isBidRequestValid(bid)).to.be.false; + bannerBid.params.pubId = 30; + expect(spec.isBidRequestValid(bannerBid)).to.be.false; }); it('Should return false when pubId is undefined', function () { - bid.params.pubId = undefined; - expect(spec.isBidRequestValid(bid)).to.be.false; + bannerBid.params.pubId = undefined; + expect(spec.isBidRequestValid(bannerBid)).to.be.false; }); - it('Should return false when the sizes array is empty', function () { - bid.sizes = []; - expect(spec.isBidRequestValid(bid)).to.be.false; + describe('banner bidRequest', function () { + it('Should return false when the sizes array is empty', function () { + bannerBid.sizes = []; + expect(spec.isBidRequestValid(bannerBid)).to.be.false; + }); + }); + describe('video bidRequest', function () { + it('Should return false when the context is undefined', function () { + 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 () { + instreamVideoBid.mediaTypes.video.context = 'wrong'; + expect(spec.isBidRequestValid(instreamVideoBid)).to.be.false; + }); + it('Should return false when playerSize is undefined', function () { + 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 = 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 = createInstreamVideoBid(); + videoBid.mediaTypes.video.playerSize = []; + expect(spec.isBidRequestValid(videoBid)).to.be.false; + }); + it('Should return true when context is outstream', function () { + expect(spec.isBidRequestValid(outstreamVideoBid)).to.be.true; + }); + }); + describe('multi format bidRequest', function () { + const multiFormatBid = createMultiFormatBid(); + it('Should return true when correct multi format bid is passed', function () { + expect(spec.isBidRequestValid(multiFormatBid)).to.be.true; + }); }); }); describe('buildRequests', function () { - let serverRequest = spec.buildRequests([bid]); + 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; @@ -51,9 +130,9 @@ 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'); + 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', 'onetagSid'); expect(data.location).to.be.a('string'); expect(data.masked).to.be.a('number'); expect(data.referrer).to.be.a('string'); @@ -68,30 +147,27 @@ 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'); - const bids = data['bids']; for (let i = 0; i < bids.length; i++) { const bid = bids[i]; - expect(bid).to.have.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'pubId', 'transactionId', 'sizes'); + if (hasTypeVideo(bid)) { + expect(bid).to.have.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'pubId', 'transactionId', 'context', 'mimes', 'playerSize', 'protocols', 'maxDuration', 'api', 'type'); + } else if (isValid(BANNER, bid)) { + expect(bid).to.have.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'pubId', 'transactionId', 'sizes', 'type'); + } expect(bid.bidId).to.be.a('string'); expect(bid.pubId).to.be.a('string'); } }); - } catch (e) { - console.log('Error while parsing'); - } + } catch (e) {} it('Returns empty data if no valid requests are passed', function () { serverRequest = spec.buildRequests([]); let dataString = serverRequest.data; try { let dataObj = JSON.parse(dataString); expect(dataObj.bids).to.be.an('array').that.is.empty; - } catch (e) { - console.log('Error while parsing'); - } + } catch (e) {} }); it('should send GDPR consent data', function () { let consentString = 'consentString'; @@ -105,7 +181,7 @@ describe('onetag', function () { gdprApplies: true } }; - let serverRequest = spec.buildRequests([bid], bidderRequest); + let serverRequest = spec.buildRequests([bannerBid], bidderRequest); const payload = JSON.parse(serverRequest.data); expect(payload).to.exist; @@ -113,44 +189,61 @@ 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 () { + let consentString = 'us_foo'; + let bidderRequest = { + 'bidderCode': 'onetag', + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'uspConsent': consentString + }; + let serverRequest = spec.buildRequests([bannerBid], bidderRequest); + const payload = JSON.parse(serverRequest.data); + + expect(payload.usPrivacy).to.exist; + expect(payload.usPrivacy).to.exist.and.to.equal(consentString); + }); }); describe('interpretResponse', function () { - const resObject = { - body: { - nobid: false, - bids: [{ - ad: '
Advertising
', - cpm: 13, - width: 300, - height: 250, - creativeId: '1820', - dealId: 'dishfo', - currency: 'USD', - requestId: 'sdiceobxcw' - }] - } - }; + 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(resObject); - - 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', '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'); - 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 () { @@ -204,5 +297,114 @@ describe('onetag', function () { expect(syncs[0].url).to.include(sync_endpoint); expect(syncs[0].url).to.not.match(/(?:[?&](?:gdpr_consent=([^&]*)|gdpr=([^&]*)))+$/); }); + it('Should send us privacy string', function () { + let usConsentString = 'us_foo'; + const syncs = spec.getUserSyncs({ iframeEnabled: true }, {}, {}, usConsentString); + expect(syncs[0].type).to.equal('iframe'); + expect(syncs[0].url).to.include(sync_endpoint); + expect(syncs[0].url).to.match(/(?:[?&](?:us_privacy=us_foo(?:[&][^&]*)*))+$/); + }); }); }); + +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/open8BidAdapter_spec.js b/test/spec/modules/open8BidAdapter_spec.js index 7ef1c38abb2..506742bef9e 100644 --- a/test/spec/modules/open8BidAdapter_spec.js +++ b/test/spec/modules/open8BidAdapter_spec.js @@ -1,5 +1,5 @@ -import { spec } from 'modules/open8BidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/open8BidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const ENDPOINT = 'https://as.vt.open8.com/v1/control/prebid'; diff --git a/test/spec/modules/openxAnalyticsAdapter_spec.js b/test/spec/modules/openxAnalyticsAdapter_spec.js index 1020b89d3b7..805435abf80 100644 --- a/test/spec/modules/openxAnalyticsAdapter_spec.js +++ b/test/spec/modules/openxAnalyticsAdapter_spec.js @@ -1,10 +1,10 @@ import { expect } from 'chai'; -import openxAdapter from 'modules/openxAnalyticsAdapter'; -import { config } from 'src/config'; -import events from 'src/events'; +import openxAdapter from 'modules/openxAnalyticsAdapter.js'; +import { config } from 'src/config.js'; +import events from 'src/events.js'; import CONSTANTS from 'src/constants.json'; -import * as utils from 'src/utils'; -import { server } from 'test/mocks/xhr'; +import * as utils from 'src/utils.js'; +import { server } from 'test/mocks/xhr.js'; const { EVENTS: { AUCTION_INIT, BID_REQUESTED, BID_RESPONSE, BID_TIMEOUT, BID_WON } diff --git a/test/spec/modules/openxBidAdapter_spec.js b/test/spec/modules/openxBidAdapter_spec.js index 38046409211..a6fbc9666b9 100644 --- a/test/spec/modules/openxBidAdapter_spec.js +++ b/test/spec/modules/openxBidAdapter_spec.js @@ -1,9 +1,9 @@ import {expect} from 'chai'; -import {spec, resetBoPixel} from 'modules/openxBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; -import {userSync} from 'src/userSync'; -import {config} from 'src/config'; -import * as utils from 'src/utils'; +import {spec, USER_ID_CODE_TO_QUERY_ARG} from 'modules/openxBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; +import {userSync} from 'src/userSync.js'; +import {config} from 'src/config.js'; +import * as utils from 'src/utils.js'; const URLBASE = '/w/1.0/arj'; const URLBASEVIDEO = '/v/1.0/avjp'; @@ -1026,120 +1026,66 @@ describe('OpenxAdapter', function () { }); describe('when there are userid providers', function () { - describe('with publisher common id', function () { - it('should not send a pubcid query param when there is no crumbs.pubcid and no userId.pubcid defined in the bid requests', function () { - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); - expect(request[0].data).to.not.have.any.keys('pubcid'); - }); - - it('should send a pubcid query param when crumbs.pubcid is defined in the bid requests', function () { - const bidRequestsWithPubcid = [{ - bidder: 'openx', - params: { - unit: '11', - delDomain: 'test-del-domain' - }, - crumbs: { - pubcid: 'c4a4c843-2368-4b5e-b3b1-6ee4702b9ad6' - }, - adUnitCode: 'adunit-code', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]] - } - }, - bidId: 'test-bid-id-1', - bidderRequestId: 'test-bid-request-1', - auctionId: 'test-auction-1' - }]; - const request = spec.buildRequests(bidRequestsWithPubcid, mockBidderRequest); - expect(request[0].data.pubcid).to.equal('c4a4c843-2368-4b5e-b3b1-6ee4702b9ad6'); - }); - - it('should send a pubcid query param when userId.pubcid is defined in the bid requests', function () { - const bidRequestsWithPubcid = [{ - bidder: 'openx', - params: { - unit: '11', - delDomain: 'test-del-domain' - }, - userId: { - pubcid: 'c1a4c843-2368-4b5e-b3b1-6ee4702b9ad6' - }, - adUnitCode: 'adunit-code', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]] - } - }, - bidId: 'test-bid-id-1', - bidderRequestId: 'test-bid-request-1', - auctionId: 'test-auction-1' - }]; - const request = spec.buildRequests(bidRequestsWithPubcid, mockBidderRequest); - expect(request[0].data.pubcid).to.equal('c1a4c843-2368-4b5e-b3b1-6ee4702b9ad6'); - }); - }); - - describe('with the trade desk unified id', function () { - it('should not send a tdid query param when there is no userId.tdid defined in the bid requests', function () { - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); - expect(request[0].data).to.not.have.any.keys('ttduuid'); - }); + const EXAMPLE_DATA_BY_ATTR = { + britepoolid: '1111-britepoolid', + criteoId: '1111-criteoId', + digitrustid: {data: {id: 'DTID', keyv: 4, privacy: {optout: false}, producer: 'ABC', version: 2}}, + id5id: '1111-id5id', + idl_env: '1111-idl_env', + lipb: {lipbid: '1111-lipb'}, + netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg', + parrableid: 'eidVersion.encryptionKeyReference.encryptedValue', + pubcid: '1111-pubcid', + tdid: '1111-tdid', + }; - it('should send a tdid query param when userId.tdid is defined in the bid requests', function () { - const bidRequestsWithTdid = [{ - bidder: 'openx', - params: { - unit: '11', - delDomain: 'test-del-domain' - }, - userId: { - tdid: '00000000-aaaa-1111-bbbb-222222222222' - }, - adUnitCode: 'adunit-code', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]] - } - }, - bidId: 'test-bid-id-1', - bidderRequestId: 'test-bid-request-1', - auctionId: 'test-auction-1' - }]; - const request = spec.buildRequests(bidRequestsWithTdid, mockBidderRequest); - expect(request[0].data.ttduuid).to.equal('00000000-aaaa-1111-bbbb-222222222222'); - }); - }); + // generates the same set of tests for each id provider + utils._each(USER_ID_CODE_TO_QUERY_ARG, (userIdQueryArg, userIdProviderKey) => { + describe(`with userId attribute: ${userIdProviderKey}`, function () { + it(`should not send a ${userIdQueryArg} query param when there is no userId.${userIdProviderKey} defined in the bid requests`, function () { + const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); + expect(request[0].data).to.not.have.any.keys(userIdQueryArg); + }); - describe('with the liveRamp identity link envelope', function () { - it('should not send a tdid query param when there is no userId.lre defined in the bid requests', function () { - const request = spec.buildRequests(bidRequestsWithMediaTypes, mockBidderRequest); - expect(request[0].data).to.not.have.any.keys('lre'); - }); + it(`should send a ${userIdQueryArg} query param when userId.${userIdProviderKey} is defined in the bid requests`, function () { + const bidRequestsWithUserId = [{ + bidder: 'openx', + params: { + unit: '11', + delDomain: 'test-del-domain' + }, + userId: { + }, + adUnitCode: 'adunit-code', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bidId: 'test-bid-id-1', + bidderRequestId: 'test-bid-request-1', + auctionId: 'test-auction-1' + }]; + // enrich bid request with userId key/value + bidRequestsWithUserId[0].userId[userIdProviderKey] = EXAMPLE_DATA_BY_ATTR[userIdProviderKey]; + + const request = spec.buildRequests(bidRequestsWithUserId, mockBidderRequest); + + let userIdValue; + // handle cases where userId key refers to an object + switch (userIdProviderKey) { + case 'digitrustid': + userIdValue = EXAMPLE_DATA_BY_ATTR.digitrustid.data.id; + break; + case 'lipb': + userIdValue = EXAMPLE_DATA_BY_ATTR.lipb.lipbid; + break; + default: + userIdValue = EXAMPLE_DATA_BY_ATTR[userIdProviderKey]; + } - it('should send a lre query param when userId.lre is defined in the bid requests', function () { - const bidRequestsWithLiveRampEnvelope = [{ - bidder: 'openx', - params: { - unit: '11', - delDomain: 'test-del-domain' - }, - userId: { - idl_env: '00000000-aaaa-1111-bbbb-222222222222' - }, - adUnitCode: 'adunit-code', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]] - } - }, - bidId: 'test-bid-id-1', - bidderRequestId: 'test-bid-request-1', - auctionId: 'test-auction-1' - }]; - const request = spec.buildRequests(bidRequestsWithLiveRampEnvelope, mockBidderRequest); - expect(request[0].data.lre).to.equal('00000000-aaaa-1111-bbbb-222222222222'); + expect(request[0].data[USER_ID_CODE_TO_QUERY_ARG[userIdProviderKey]]).to.equal(userIdValue); + }); }); }); }); @@ -1209,7 +1155,7 @@ describe('OpenxAdapter', function () { 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', 'transactionId': '4008d88a-8137-410b-aa35-fbfdabcb478e' - } + }; mockBidderRequest = {refererInfo: {}}; }); @@ -1641,32 +1587,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/optimeraBidAdapter_spec.js b/test/spec/modules/optimeraBidAdapter_spec.js index a0111ca9944..ada07fe25c2 100644 --- a/test/spec/modules/optimeraBidAdapter_spec.js +++ b/test/spec/modules/optimeraBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/optimeraBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/optimeraBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('OptimeraAdapter', function () { const adapter = newBidder(spec); diff --git a/test/spec/modules/orbidderBidAdapter_spec.js b/test/spec/modules/orbidderBidAdapter_spec.js index 9e7d10d7b04..eec6ccd19f6 100644 --- a/test/spec/modules/orbidderBidAdapter_spec.js +++ b/test/spec/modules/orbidderBidAdapter_spec.js @@ -1,8 +1,8 @@ import {expect} from 'chai'; -import {spec} from 'modules/orbidderBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; -import openxAdapter from '../../../modules/openxAnalyticsAdapter'; -import {detectReferer} from 'src/refererDetection'; +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); @@ -96,9 +96,13 @@ describe('orbidderBidAdapter', () => { expect(request.url).to.equal(`${spec.orbidderHost}/bid`); }); + it('contains prebid version parameter', () => { + expect(request.data.v).to.equal($$PREBID_GLOBAL$$.version); + }); + it('sends correct bid parameters', () => { - // we add one, because we add referer information from bidderRequest object - expect(Object.keys(request.data).length).to.equal(Object.keys(defaultBidRequest).length + 1); + // we add two, because we add referer information and version from bidderRequest object + expect(Object.keys(request.data).length).to.equal(Object.keys(defaultBidRequest).length + 2); expect(request.data.pageUrl).to.equal('https://localhost:9876/'); // expect(request.data.referrer).to.equal(''); Object.keys(defaultBidRequest).forEach((key) => { @@ -149,39 +153,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.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/otmBidAdapter_spec.js b/test/spec/modules/otmBidAdapter_spec.js index f3a98d43e57..8ac01c1657e 100644 --- a/test/spec/modules/otmBidAdapter_spec.js +++ b/test/spec/modules/otmBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from 'modules/otmBidAdapter'; +import {spec} from 'modules/otmBidAdapter.js'; describe('otmBidAdapterTests', function () { it('validate_pub_params', function () { diff --git a/test/spec/modules/outconBidAdapter_spec.js b/test/spec/modules/outconBidAdapter_spec.js index d9e763b9df9..81c3fdded62 100644 --- a/test/spec/modules/outconBidAdapter_spec.js +++ b/test/spec/modules/outconBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from '../../../modules/outconBidAdapter'; +import { spec } from '../../../modules/outconBidAdapter.js'; describe('outconBidAdapter', function () { describe('bidRequestValidity', function () { diff --git a/test/spec/modules/ozoneBidAdapter_spec.js b/test/spec/modules/ozoneBidAdapter_spec.js index 7d7d658351f..c8a636efb4c 100644 --- a/test/spec/modules/ozoneBidAdapter_spec.js +++ b/test/spec/modules/ozoneBidAdapter_spec.js @@ -1,9 +1,9 @@ import { expect } from 'chai'; -import { spec, getWidthAndHeightFromVideoObject, playerSizeIsNestedArray, defaultSize } from 'modules/ozoneBidAdapter'; -import { config } from 'src/config'; -import {Renderer} from '../../../src/Renderer'; -import {getGranularityKeyName, getGranularityObject} from '../../../modules/ozoneBidAdapter'; -import * as utils from '../../../src/utils'; +import { spec, getWidthAndHeightFromVideoObject, playerSizeIsNestedArray, defaultSize } from 'modules/ozoneBidAdapter.js'; +import { config } from 'src/config.js'; +import {Renderer} from '../../../src/Renderer.js'; +import {getGranularityKeyName, getGranularityObject} from '../../../modules/ozoneBidAdapter.js'; +import * as utils from '../../../src/utils.js'; const OZONEURI = 'https://elb.the-ozone-project.com/openrtb2/auction'; const BIDDER_CODE = 'ozone'; /* @@ -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,7 +63,7 @@ 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'} @@ -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': '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 @@ -279,176 +569,1002 @@ var validResponse = { } } ], - 'seat': 'appnexus' + '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': {} +}; + +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 } ], - 'cur': 'GBP', /* NOTE - this is where cur is, not in the seatbids. */ - 'ext': { - 'responsetimemillis': { - 'appnexus': 47, - 'openx': 30 - } + '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' + ] }, - 'timing': { - 'start': 1536848078.089177, - 'end': 1536848078.142203, - 'TimeTaken': 0.05302619934082031 - } - }, - 'headers': {} + '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 validOutstreamResponse = { + +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 } @@ -781,25 +1897,6 @@ describe('ozone Adapter', function () { expect(spec.isBidRequestValid(xBadLotame)).to.equal(false); }); - var xBadVideoContext = { - bidder: BIDDER_CODE, - params: { - 'placementId': '1234567890', - 'publisherId': '9876abcd12-3', - 'lotameData': {}, - siteId: '1234567890' - }, - mediaTypes: { - video: { - mimes: ['video/mp4'], - 'context': 'instream'}, - } - }; - - it('should not validate video instream being sent', function () { - expect(spec.isBidRequestValid(xBadVideoContext)).to.equal(false); - }); - var xBadVideoContext2 = { bidder: BIDDER_CODE, params: { @@ -835,30 +1932,64 @@ describe('ozone Adapter', function () { it('should validate video outstream being sent', function () { expect(spec.isBidRequestValid(validVideoBidReq)).to.equal(true); }); + it('should validate video instream being sent even though its not properly supported yet', function () { + let instreamVid = JSON.parse(JSON.stringify(validVideoBidReq)); + instreamVid.mediaTypes.video.context = 'instream'; + expect(spec.isBidRequestValid(instreamVid)).to.equal(true); + }); + // validate lotame override parameters + it('should validate lotame override 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'}; + }; + expect(spec.isBidRequestValid(validBidReq)).to.equal(true); + }); + it('should validate missing lotame override params', function () { + // mock the getGetParametersAsObject function to simulate GET parameters for lotame overrides: + spec.getGetParametersAsObject = function() { + return {'oz_lotameid': '123abc', 'oz_lotamepid': 'pid123'}; + }; + expect(spec.isBidRequestValid(validBidReq)).to.equal(false); + }); + it('should validate invalid lotame override 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': '123 "this ain\\t right!" eee'}; + }; + expect(spec.isBidRequestValid(validBidReq)).to.equal(false); + }); + it('should validate no lotame override params', function () { + // mock the getGetParametersAsObject function to simulate GET parameters for lotame overrides: + spec.getGetParametersAsObject = function() { + return {}; + }; + expect(spec.isBidRequestValid(validBidReq)).to.equal(true); + }); }); 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'); @@ -867,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'); @@ -878,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: @@ -913,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, @@ -931,9 +2062,10 @@ describe('ozone Adapter', function () { expect(payload.user.ext.consent).to.equal(consentString); }); - it('should add gdpr consent information to the request when ozone is true and vendorData is missing vendorConsents (Mirror)', function () { + // mirror + 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, @@ -948,10 +2080,9 @@ describe('ozone Adapter', function () { expect(payload.regs.ext.gdpr).to.equal(1); expect(payload.user.ext.consent).to.equal(consentString); }); - 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, @@ -970,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, @@ -1002,7 +2133,6 @@ describe('ozone Adapter', function () { }); it('should pick up the value of pubcid when built using the pubCommonId module (not userId)', function () { - console.log(validBidRequests[0].crumbs); let bidRequests = validBidRequests; // values from http://prebid.org/dev-docs/modules/userId.html#pubcommon-id bidRequests[0]['userId'] = { @@ -1015,14 +2145,14 @@ describe('ozone Adapter', function () { // '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; @@ -1048,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'); @@ -1058,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'); @@ -1069,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'); @@ -1079,22 +2209,139 @@ 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'); }); + + it('should pick up the value of valid lotame override parameters when there is a lotame object', function () { + spec.getGetParametersAsObject = function() { + return {'oz_lotameid': '123abc', 'oz_lotamepid': 'pid123', 'oz_lotametpid': '123eee'}; + }; + const request = spec.buildRequests(validBidRequests, validBidderRequest.bidderRequest); + const payload = JSON.parse(request.data); + 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 () { + let nolotameBidReq = JSON.parse(JSON.stringify(validBidRequests)); + nolotameBidReq[0].params.lotameData = {}; + spec.getGetParametersAsObject = function() { + return {'oz_lotameid': '123abc', 'oz_lotamepid': 'pid123', 'oz_lotametpid': '123eeetpid'}; + }; + const request = spec.buildRequests(nolotameBidReq, validBidderRequest.bidderRequest); + const payload = JSON.parse(request.data); + 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 () { + let nolotameBidReq = JSON.parse(JSON.stringify(validBidRequests)); + delete (nolotameBidReq[0].params['lotameData']); + spec.getGetParametersAsObject = function() { + return {'oz_lotameid': '123abc', 'oz_lotamepid': 'pid123', 'oz_lotametpid': '123eeetpid'}; + }; + const request = spec.buildRequests(nolotameBidReq, validBidderRequest.bidderRequest); + const payload = JSON.parse(request.data); + 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.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.bidderRequest); + const payload = JSON.parse(request.data); + expect(payload.regs).to.include.keys('coppa'); + expect(payload.regs.coppa).to.equal(1); + config.resetConfig(); + }); + 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.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); @@ -1103,15 +2350,15 @@ describe('ozone Adapter', function () { }); it('should build bid array with gdpr', function () { - var validBidderRequestWithGdpr = bidderRequestWithFullGdpr; - validBidderRequestWithGdpr.gdprConsent = {'gdprApplies': 1, 'consentString': 'This is the gdpr consent string'}; - const request = spec.buildRequests(validBidRequests, validBidderRequestWithGdpr); + 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 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); }); @@ -1128,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 () { @@ -1159,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'); @@ -1258,4 +2645,178 @@ describe('ozone Adapter', function () { expect(result.name).to.equal('rupert'); }); }); + + describe('blockTheRequest', function() { + it('should return true if oz_request is false', function() { + config.setConfig({'ozone': {'oz_request': false}}); + let result = spec.blockTheRequest(bidderRequestWithFullGdpr); + expect(result).to.be.true; + config.resetConfig(); + }); + it('should return false if oz_request is true', function() { + config.setConfig({'ozone': {'oz_request': true}}); + let result = spec.blockTheRequest(bidderRequestWithFullGdpr); + expect(result).to.be.false; + 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'}; + let result = spec.makeLotameObjectFromOverride( + objLotameOverride, + {'Profile': {'pid': 'originalpid', 'tpid': 'originaltpid', 'Audiences': {'Audience': [{'id': 'aud1'}]}}} + ); + expect(result.Profile.Audiences.Audience).to.be.an('array'); + expect(result.Profile.Audiences.Audience[0]).to.be.an('object'); + expect(result.Profile.Audiences.Audience[0]).to.deep.include({'id': '12345', 'abbr': '12345'}); + }); + it('should return the original object if it seems weird', function () { + let objLotameOverride = {'oz_lotametpid': '1234', 'oz_lotameid': '12345', 'oz_lotamepid': '123456'}; + let objLotameOriginal = {'Profile': {'pid': 'originalpid', 'tpid': 'originaltpid', 'somethingstrange': [{'id': 'aud1'}]}}; + let result = spec.makeLotameObjectFromOverride( + objLotameOverride, + objLotameOriginal + ); + expect(result).to.equal(objLotameOriginal); + }); + }); + describe('lotameDataIsValid', function() { + it('should allow a valid minimum lotame object', function() { + let obj = {'Profile': {'pid': '', 'tpid': '', 'Audiences': {'Audience': []}}}; + let result = spec.isLotameDataValid(obj); + expect(result).to.be.true; + }); + it('should allow a valid lotame object', function() { + let obj = {'Profile': {'pid': '12345', 'tpid': '45678', 'Audiences': {'Audience': [{'id': '1234', 'abbr': '567'}, {'id': '9999', 'abbr': '1111'}]}}}; + let result = spec.isLotameDataValid(obj); + expect(result).to.be.true; + }); + it('should disallow a lotame object without an Audience.id', function() { + let obj = {'Profile': {'tpid': '', 'pid': '', 'Audiences': {'Audience': [{'abbr': 'marktest'}]}}}; + let result = spec.isLotameDataValid(obj); + 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 88c9680c888..7d0858ed25e 100644 --- a/test/spec/modules/padsquadBidAdapter_spec.js +++ b/test/spec/modules/padsquadBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from 'modules/padsquadBidAdapter'; +import {spec} from 'modules/padsquadBidAdapter.js'; const REQUEST = { 'bidderCode': 'padsquad', @@ -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/papyrusBidAdapter_spec.js b/test/spec/modules/papyrusBidAdapter_spec.js index f3c6f42f5b2..20fcced2950 100644 --- a/test/spec/modules/papyrusBidAdapter_spec.js +++ b/test/spec/modules/papyrusBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/papyrusBidAdapter'; +import { spec } from 'modules/papyrusBidAdapter.js'; const ENDPOINT = 'https://prebid.papyrus.global'; const BIDDER_CODE = 'papyrus'; diff --git a/test/spec/modules/parrableIdSystem_spec.js b/test/spec/modules/parrableIdSystem_spec.js index 540e63aa630..fdfd3042561 100644 --- a/test/spec/modules/parrableIdSystem_spec.js +++ b/test/spec/modules/parrableIdSystem_spec.js @@ -1,75 +1,227 @@ import { expect } from 'chai'; -import {config} from 'src/config'; -import * as utils from 'src/utils'; +import { config } from 'src/config.js'; +import * as utils from 'src/utils.js'; +import { newStorageManager } from 'src/storageManager.js'; +import { getRefererInfo } from 'src/refererDetection.js'; +import { uspDataHandler } from 'src/adapterManager.js'; import { init, requestBidsHook, setSubmoduleRegistry } from 'modules/userId/index.js'; -import { parrableIdSubmodule } from 'modules/parrableIdSystem'; +import { parrableIdSubmodule } from 'modules/parrableIdSystem.js'; +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_VALUE = '01.1563917337.test-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; +} - describe('Parrable ID in Bid Request', function() { - let adUnits; +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() callback', function() { + let logErrorStub; + let callbackSpy = sinon.spy(); beforeEach(function() { - adUnits = [getAdUnitMock()]; + 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('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; + }); + }); + + describe('parrableIdSystem.getId() 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 + }); }); - it('should append parrableid to bid request', function(done) { - // simulate existing browser local storage values - utils.setCookie( - P_COOKIE_NAME, - P_COOKIE_VALUE, - (new Date(Date.now() + 5000).toUTCString()) + 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'; + + storage.setCookie(oldEidCookieName, oldEid); + storage.setCookie(oldOptoutCookieName, 'true'); + + 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); + }); + }); + + describe('parrableIdSystem.decode()', function() { + it('provides the Parrable ID (EID) from a stored object', function() { + let eid = '01.123.4567890'; + let parrableId = { + eid, + ccpaOptout: true + }; + + expect(parrableIdSubmodule.decode(parrableId)).to.deep.equal({ + parrableid: eid + }); + }); + }); + + describe('userId requestBids hook', function() { + let adUnits; + beforeEach(function() { + adUnits = [getAdUnitMock()]; + writeParrableCookie({ eid: P_COOKIE_EID }); setSubmoduleRegistry([parrableIdSubmodule]); init(config); config.setConfig(getConfigMock()); + }); + + afterEach(function() { + removeParrableCookie(); + storage.setCookie(P_COOKIE_NAME, '', EXPIRED_COOKIE_DATE); + }); + 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_VALUE); + expect(bid.userId.parrableid).to.equal(P_COOKIE_EID); }); }); - utils.setCookie(P_COOKIE_NAME, '', EXPIRED_COOKIE_DATE); 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/piximediaBidAdapter_spec.js b/test/spec/modules/piximediaBidAdapter_spec.js index 95e03734345..88a6433b71d 100644 --- a/test/spec/modules/piximediaBidAdapter_spec.js +++ b/test/spec/modules/piximediaBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/piximediaBidAdapter'; +import { spec } from 'modules/piximediaBidAdapter.js'; describe('piximediaAdapterTest', function() { describe('bidRequestValidity', function() { diff --git a/test/spec/modules/platformioBidAdapter_spec.js b/test/spec/modules/platformioBidAdapter_spec.js new file mode 100644 index 00000000000..ee753be17a7 --- /dev/null +++ b/test/spec/modules/platformioBidAdapter_spec.js @@ -0,0 +1,348 @@ +import {expect} from 'chai'; +import {spec} from 'modules/platformioBidAdapter'; +import {newBidder} from 'src/adapters/bidderFactory'; + +describe('Platform.io Adapter Tests', function () { + const slotConfigs = [{ + placementCode: '/DfpAccount1/slot1', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bidId: 'bid12345', + mediaType: 'banner', + params: { + pubId: '29521', + siteId: '26047', + placementId: '123', + bidFloor: '0.001', + ifa: 'IFA', + latitude: '40.712775', + longitude: '-74.005973' + } + }, { + placementCode: '/DfpAccount2/slot2', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + bidId: 'bid23456', + mediaType: 'banner', + params: { + pubId: '29521', + siteId: '26047', + placementId: '1234', + bidFloor: '0.000001', + } + }]; + const nativeSlotConfig = [{ + placementCode: '/DfpAccount1/slot3', + bidId: 'bid12345', + mediaType: 'native', + nativeParams: { + title: { required: true, len: 200 }, + body: {}, + image: { wmin: 100 }, + sponsoredBy: { }, + icon: { } + }, + params: { + pubId: '29521', + placementId: '123', + siteId: '26047' + } + }]; + const videoSlotConfig = [{ + placementCode: '/DfpAccount1/slot4', + mediaTypes: { + video: { + playerSize: [[640, 480]] + } + }, + bidId: 'bid12345678', + mediaType: 'video', + video: { + skippable: true + }, + params: { + pubId: '29521', + placementId: '1234567', + siteId: '26047', + } + }]; + const appSlotConfig = [{ + placementCode: '/DfpAccount1/slot5', + bidId: 'bid12345', + params: { + pubId: '29521', + placementId: '1234', + app: { + id: '1111', + name: 'app name', + bundle: 'io.platform.apps', + storeUrl: 'https://platform.io/apps', + domain: 'platform.io' + } + } + }]; + + it('Verify build request', function () { + const request = spec.buildRequests(slotConfigs); + expect(request.url).to.equal('https://piohbdisp.hb.adx1.com/'); + expect(request.method).to.equal('POST'); + const ortbRequest = JSON.parse(request.data); + // site object + expect(ortbRequest.site).to.not.equal(null); + expect(ortbRequest.site.publisher).to.not.equal(null); + expect(ortbRequest.site.publisher.id).to.equal('29521'); + expect(ortbRequest.site.ref).to.equal(window.top.document.referrer); + expect(ortbRequest.site.page).to.equal(window.location.href); + expect(ortbRequest.imp).to.have.lengthOf(2); + // device object + expect(ortbRequest.device).to.not.equal(null); + expect(ortbRequest.device.ua).to.equal(navigator.userAgent); + expect(ortbRequest.device.ifa).to.equal('IFA'); + expect(ortbRequest.device.geo.lat).to.equal('40.712775'); + expect(ortbRequest.device.geo.lon).to.equal('-74.005973'); + // slot 1 + expect(ortbRequest.imp[0].tagid).to.equal('123'); + expect(ortbRequest.imp[0].banner).to.not.equal(null); + expect(ortbRequest.imp[0].banner.w).to.equal(300); + expect(ortbRequest.imp[0].banner.h).to.equal(250); + expect(ortbRequest.imp[0].bidfloor).to.equal('0.001'); + // slot 2 + expect(ortbRequest.imp[1].tagid).to.equal('1234'); + expect(ortbRequest.imp[1].banner).to.not.equal(null); + expect(ortbRequest.imp[1].banner.w).to.equal(728); + expect(ortbRequest.imp[1].banner.h).to.equal(90); + expect(ortbRequest.imp[1].bidfloor).to.equal('0.000001'); + }); + + it('Verify parse response', function () { + const request = spec.buildRequests(slotConfigs); + const ortbRequest = JSON.parse(request.data); + const ortbResponse = { + seatbid: [{ + bid: [{ + impid: ortbRequest.imp[0].id, + price: 1.25, + adm: 'This is an Ad', + w: 300, + h: 250 + }] + }], + cur: 'USD' + }; + const bids = spec.interpretResponse({ body: ortbResponse }, request); + expect(bids).to.have.lengthOf(1); + // verify first bid + const bid = bids[0]; + expect(bid.cpm).to.equal(1.25); + expect(bid.ad).to.equal('This is an Ad'); + expect(bid.width).to.equal(300); + expect(bid.height).to.equal(250); + expect(bid.adId).to.equal('bid12345'); + expect(bid.creativeId).to.equal('bid12345'); + expect(bid.netRevenue).to.equal(true); + expect(bid.currency).to.equal('USD'); + expect(bid.ttl).to.equal(360); + }); + + it('Verify full passback', function () { + const request = spec.buildRequests(slotConfigs); + const bids = spec.interpretResponse({ body: null }, request) + expect(bids).to.have.lengthOf(0); + }); + + it('Verify Native request', function () { + const request = spec.buildRequests(nativeSlotConfig); + expect(request.url).to.equal('https://piohbdisp.hb.adx1.com/'); + expect(request.method).to.equal('POST'); + const ortbRequest = JSON.parse(request.data); + // native impression + expect(ortbRequest.imp[0].tagid).to.equal('123'); + const nativePart = ortbRequest.imp[0]['native']; + expect(nativePart).to.not.equal(null); + expect(nativePart.ver).to.equal('1.1'); + expect(nativePart.request).to.not.equal(null); + // native request assets + const nativeRequest = JSON.parse(ortbRequest.imp[0]['native'].request); + expect(nativeRequest).to.not.equal(null); + expect(nativeRequest.assets).to.have.lengthOf(5); + expect(nativeRequest.assets[0].id).to.equal(1); + expect(nativeRequest.assets[1].id).to.equal(2); + expect(nativeRequest.assets[2].id).to.equal(3); + expect(nativeRequest.assets[3].id).to.equal(4); + expect(nativeRequest.assets[4].id).to.equal(5); + expect(nativeRequest.assets[0].required).to.equal(1); + expect(nativeRequest.assets[0].title).to.not.equal(null); + expect(nativeRequest.assets[0].title.len).to.equal(200); + expect(nativeRequest.assets[1].title).to.be.undefined; + expect(nativeRequest.assets[1].data).to.not.equal(null); + expect(nativeRequest.assets[1].data.type).to.equal(2); + expect(nativeRequest.assets[1].data.len).to.equal(200); + expect(nativeRequest.assets[2].required).to.equal(0); + expect(nativeRequest.assets[3].img).to.not.equal(null); + expect(nativeRequest.assets[3].img.wmin).to.equal(50); + expect(nativeRequest.assets[3].img.hmin).to.equal(50); + expect(nativeRequest.assets[3].img.type).to.equal(1); + expect(nativeRequest.assets[4].img).to.not.equal(null); + expect(nativeRequest.assets[4].img.wmin).to.equal(100); + expect(nativeRequest.assets[4].img.hmin).to.equal(150); + expect(nativeRequest.assets[4].img.type).to.equal(3); + }); + + it('Verify Native response', function () { + const request = spec.buildRequests(nativeSlotConfig); + expect(request.url).to.equal('https://piohbdisp.hb.adx1.com/'); + expect(request.method).to.equal('POST'); + const ortbRequest = JSON.parse(request.data); + const nativeResponse = { + 'native': { + assets: [ + { id: 1, title: { text: 'Ad Title' } }, + { id: 2, data: { value: 'Test description' } }, + { id: 3, data: { value: 'Brand' } }, + { id: 4, img: { url: 'https://adx1public.s3.amazonaws.com/creatives_icon.png', w: 100, h: 100 } }, + { id: 5, img: { url: 'https://adx1public.s3.amazonaws.com/creatives_image.png', w: 300, h: 300 } } + ], + link: { url: 'https://brand.com/' } + } + }; + const ortbResponse = { + seatbid: [{ + bid: [{ + impid: ortbRequest.imp[0].id, + price: 1.25, + nurl: 'https://rtb.adx1.com/log', + adm: JSON.stringify(nativeResponse) + }] + }], + cur: 'USD', + }; + const bids = spec.interpretResponse({ body: ortbResponse }, request); + // verify bid + const bid = bids[0]; + expect(bid.cpm).to.equal(1.25); + expect(bid.adId).to.equal('bid12345'); + expect(bid.ad).to.be.undefined; + expect(bid.mediaType).to.equal('native'); + const nativeBid = bid['native']; + expect(nativeBid).to.not.equal(null); + expect(nativeBid.title).to.equal('Ad Title'); + expect(nativeBid.sponsoredBy).to.equal('Brand'); + expect(nativeBid.icon.url).to.equal('https://adx1public.s3.amazonaws.com/creatives_icon.png'); + expect(nativeBid.image.url).to.equal('https://adx1public.s3.amazonaws.com/creatives_image.png'); + expect(nativeBid.image.width).to.equal(300); + expect(nativeBid.image.height).to.equal(300); + expect(nativeBid.icon.width).to.equal(100); + expect(nativeBid.icon.height).to.equal(100); + expect(nativeBid.clickUrl).to.equal(encodeURIComponent('https://brand.com/')); + expect(nativeBid.impressionTrackers).to.have.lengthOf(1); + expect(nativeBid.impressionTrackers[0]).to.equal('https://rtb.adx1.com/log'); + }); + + it('Verify Video request', function () { + const request = spec.buildRequests(videoSlotConfig); + expect(request.url).to.equal('https://piohbdisp.hb.adx1.com/'); + expect(request.method).to.equal('POST'); + const videoRequest = JSON.parse(request.data); + // site object + expect(videoRequest.site).to.not.equal(null); + expect(videoRequest.site.publisher.id).to.equal('29521'); + expect(videoRequest.site.ref).to.equal(window.top.document.referrer); + expect(videoRequest.site.page).to.equal(window.location.href); + // device object + expect(videoRequest.device).to.not.equal(null); + expect(videoRequest.device.ua).to.equal(navigator.userAgent); + // slot 1 + expect(videoRequest.imp[0].tagid).to.equal('1234567'); + expect(videoRequest.imp[0].video).to.not.equal(null); + expect(videoRequest.imp[0].video.w).to.equal(640); + expect(videoRequest.imp[0].video.h).to.equal(480); + expect(videoRequest.imp[0].banner).to.equal(null); + expect(videoRequest.imp[0].native).to.equal(null); + }); + + it('Verify parse video response', function () { + const request = spec.buildRequests(videoSlotConfig); + const videoRequest = JSON.parse(request.data); + const videoResponse = { + seatbid: [{ + bid: [{ + impid: videoRequest.imp[0].id, + price: 1.90, + adm: 'https://vid.example.com/9876', + crid: '510511_754567308' + }] + }], + cur: 'USD' + }; + const bids = spec.interpretResponse({ body: videoResponse }, request); + expect(bids).to.have.lengthOf(1); + // verify first bid + const bid = bids[0]; + expect(bid.cpm).to.equal(1.90); + expect(bid.vastUrl).to.equal('https://vid.example.com/9876'); + expect(bid.crid).to.equal('510511_754567308'); + expect(bid.width).to.equal(640); + expect(bid.height).to.equal(480); + expect(bid.adId).to.equal('bid12345678'); + expect(bid.netRevenue).to.equal(true); + expect(bid.currency).to.equal('USD'); + expect(bid.ttl).to.equal(360); + }); + + it('Verifies bidder code', function () { + expect(spec.code).to.equal('platformio'); + }); + + it('Verifies supported media types', function () { + expect(spec.supportedMediaTypes).to.have.lengthOf(3); + expect(spec.supportedMediaTypes[0]).to.equal('banner'); + expect(spec.supportedMediaTypes[1]).to.equal('native'); + expect(spec.supportedMediaTypes[2]).to.equal('video'); + }); + + it('Verifies if bid request valid', function () { + expect(spec.isBidRequestValid(slotConfigs[0])).to.equal(true); + expect(spec.isBidRequestValid(slotConfigs[1])).to.equal(true); + expect(spec.isBidRequestValid(nativeSlotConfig[0])).to.equal(true); + expect(spec.isBidRequestValid(videoSlotConfig[0])).to.equal(true); + }); + + it('Verify app requests', function () { + const request = spec.buildRequests(appSlotConfig); + const ortbRequest = JSON.parse(request.data); + expect(ortbRequest.site).to.equal(null); + expect(ortbRequest.app).to.not.be.null; + expect(ortbRequest.app.publisher).to.not.equal(null); + expect(ortbRequest.app.publisher.id).to.equal('29521'); + expect(ortbRequest.app.id).to.equal('1111'); + expect(ortbRequest.app.name).to.equal('app name'); + expect(ortbRequest.app.bundle).to.equal('io.platform.apps'); + expect(ortbRequest.app.storeurl).to.equal('https://platform.io/apps'); + expect(ortbRequest.app.domain).to.equal('platform.io'); + }); + + it('Verify GDPR', function () { + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'serialized_gpdr_data' + } + }; + const request = spec.buildRequests(slotConfigs, bidderRequest); + expect(request.url).to.equal('https://piohbdisp.hb.adx1.com/'); + expect(request.method).to.equal('POST'); + const ortbRequest = JSON.parse(request.data); + expect(ortbRequest.user).to.not.equal(null); + expect(ortbRequest.user.ext).to.not.equal(null); + expect(ortbRequest.user.ext.consent).to.equal('serialized_gpdr_data'); + expect(ortbRequest.regs).to.not.equal(null); + expect(ortbRequest.regs.ext).to.not.equal(null); + expect(ortbRequest.regs.ext.gdpr).to.equal(1); + }); +}); diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 538e1da9aeb..294ada6f988 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1,12 +1,13 @@ import { expect } from 'chai'; -import { PrebidServer as Adapter, resetSyncedStatus } from 'modules/prebidServerBidAdapter/index.js'; -import adapterManager from 'src/adapterManager'; -import * as utils from 'src/utils'; -import { ajax } from 'src/ajax'; -import { config } from 'src/config'; -import events from 'src/events'; -import CONSTANTS from 'src/constants'; -import { server } from 'test/mocks/xhr'; +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'; +import { config } from 'src/config.js'; +import events from 'src/events.js'; +import CONSTANTS from 'src/constants.json'; +import { server } from 'test/mocks/xhr.js'; +import { createEidsArray } from 'modules/userId/eids.js'; let CONFIG = { accountId: '1', @@ -260,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, @@ -303,6 +309,7 @@ const RESPONSE_OPENRTB_VIDEO = { ext: { prebid: { type: 'video', + bidid: '654321' }, bidder: { appnexus: { @@ -431,6 +438,7 @@ describe('S2S Adapter', function () { done = sinon.spy(); beforeEach(function () { + config.resetConfig(); adapter = new Adapter(); BID_REQUESTS = [ { @@ -460,7 +468,8 @@ describe('S2S Adapter', function () { 'sizes': [300, 250], 'bidId': '123', 'bidderRequestId': '3d1063078dfcc8', - 'auctionId': '173afb6d132ba3' + 'auctionId': '173afb6d132ba3', + 'storedAuctionResponse': 11111 } ], 'auctionStart': 1510852447530, @@ -479,16 +488,15 @@ 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 () { let ortb2Config = utils.deepClone(CONFIG); ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; @@ -507,7 +515,6 @@ describe('S2S Adapter', function () { describe('gdpr tests', function () { afterEach(function () { - config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); }); @@ -606,7 +613,6 @@ describe('S2S Adapter', function () { describe('us_privacy (ccpa) consent data', function () { afterEach(function () { - config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); }); @@ -651,7 +657,6 @@ describe('S2S Adapter', function () { describe('gdpr and us_privacy (ccpa) consent data', function () { afterEach(function () { - config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); }); @@ -787,6 +792,27 @@ describe('S2S Adapter', function () { }); }); + it('adds debugging value from storedAuctionResponse to OpenRTB', function () { + const s2sConfig = Object.assign({}, CONFIG, { + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' + }); + const _config = { + s2sConfig: s2sConfig, + device: { ifa: '6D92078A-8246-4BA4-AE5B-76104861E7DC' }, + app: { bundle: 'com.test.app' } + }; + + config.setConfig(_config); + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + const requestBid = JSON.parse(server.requests[0].requestBody); + expect(requestBid.imp).to.exist.and.to.be.a('array'); + expect(requestBid.imp).to.have.lengthOf(1); + expect(requestBid.imp[0].ext).to.exist.and.to.be.a('object'); + expect(requestBid.imp[0].ext.prebid).to.exist.and.to.be.a('object'); + expect(requestBid.imp[0].ext.prebid.storedauctionresponse).to.exist.and.to.be.a('object'); + expect(requestBid.imp[0].ext.prebid.storedauctionresponse.id).to.equal('11111'); + }); + it('adds device.w and device.h even if the config lacks a device object', function () { const s2sConfig = Object.assign({}, CONFIG, { endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' @@ -876,6 +902,15 @@ describe('S2S Adapter', function () { const _config = { s2sConfig: s2sConfig, + site: { + publisher: { + id: '1234', + domain: 'test.com' + }, + content: { + language: 'en' + } + } }; config.setConfig(_config); @@ -883,7 +918,21 @@ describe('S2S Adapter', function () { const requestBid = JSON.parse(server.requests[0].requestBody); expect(requestBid.site).to.exist.and.to.be.a('object'); expect(requestBid.site.publisher).to.exist.and.to.be.a('object'); + expect(requestBid.site.publisher.id).to.exist.and.to.be.a('string'); + expect(requestBid.site.publisher.domain).to.exist.and.to.be.a('string'); expect(requestBid.site.page).to.exist.and.to.be.a('string'); + expect(requestBid.site.content).to.exist.and.to.be.a('object'); + expect(requestBid.site.content.language).to.exist.and.to.be.a('string'); + expect(requestBid.site).to.deep.equal({ + publisher: { + id: '1234', + domain: 'test.com' + }, + content: { + language: 'en' + }, + page: 'http://mytestpage.com' + }); }); it('adds appnexus aliases to request', function () { @@ -909,6 +958,7 @@ describe('S2S Adapter', function () { aliases: { brealtime: 'appnexus' }, + auctiontimestamp: 1510852447530, targeting: { includebidderkeys: false, includewinners: true @@ -943,6 +993,7 @@ describe('S2S Adapter', function () { aliases: { [alias]: 'appnexus' }, + auctiontimestamp: 1510852447530, targeting: { includebidderkeys: false, includewinners: true @@ -1044,6 +1095,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'; @@ -1060,8 +1164,10 @@ describe('S2S Adapter', function () { lipb: { lipbid: 'li-xyz', segments: ['segA', 'segB'] - } + }, + idl_env: '0000-1111-2222-3333' }; + userIdBidRequest[0].bids[0].userIdAsEids = createEidsArray(userIdBidRequest[0].bids[0].userId); adapter.callBids(REQUEST, userIdBidRequest, addBidResponse, done, ajax); let requestBid = JSON.parse(server.requests[0].requestBody); @@ -1080,6 +1186,8 @@ 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'); + // LiveRamp should exist + expect(requestBid.user.ext.eids.filter(eid => eid.source === 'liveramp.com')[0].uids[0].id).is.equal('0000-1111-2222-3333'); }); it('when config \'currency.adServerCurrency\' value is an array: ORTB has property \'cur\' value set to a single item array', function () { @@ -1190,6 +1298,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, @@ -1221,6 +1330,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 @@ -1254,6 +1364,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' }, @@ -1287,7 +1398,51 @@ describe('S2S Adapter', function () { adapter.callBids(REQUEST, bidRequests, addBidResponse, done, ajax); const parsedRequestBody = JSON.parse(server.requests[0].requestBody); expect(parsedRequestBody.source.ext.schain).to.deep.equal(schainObject); - }) + }); + + it('passes first party data in request', () => { + const s2sBidRequest = utils.deepClone(REQUEST); + const bidRequests = utils.deepClone(BID_REQUESTS); + + const commonContext = { + keywords: ['power tools'], + search: 'drill' + }; + const commonUser = { + keywords: ['a', 'b'], + gender: 'M' + }; + + const context = { + content: { userrating: 4 }, + data: { + pageType: 'article', + category: 'tools' + } + }; + const user = { + yob: '1984', + geo: { country: 'ca' }, + data: { + registered: true, + interests: ['cars'] + } + }; + const allowedBidders = [ 'rubicon', 'appnexus' ]; + + const expected = allowedBidders.map(bidder => ({ + bidders: [ bidder ], + config: { fpd: { site: context, user } } + })); + + config.setConfig({ fpd: { context: commonContext, user: commonUser } }); + config.setBidderConfig({ bidders: allowedBidders, config: { fpd: { context, user } } }); + adapter.callBids(s2sBidRequest, bidRequests, addBidResponse, done, ajax); + const parsedRequestBody = JSON.parse(server.requests[0].requestBody); + expect(parsedRequestBody.ext.prebid.bidderconfig).to.deep.equal(expected); + expect(parsedRequestBody.site.ext.data).to.deep.equal(commonContext); + expect(parsedRequestBody.user.ext.data).to.deep.equal(commonUser); + }); describe('pbAdSlot config', function () { it('should not send \"imp.ext.context.data.adslot\" if \"fpd.context\" is undefined', function () { @@ -1365,67 +1520,52 @@ describe('S2S Adapter', function () { }); 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); @@ -1439,11 +1579,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'); }); @@ -1459,9 +1597,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]; @@ -1473,9 +1610,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'); @@ -1484,9 +1620,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'); @@ -1503,11 +1638,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' }); @@ -1519,11 +1652,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); @@ -1541,9 +1672,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); @@ -1556,9 +1686,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; @@ -1571,8 +1700,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 () { @@ -1581,9 +1731,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]; @@ -1609,9 +1758,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]; @@ -1635,9 +1784,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]; @@ -1662,9 +1810,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]; @@ -1674,6 +1821,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', @@ -1685,9 +1903,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]; @@ -1702,6 +1919,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; @@ -1807,6 +2116,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', @@ -1859,6 +2176,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 fcff6837ece..e87be40314c 100644 --- a/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js +++ b/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js @@ -1,6 +1,6 @@ -import prebidmanagerAnalytics from 'modules/prebidmanagerAnalyticsAdapter'; +import prebidmanagerAnalytics from 'modules/prebidmanagerAnalyticsAdapter.js'; import {expect} from 'chai'; -import {server} from 'test/mocks/xhr'; +import {server} from 'test/mocks/xhr.js'; let events = require('src/events'); let constants = require('src/constants.json'); @@ -101,4 +101,38 @@ describe('Prebid Manager Analytics Adapter', function () { sinon.assert.callCount(prebidmanagerAnalytics.track, 6); }); }); + + describe('build utm tag data', function () { + beforeEach(function () { + localStorage.setItem('pm_utm_source', 'utm_source'); + localStorage.setItem('pm_utm_medium', 'utm_medium'); + localStorage.setItem('pm_utm_campaign', 'utm_camp'); + localStorage.setItem('pm_utm_term', ''); + localStorage.setItem('pm_utm_content', ''); + }); + afterEach(function () { + localStorage.removeItem('pm_utm_source'); + localStorage.removeItem('pm_utm_medium'); + localStorage.removeItem('pm_utm_campaign'); + localStorage.removeItem('pm_utm_term'); + localStorage.removeItem('pm_utm_content'); + prebidmanagerAnalytics.disableAnalytics() + }); + it('should build utm data from local storage', function () { + prebidmanagerAnalytics.enableAnalytics({ + provider: 'prebidmanager', + options: { + bundleId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + } + }); + + const pmEvents = JSON.parse(server.requests[0].requestBody.substring(2)); + + expect(pmEvents.utmTags.utm_source).to.equal('utm_source'); + expect(pmEvents.utmTags.utm_medium).to.equal('utm_medium'); + expect(pmEvents.utmTags.utm_campaign).to.equal('utm_camp'); + expect(pmEvents.utmTags.utm_term).to.equal(''); + expect(pmEvents.utmTags.utm_content).to.equal(''); + }); + }); }); diff --git a/test/spec/modules/priceFloorsSchema.json b/test/spec/modules/priceFloorsSchema.json new file mode 100644 index 00000000000..7b524da381e --- /dev/null +++ b/test/spec/modules/priceFloorsSchema.json @@ -0,0 +1,86 @@ +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "description": "A Price Floors object which is parsed and used to enforce dynamic floors depending on the properties of the json", + "type": "object", + "title": "Price Floors Enforcement", + "required": [ + "schema", + "values" + ], + "properties": { + "schema": { + "type": "object", + "description": "Defines the schema of the rules", + "required": [ + "fields" + ], + "properties": { + "fields": { + "type": "array", + "description": "The list of fields to be used for matching criteria of a bid response with a price floor", + "minItems": 1, + "uniqueItems": true, + "additionalItems": false, + "items": { + "type": "string" + } + }, + "delimiter": { + "type": "string", + "description": "The character used to differentiate the fields inside a single rule", + "examples": [ + "|", + "^", + "~" + ] + } + } + }, + "values": { + "type": "object", + "description": "A object with key : value pairs which constitutes a rule and floor", + "additionalProperties": { + "type": "number" + }, + "minProperties": 1, + "examples": [ + { + "123456/someSlot|300x250|www.prebid.org": 1.5, + "123456/someSlot|300x600|www.prebid.org": 2.5, + "123456/someSlot|300x600|*": 1.2, + "123456/someSlot|*|*": 0.8 + } + ] + }, + "currency": { + "type": "string", + "description": "The three digit Currency Code which the floors are provided in", + "examples": [ + "USD", + "EUR", + "JPY" + ], + "pattern": "^[a-zA-Z]{3}$" + }, + "modelVersion": { + "type": "string", + "description": "The floor modeling name to be used for tracking", + "examples": [ + "Prebid-Floor-Model-1.2" + ] + }, + "skipRate": { + "type": "integer", + "description": "The skip rate as to which flooring will be 'turned off' for a given auction", + "minimum": 0, + "maximum": 100 + }, + "default": { + "type": "number", + "description": "The default floor to use if no entry in the value matches a bid response", + "examples": [ + 0.75 + ] + } + } +} \ No newline at end of file diff --git a/test/spec/modules/priceFloors_spec.js b/test/spec/modules/priceFloors_spec.js new file mode 100644 index 00000000000..9d35554c27f --- /dev/null +++ b/test/spec/modules/priceFloors_spec.js @@ -0,0 +1,1262 @@ +import {expect} from 'chai'; +import * as utils from 'src/utils.js'; +import { getGlobal } from 'src/prebidGlobal.js'; +import CONSTANTS from 'src/constants.json'; +import { + _floorDataForAuction, + getFloorsDataForAuction, + getFirstMatchingFloor, + getFloor, + handleSetFloorsConfig, + requestBidsHook, + isFloorsDataValid, + addBidResponseHook, + 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', + schema: { + delimiter: '|', + fields: ['mediaType'] + }, + values: { + 'banner': 1.0, + 'video': 5.0, + '*': 2.5 + } + }; + const basicFloorConfig = { + enabled: true, + auctionDelay: 0, + endpoint: {}, + enforcement: { + enforceJS: true, + enforcePBS: false, + floorDeals: false, + bidAdjustment: true + }, + data: basicFloorData + } + const basicBidRequest = { + bidder: 'rubicon', + adUnitCode: 'test_div_1', + auctionId: '1234-56-789', + }; + + function getAdUnitMock(code = 'adUnit-code') { + return { + code, + mediaTypes: {banner: { sizes: [[300, 200], [300, 600]] }, native: {}}, + bids: [{bidder: 'someBidder'}, {bidder: 'someOtherBidder'}] + }; + } + 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(); + utils.logWarn.restore(); + // reset global bidder settings so no weird test side effects + getGlobal().bidderSettings = {}; + }); + + describe('getFloorsDataForAuction', function () { + it('converts basic input floor data into a floorData map for the auction correctly', function () { + // basic input where nothing needs to be updated + expect(getFloorsDataForAuction(basicFloorData)).to.deep.equal(basicFloorData); + + // if cur and delim not defined then default to correct ones (usd and |) + let inputFloorData = utils.deepClone(basicFloorData); + delete inputFloorData.currency; + delete inputFloorData.schema.delimiter; + expect(getFloorsDataForAuction(inputFloorData)).to.deep.equal(basicFloorData); + + // should not use defaults if differing values + inputFloorData.currency = 'EUR' + inputFloorData.schema.delimiter = '^' + let resultingData = getFloorsDataForAuction(inputFloorData); + expect(resultingData.currency).to.equal('EUR'); + expect(resultingData.schema.delimiter).to.equal('^'); + }); + + it('converts more complex floor data correctly', function () { + let inputFloorData = { + schema: { + fields: ['mediaType', 'size', 'domain'] + }, + values: { + 'banner|300x250|prebid.org': 1.0, + 'video|640x480|prebid.org': 5.0, + 'banner|728x90|rubicon.com': 3.5, + 'video|600x300|appnexus.com': 3.5, + '*|*|prebid.org': 3.5, + } + }; + let resultingData = getFloorsDataForAuction(inputFloorData); + expect(resultingData).to.deep.equal({ + currency: 'USD', + schema: { + delimiter: '|', + fields: ['mediaType', 'size', 'domain'] + }, + values: { + 'banner|300x250|prebid.org': 1.0, + 'video|640x480|prebid.org': 5.0, + 'banner|728x90|rubicon.com': 3.5, + 'video|600x300|appnexus.com': 3.5, + '*|*|prebid.org': 3.5, + } + }); + }); + + it('adds adUnitCode to the schema if the floorData comes from adUnit level to maintain scope', function () { + let inputFloorData = utils.deepClone(basicFloorData); + let resultingData = getFloorsDataForAuction(inputFloorData, 'test_div_1'); + expect(resultingData).to.deep.equal({ + modelVersion: 'basic model', + currency: 'USD', + schema: { + delimiter: '|', + fields: ['adUnitCode', 'mediaType'] + }, + values: { + 'test_div_1|banner': 1.0, + 'test_div_1|video': 5.0, + 'test_div_1|*': 2.5 + } + }); + + // uses the right delim if not | + inputFloorData.schema.delimiter = '^'; + resultingData = getFloorsDataForAuction(inputFloorData, 'this_is_a_div'); + expect(resultingData).to.deep.equal({ + modelVersion: 'basic model', + currency: 'USD', + schema: { + delimiter: '^', + fields: ['adUnitCode', 'mediaType'] + }, + values: { + 'this_is_a_div^banner': 1.0, + 'this_is_a_div^video': 5.0, + 'this_is_a_div^*': 2.5 + } + }); + }); + }); + + describe('getFirstMatchingFloor', function () { + it('selects the right floor for different mediaTypes', function () { + // banner with * size (not in rule file so does not do anything) + expect(getFirstMatchingFloor({...basicFloorData}, basicBidRequest, {mediaType: 'banner', size: '*'})).to.deep.equal({ + matchingFloor: 1.0, + matchingData: 'banner', + matchingRule: 'banner' + }); + // video with * size (not in rule file so does not do anything) + expect(getFirstMatchingFloor({...basicFloorData}, basicBidRequest, {mediaType: 'video', size: '*'})).to.deep.equal({ + matchingFloor: 5.0, + matchingData: 'video', + matchingRule: 'video' + }); + // native (not in the rule list) with * size (not in rule file so does not do anything) + expect(getFirstMatchingFloor({...basicFloorData}, basicBidRequest, {mediaType: 'native', size: '*'})).to.deep.equal({ + matchingFloor: 2.5, + matchingData: 'native', + matchingRule: '*' + }); + }); + it('selects the right floor for different sizes', function () { + let inputFloorData = { + currency: 'USD', + schema: { + delimiter: '|', + fields: ['size'] + }, + values: { + '300x250': 1.1, + '640x480': 2.2, + '728x90': 3.3, + '600x300': 4.4, + '*': 5.5, + } + } + // banner with 300x250 size + expect(getFirstMatchingFloor(inputFloorData, basicBidRequest, {mediaType: 'banner', size: [300, 250]})).to.deep.equal({ + matchingFloor: 1.1, + matchingData: '300x250', + matchingRule: '300x250' + }); + // video with 300x250 size + expect(getFirstMatchingFloor(inputFloorData, basicBidRequest, {mediaType: 'video', size: [300, 250]})).to.deep.equal({ + matchingFloor: 1.1, + matchingData: '300x250', + matchingRule: '300x250' + }); + // native (not in the rule list) with 300x600 size + expect(getFirstMatchingFloor(inputFloorData, basicBidRequest, {mediaType: 'native', size: [600, 300]})).to.deep.equal({ + matchingFloor: 4.4, + matchingData: '600x300', + matchingRule: '600x300' + }); + // n/a mediaType with a size not in file should go to catch all + expect(getFirstMatchingFloor(inputFloorData, basicBidRequest, {mediaType: undefined, size: [1, 1]})).to.deep.equal({ + matchingFloor: 5.5, + matchingData: '1x1', + matchingRule: '*' + }); + }); + it('selects the right floor for more complex rules', function () { + let inputFloorData = { + currency: 'USD', + schema: { + delimiter: '^', + fields: ['adUnitCode', 'mediaType', 'size'] + }, + values: { + 'test_div_1^banner^300x250': 1.1, + 'test_div_1^video^640x480': 2.2, + 'test_div_2^*^*': 3.3, + '*^banner^300x250': 4.4, + 'weird_div^*^300x250': 5.5 + }, + default: 0.5 + }; + // banner with 300x250 size + expect(getFirstMatchingFloor(inputFloorData, basicBidRequest, {mediaType: 'banner', size: [300, 250]})).to.deep.equal({ + matchingFloor: 1.1, + matchingData: 'test_div_1^banner^300x250', + matchingRule: 'test_div_1^banner^300x250' + }); + // video with 300x250 size -> No matching rule so should use default + expect(getFirstMatchingFloor(inputFloorData, basicBidRequest, {mediaType: 'video', size: [300, 250]})).to.deep.equal({ + matchingFloor: 0.5, + matchingData: 'test_div_1^video^300x250', + matchingRule: undefined + }); + // remove default and should still return the same floor as above since matches are cached + delete inputFloorData.default; + expect(getFirstMatchingFloor(inputFloorData, basicBidRequest, {mediaType: 'video', size: [300, 250]})).to.deep.equal({ + matchingFloor: 0.5, + matchingData: 'test_div_1^video^300x250', + matchingRule: undefined + }); + // update adUnitCode to test_div_2 with weird other params + let newBidRequest = { ...basicBidRequest, adUnitCode: 'test_div_2' } + expect(getFirstMatchingFloor(inputFloorData, newBidRequest, {mediaType: 'badmediatype', size: [900, 900]})).to.deep.equal({ + matchingFloor: 3.3, + matchingData: 'test_div_2^badmediatype^900x900', + matchingRule: 'test_div_2^*^*' + }); + }); + it('it does not break if floorData has bad values', function () { + let inputFloorData = {}; + expect(getFirstMatchingFloor(inputFloorData, basicBidRequest, {mediaType: 'banner', size: '*'})).to.deep.equal({ + matchingFloor: undefined + }); + // if default is there use it + inputFloorData = { default: 5.0 }; + expect(getFirstMatchingFloor(inputFloorData, basicBidRequest, {mediaType: 'banner', size: '*'})).to.deep.equal({ + matchingFloor: 5.0 + }); + }); + }); + describe('pre-auction tests', function () { + let exposedAdUnits; + const validateBidRequests = (getFloorExpected, FloorDataExpected) => { + exposedAdUnits.forEach(adUnit => adUnit.bids.forEach(bid => { + expect(bid.hasOwnProperty('getFloor')).to.equal(getFloorExpected); + expect(bid.floorData).to.deep.equal(FloorDataExpected); + })); + }; + const runStandardAuction = (adUnits = [getAdUnitMock('test_div_1')]) => { + requestBidsHook(config => exposedAdUnits = config.adUnits, { + auctionId: basicBidRequest.auctionId, + adUnits, + }); + }; + let fakeFloorProvider; + let actualAllowedFields = allowedFields; + let actualFieldMatchingFunctions = fieldMatchingFunctions; + const defaultAllowedFields = [...allowedFields]; + const defaultMatchingFunctions = {...fieldMatchingFunctions}; + beforeEach(function() { + fakeFloorProvider = sinon.fakeServer.create(); + }); + afterEach(function() { + fakeFloorProvider.restore(); + exposedAdUnits = undefined; + actualAllowedFields = [...defaultAllowedFields]; + actualFieldMatchingFunctions = {...defaultMatchingFunctions}; + }); + it('should not do floor stuff if no resulting floor object can be resolved for auciton', function () { + handleSetFloorsConfig({ + ...basicFloorConfig, + data: undefined + }); + runStandardAuction(); + validateBidRequests(false, { + skipped: true, + modelVersion: undefined, + location: undefined, + skipRate: 0, + fetchStatus: undefined + }); + }); + it('should use adUnit level data if not setConfig or fetch has occured', function () { + handleSetFloorsConfig({ + ...basicFloorConfig, + data: undefined + }); + // attach floor data onto an adUnit and run an auction + let adUnitWithFloors1 = { + ...getAdUnitMock('adUnit-Div-1'), + floors: { + ...basicFloorData, + modelVersion: 'adUnit Model Version', // change the model name + } + }; + let adUnitWithFloors2 = { + ...getAdUnitMock('adUnit-Div-2'), + floors: { + ...basicFloorData, + values: { + 'banner': 5.0, + '*': 10.4 + } + } + }; + runStandardAuction([adUnitWithFloors1, adUnitWithFloors2]); + validateBidRequests(true, { + skipped: false, + modelVersion: 'adUnit Model Version', + location: 'adUnit', + skipRate: 0, + fetchStatus: undefined + }); + }); + it('bidRequests should have getFloor function and flooring meta data when setConfig occurs', function () { + handleSetFloorsConfig({...basicFloorConfig}); + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'basic model', + location: 'setConfig', + skipRate: 0, + fetchStatus: 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 + }); + + // 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 + }); + + // 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 + }); + }); + it('should randomly pick a model if floorsSchemaVersion is 2', function () { + let inputFloors = { + ...basicFloorConfig, + 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 + }); + + // 11 - 50 should use second model + randValue = 0.40; + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'model-2', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined + }); + + // 51 - 100 should use third model + randValue = 0.75; + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'model-3', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined + }); + }); + it('should not overwrite previous data object if the new one is bad', function () { + handleSetFloorsConfig({...basicFloorConfig}); + handleSetFloorsConfig({ + ...basicFloorConfig, + data: undefined + }); + handleSetFloorsConfig({ + ...basicFloorConfig, + data: 5 + }); + handleSetFloorsConfig({ + ...basicFloorConfig, + data: { + schema: {fields: ['thisIsNotAllowedSoShouldFail']}, + values: {'*': 1.2}, + modelVersion: 'FAIL' + } + }); + runStandardAuction(); + validateBidRequests(true, { + skipped: false, + modelVersion: 'basic model', + location: 'setConfig', + skipRate: 0, + fetchStatus: undefined + }); + }); + it('should dynamically add new schema fileds and functions if added via setConfig', function () { + let deviceSpoof; + handleSetFloorsConfig({ + ...basicFloorConfig, + data: { + schema: {fields: ['deviceType']}, + values: { + 'mobile': 1.0, + 'desktop': 2.0, + 'tablet': 3.0, + '*': 4.0 + } + }, + additionalSchemaFields: { + deviceType: () => deviceSpoof + } + }); + expect(allowedFields).to.contain('deviceType'); + expect(fieldMatchingFunctions['deviceType']).to.be.a('function'); + + // run getFloor to make sure it selcts right stuff! (other params do not matter since we only are testing deviceType) + runStandardAuction(); + + // set deviceType to mobile; + deviceSpoof = 'mobile'; + exposedAdUnits[0].bids[0].auctionId = basicBidRequest.auctionId + expect(exposedAdUnits[0].bids[0].getFloor()).to.deep.equal({ + currency: 'USD', + floor: 1.0 // 'mobile': 1.0, + }); + + // set deviceType to desktop; + deviceSpoof = 'desktop'; + expect(exposedAdUnits[0].bids[0].getFloor()).to.deep.equal({ + currency: 'USD', + floor: 2.0 // 'desktop': 2.0, + }); + + // set deviceType to tablet; + deviceSpoof = 'tablet'; + expect(exposedAdUnits[0].bids[0].getFloor()).to.deep.equal({ + currency: 'USD', + floor: 3.0 // 'tablet': 3.0 + }); + + // set deviceType to unknown; + deviceSpoof = 'unknown'; + expect(exposedAdUnits[0].bids[0].getFloor()).to.deep.equal({ + currency: 'USD', + floor: 4.0 // '*': 4.0 + }); + }); + it('Should continue auction of delay is hit without a response from floor provider', function () { + handleSetFloorsConfig({...basicFloorConfig, auctionDelay: 250, endpoint: {url: '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; + + // hit the delay + clock.tick(250); + + // log warn should be called and adUnits not undefined + expect(logWarnSpy.calledOnce).to.equal(true); + expect(exposedAdUnits).to.not.be.undefined; + + // the exposedAdUnits should be from the fetch not setConfig level data + validateBidRequests(true, { + skipped: false, + modelVersion: 'basic model', + location: 'setConfig', + skipRate: 0, + fetchStatus: 'timeout' + }); + fakeFloorProvider.respond(); + }); + it('It should fetch if config has url and bidRequests have fetch level flooring meta data', function () { + // init the fake server with response stuff + let fetchFloorData = { + ...basicFloorData, + modelVersion: 'fetch model name', // change the model name + }; + fakeFloorProvider.respondWith(JSON.stringify(fetchFloorData)); + + // run setConfig indicating fetch + handleSetFloorsConfig({...basicFloorConfig, 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: 0, + fetchStatus: 'success' + }); + }); + 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, 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' + }); + }); + 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' + }); + }); + it('Should not break if floor provider returns non json', function () { + fakeFloorProvider.respondWith('Not valid response'); + + // run setConfig indicating fetch + handleSetFloorsConfig({...basicFloorConfig, auctionDelay: 250, endpoint: {url: 'http://www.fakeFloorProvider.json'}}); + + // run the auction and make server respond + 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' + }); + }); + it('should handle not using fetch correctly', function () { + // run setConfig twice indicating fetch + fakeFloorProvider.respondWith(JSON.stringify(basicFloorData)); + handleSetFloorsConfig({...basicFloorConfig, auctionDelay: 250, endpoint: {url: 'http://www.fakeFloorProvider.json'}}); + handleSetFloorsConfig({...basicFloorConfig, auctionDelay: 250, endpoint: {url: 'http://www.fakeFloorProvider.json'}}); + + // log warn should be called and server only should have one request + expect(logWarnSpy.calledOnce).to.equal(true); + expect(fakeFloorProvider.requests.length).to.equal(1); + expect(fakeFloorProvider.requests[0].url).to.equal('http://www.fakeFloorProvider.json'); + + // now we respond and then run again it should work and make another request + fakeFloorProvider.respond(); + handleSetFloorsConfig({...basicFloorConfig, auctionDelay: 250, endpoint: {url: 'http://www.fakeFloorProvider.json'}}); + fakeFloorProvider.respond(); + + // now warn still only called once and server called twice + expect(logWarnSpy.calledOnce).to.equal(true); + expect(fakeFloorProvider.requests.length).to.equal(2); + + // should log error if method is not GET for now + expect(logErrorSpy.calledOnce).to.equal(false); + handleSetFloorsConfig({...basicFloorConfig, endpoint: {url: 'http://www.fakeFloorProvider.json', method: 'POST'}}); + 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); + + // no fields array + delete inputFloorData.schema.fields; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + + // Fields is not an array + inputFloorData.schema.fields = {}; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + inputFloorData.schema.fields = undefined; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + inputFloorData.schema.fields = 'adUnitCode'; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + + // fields has a value that is not one of the "allowed" fields + inputFloorData.schema.fields = ['adUnitCode', 'notValidMapping']; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + }); + it('should work correctly for values object', function () { + let inputFloorData = utils.deepClone(basicFloorData); + expect(isFloorsDataValid(inputFloorData)).to.to.equal(true); + + // no values object + delete inputFloorData.values; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + + // values is not correct type + inputFloorData.values = []; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + inputFloorData.values = '123455/slot'; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + + // is an object but structure is wrong + inputFloorData.values = { + 'banner': 'not a floor value' + }; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + inputFloorData.values = { + 'banner': undefined + }; + expect(isFloorsDataValid(inputFloorData)).to.to.equal(false); + + // should be true if at least one rule is valid + inputFloorData.schema.fields = ['adUnitCode', 'mediaType']; + inputFloorData.values = { + 'banner': 1.0, + 'test-div-1|native': 1.0, // only valid rule should still work and delete the other rules + 'video': 1.0, + '*': 1.0 + }; + 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 = { + ...basicBidRequest, + getFloor + }; + it('returns empty if no matching data for auction is found', function () { + expect(bidRequest.getFloor({})).to.deep.equal({}); + }); + it('picks the right rule depending on input', function () { + _floorDataForAuction[bidRequest.auctionId] = utils.deepClone(basicFloorConfig); + + // empty params into getFloor should use default of banner * FloorData Curr + let inputParams = {}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 1.0 + }); + + // ask for banner + inputParams = {mediaType: 'banner'}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 1.0 + }); + + // ask for video + inputParams = {mediaType: 'video'}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 5.0 + }); + + // ask for * + inputParams = {mediaType: '*'}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 2.5 + }); + }); + it('picks the right rule with more complex rules', function () { + _floorDataForAuction[bidRequest.auctionId] = { + ...basicFloorConfig, + data: { + currency: 'USD', + schema: { fields: ['mediaType', 'size'], delimiter: '|' }, + values: { + 'banner|300x250': 0.5, + 'banner|300x600': 1.5, + 'banner|728x90': 2.5, + 'banner|*': 3.5, + 'video|640x480': 4.5, + 'video|*': 5.5 + }, + default: 10.0 + } + }; + + // assumes banner * + let inputParams = {}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 3.5 + }); + + // ask for banner with a size + inputParams = {mediaType: 'banner', size: [300, 600]}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 1.5 + }); + + // ask for video with a size + inputParams = {mediaType: 'video', size: [640, 480]}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 4.5 + }); + + // ask for video with a size not in rules (should pick rule which has video and *) + inputParams = {mediaType: 'video', size: [111, 222]}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 5.5 + }); + + // ask for native * but no native rule so should use default value if there + inputParams = {mediaType: 'native', size: '*'}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 10.0 + }); + }); + it('should round up to 4 decimal places', function () { + _floorDataForAuction[bidRequest.auctionId] = utils.deepClone(basicFloorConfig); + _floorDataForAuction[bidRequest.auctionId].data.values = { + 'banner': 1.777777, + 'video': 1.1111111, + }; + + // assumes banner * + let inputParams = {mediaType: 'banner'}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 1.7778 + }); + + // assumes banner * + inputParams = {mediaType: 'video'}; + expect(bidRequest.getFloor(inputParams)).to.deep.equal({ + currency: 'USD', + floor: 1.1112 + }); + }); + it('should return the adjusted floor if bidder has cpm adjustment function', function () { + getGlobal().bidderSettings = { + rubicon: { + bidCpmAdjustment: function (bidCpm) { + return bidCpm * 0.5; + }, + }, + appnexus: { + bidCpmAdjustment: function (bidCpm) { + return bidCpm * 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', + adUnitCode: 'test_div_2', + auctionId: '987654321', + mediaTypes: { + video: {} + }, + getFloor + }; + _floorDataForAuction[inputBidReq.auctionId] = utils.deepClone(basicFloorConfig); + _floorDataForAuction[inputBidReq.auctionId].data.values = { + '*': 1.0, + 'banner': 3.0, + 'video': 5.0 + }; + + // because bid req only has video, if a bidder asks for a floor for * we can actually give them the right mediaType + expect(inputBidReq.getFloor({mediaType: '*'})).to.deep.equal({ + currency: 'USD', + floor: 5.0 // 'video': 5.0 + }); + delete _floorDataForAuction[inputBidReq.auctionId].data.matchingInputs; + + // Same for if only banner is in the input bid + inputBidReq.mediaTypes = {banner: {}}; + expect(inputBidReq.getFloor({mediaType: '*'})).to.deep.equal({ + currency: 'USD', + floor: 3.0 // 'banner': 3.0, + }); + delete _floorDataForAuction[inputBidReq.auctionId].data.matchingInputs; + + // if both are present then it will really use the * + inputBidReq.mediaTypes = {banner: {}, video: {}}; + expect(inputBidReq.getFloor({mediaType: '*'})).to.deep.equal({ + currency: 'USD', + floor: 1.0 // '*': 1.0, + }); + delete _floorDataForAuction[inputBidReq.auctionId].data.matchingInputs; + + // now if size can be inferred (meaning only one size is in the specified mediaType, it will use it) + _floorDataForAuction[inputBidReq.auctionId].data.schema.fields = ['mediaType', 'size']; + _floorDataForAuction[inputBidReq.auctionId].data.values = { + '*|*': 1.0, + 'banner|300x250': 2.0, + 'banner|728x90': 3.0, + 'banner|*': 4.0, + 'video|300x250': 5.0, + 'video|728x90': 6.0, + 'video|*': 7.0 + }; + // mediaType is banner and only one size, so if someone asks for banner * we should give them banner 300x250 + // instead of banner|* + inputBidReq.mediaTypes = {banner: {sizes: [[300, 250]]}}; + expect(inputBidReq.getFloor({mediaType: 'banner', size: '*'})).to.deep.equal({ + currency: 'USD', + floor: 2.0 // 'banner|300x250': 2.0, + }); + delete _floorDataForAuction[inputBidReq.auctionId].data.matchingInputs; + + // now for video it should look at playersize (prebid core translates playersize into typical array of size arrays) + inputBidReq.mediaTypes = {video: {playerSize: [[728, 90]]}}; + expect(inputBidReq.getFloor({mediaType: 'video', size: '*'})).to.deep.equal({ + currency: 'USD', + floor: 6.0 // 'video|728x90': 6.0, + }); + delete _floorDataForAuction[inputBidReq.auctionId].data.matchingInputs; + + // Now if multiple sizes are there, it will actually use * since can't infer + inputBidReq.mediaTypes = {banner: {sizes: [[300, 250], [728, 90]]}}; + expect(inputBidReq.getFloor({mediaType: 'banner', size: '*'})).to.deep.equal({ + currency: 'USD', + floor: 4.0 // 'banner|*': 4.0, + }); + delete _floorDataForAuction[inputBidReq.auctionId].data.matchingInputs; + + // lastly, if you pass in * mediaType and * size it should resolve both if possble + inputBidReq.mediaTypes = {banner: {sizes: [[300, 250]]}}; + expect(inputBidReq.getFloor({mediaType: '*', size: '*'})).to.deep.equal({ + currency: 'USD', + floor: 2.0 // 'banner|300x250': 2.0, + }); + delete _floorDataForAuction[inputBidReq.auctionId].data.matchingInputs; + + inputBidReq.mediaTypes = {video: {playerSize: [[300, 250]]}}; + expect(inputBidReq.getFloor({mediaType: '*', size: '*'})).to.deep.equal({ + currency: 'USD', + floor: 5.0 // 'video|300x250': 5.0, + }); + delete _floorDataForAuction[inputBidReq.auctionId].data.matchingInputs; + + // now it has both mediaTypes so will use * mediaType and thus not use sizes either + inputBidReq.mediaTypes = {video: {playerSize: [[300, 250]]}, banner: {sizes: [[300, 250]]}}; + expect(inputBidReq.getFloor({mediaType: '*', size: '*'})).to.deep.equal({ + currency: 'USD', + floor: 1.0 // '*|*': 1.0, + }); + delete _floorDataForAuction[inputBidReq.auctionId].data.matchingInputs; + }); + }); + }); + describe('bidResponseHook tests', function () { + let returnedBidResponse; + let bidderRequest = { + bidderCode: 'appnexus', + auctionId: '123456', + bids: [{ + bidder: 'appnexus', + adUnitCode: 'test_div_1', + auctionId: '123456', + bidId: '1111' + }] + }; + let basicBidResponse = { + bidderCode: 'appnexus', + width: 300, + height: 250, + cpm: 0.5, + mediaType: 'banner', + requestId: '1111', + }; + beforeEach(function () { + returnedBidResponse = {}; + }); + function runBidResponse(bidResp = basicBidResponse) { + let next = (adUnitCode, bid) => { + returnedBidResponse = bid; + }; + addBidResponseHook.bind({ bidderRequest })(next, bidResp.adUnitCode, bidResp); + }; + it('continues with the auction if not floors data is present without any flooring', function () { + runBidResponse(); + expect(returnedBidResponse).to.not.haveOwnProperty('floorData'); + }); + it('if no matching rule it should not floor and should call log warn', function () { + _floorDataForAuction[bidderRequest.auctionId] = utils.deepClone(basicFloorConfig); + _floorDataForAuction[bidderRequest.auctionId].data.values = { 'video': 1.0 }; + runBidResponse(); + expect(returnedBidResponse).to.not.haveOwnProperty('floorData'); + expect(logWarnSpy.calledOnce).to.equal(true); + }); + it('if it finds a rule and floors should update the bid accordingly', function () { + _floorDataForAuction[bidderRequest.auctionId] = utils.deepClone(basicFloorConfig); + _floorDataForAuction[bidderRequest.auctionId].data.values = { 'banner': 1.0 }; + runBidResponse(); + expect(returnedBidResponse).to.haveOwnProperty('floorData'); + expect(returnedBidResponse.status).to.equal(CONSTANTS.BID_STATUS.BID_REJECTED); + expect(returnedBidResponse.cpm).to.equal(0); + }); + it('if it finds a rule and does not floor should update the bid accordingly', function () { + _floorDataForAuction[bidderRequest.auctionId] = utils.deepClone(basicFloorConfig); + _floorDataForAuction[bidderRequest.auctionId].data.values = { 'banner': 0.3 }; + runBidResponse(); + expect(returnedBidResponse).to.haveOwnProperty('floorData'); + expect(returnedBidResponse.floorData).to.deep.equal({ + floorValue: 0.3, + floorCurrency: 'USD', + floorRule: 'banner', + cpmAfterAdjustments: 0.5, + enforcements: { + bidAdjustment: true, + enforceJS: true, + enforcePBS: false, + floorDeals: false + }, + matchedFields: { + mediaType: 'banner' + } + }); + expect(returnedBidResponse.cpm).to.equal(0.5); + }); + it('if should work with more complex rules and update accordingly', function () { + _floorDataForAuction[bidderRequest.auctionId] = { + ...basicFloorConfig, + data: { + currency: 'USD', + schema: { fields: ['mediaType', 'size'], delimiter: '|' }, + values: { + 'banner|300x250': 0.5, + 'banner|300x600': 1.5, + 'banner|728x90': 2.5, + 'banner|*': 3.5, + 'video|640x480': 4.5, + 'video|*': 5.5 + }, + default: 10.0 + } + }; + runBidResponse(); + expect(returnedBidResponse).to.haveOwnProperty('floorData'); + expect(returnedBidResponse.floorData).to.deep.equal({ + floorValue: 0.5, + floorCurrency: 'USD', + floorRule: 'banner|300x250', + cpmAfterAdjustments: 0.5, + enforcements: { + bidAdjustment: true, + enforceJS: true, + enforcePBS: false, + floorDeals: false + }, + matchedFields: { + mediaType: 'banner', + size: '300x250' + } + }); + expect(returnedBidResponse.cpm).to.equal(0.5); + + // update bidResponse to have different combinations (should pick video|*) + runBidResponse({ + width: 300, + height: 250, + cpm: 7.5, + mediaType: 'video', + requestId: '1111', + }); + expect(returnedBidResponse).to.haveOwnProperty('floorData'); + expect(returnedBidResponse.floorData).to.deep.equal({ + floorValue: 5.5, + floorCurrency: 'USD', + floorRule: 'video|*', + cpmAfterAdjustments: 7.5, + enforcements: { + bidAdjustment: true, + enforceJS: true, + enforcePBS: false, + floorDeals: false + }, + matchedFields: { + mediaType: 'video', + size: '300x250' + } + }); + 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 f51e1188b73..3ffc017f177 100644 --- a/test/spec/modules/projectLimeLightBidAdapter_spec.js +++ b/test/spec/modules/projectLimeLightBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec} from '../../../modules/projectLimeLightBidAdapter'; +import {spec} from '../../../modules/projectLimeLightBidAdapter.js'; describe('ProjectLimeLightAdapter', function () { let bid = { diff --git a/test/spec/modules/proxistoreBidAdapter_spec.js b/test/spec/modules/proxistoreBidAdapter_spec.js index 4fd7d97ae99..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,13 +28,27 @@ 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); }); }); describe('buildRequests', function () { - const url = 'https://abs.proxistore.com/fr/v3/rtb/prebid'; + const url = 'https://abs.proxistore.com/fr/v3/rtb/prebid/multi'; const request = spec.buildRequests([bid], bidderRequest); it('should return a valid object', function () { expect(request).to.be.an('object'); @@ -50,10 +64,19 @@ describe('ProxistoreBidAdapter', function () { }); it('should have the value consentGiven to true bc we have 418 in the vendor list', function () { const data = JSON.parse(request.data); + expect(data.gdpr.consentString).equal(bidderRequest.gdprConsent.consentString); expect(data.gdpr.applies).to.be.true; expect(data.gdpr.consentGiven).to.be.true; }); + it('should have a property a length of bids equal to one if there is only one bid', function () { + const data = JSON.parse(request.data); + expect(data.hasOwnProperty('bids')).to.be.true; + expect(data.bids).to.be.an('array'); + expect(data.bids.length).equal(1); + expect(data.bids[0].hasOwnProperty('id')).to.be.true; + expect(data.bids[0].sizes).to.be.an('array'); + }); }); describe('interpretResponse', function () { @@ -88,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 fd2bff5bac6..ab0ef2adc51 100644 --- a/test/spec/modules/pubCommonId_spec.js +++ b/test/spec/modules/pubCommonId_spec.js @@ -9,11 +9,11 @@ import { setStorageItem, getStorageItem, removeStorageItem, - getPubcidConfig } from 'modules/pubCommonId'; -import { getAdUnits } from 'test/fixtures/fixtures'; -import * as auctionModule from 'src/auction'; -import { registerBidder } from 'src/adapters/bidderFactory'; -import * as utils from 'src/utils'; + getPubcidConfig } from 'modules/pubCommonId.js'; +import { getAdUnits } from 'test/fixtures/fixtures.js'; +import * as auctionModule from 'src/auction.js'; +import { registerBidder } from 'src/adapters/bidderFactory.js'; +import * as utils from 'src/utils.js'; let events = require('src/events'); let constants = require('src/constants.json'); diff --git a/test/spec/modules/pubgeniusBidAdapter_spec.js b/test/spec/modules/pubgeniusBidAdapter_spec.js new file mode 100644 index 00000000000..c510be99402 --- /dev/null +++ b/test/spec/modules/pubgeniusBidAdapter_spec.js @@ -0,0 +1,439 @@ +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 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 + } + ] + }; + bidderRequest.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 new file mode 100755 index 00000000000..537ba4483cf --- /dev/null +++ b/test/spec/modules/pubmaticAnalyticsAdapter_spec.js @@ -0,0 +1,702 @@ +import pubmaticAnalyticsAdapter from 'modules/pubmaticAnalyticsAdapter.js'; +import CONSTANTS from 'src/constants.json'; +import { config } from 'src/config.js'; +import { + setConfig, + addBidResponseHook, +} from 'modules/currency.js'; + +// using es6 "import * as events from 'src/events'" causes the events.getEvents stub not to work... +let events = require('src/events'); +let ajax = require('src/ajax'); +let utils = require('src/utils'); + +const { + EVENTS: { + AUCTION_INIT, + AUCTION_END, + BID_REQUESTED, + BID_RESPONSE, + BIDDER_DONE, + BID_WON, + BID_TIMEOUT, + SET_TARGETING + } +} = CONSTANTS; + +const BID = { + 'bidder': 'pubmatic', + 'width': 640, + 'height': 480, + 'mediaType': 'video', + 'statusMessage': 'Bid available', + 'bidId': '2ecff0db240757', + 'partnerImpId': 'partnerImpressionID-1', + 'adId': 'fake_ad_id', + 'source': 's2s', + 'requestId': '2ecff0db240757', + 'currency': 'USD', + 'creativeId': '3571560', + 'cpm': 1.22752, + 'originalCpm': 1.22752, + 'originalCurrency': 'USD', + 'ttl': 300, + 'netRevenue': false, + 'ad': '', + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa', + 'responseTimestamp': 1519149629415, + 'requestTimestamp': 1519149628471, + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 944, + 'pbLg': '1.00', + 'pbMg': '1.20', + 'pbHg': '1.22', + 'pbAg': '1.20', + 'pbDg': '1.22', + 'pbCg': '', + 'size': '640x480', + 'adserverTargeting': { + 'hb_bidder': 'pubmatic', + 'hb_adid': '2ecff0db240757', + 'hb_pb': 1.20, + 'hb_size': '640x480', + 'hb_source': 'server' + }, + getStatusCode() { + return 1; + } +}; + +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, + height: 90, + mediaType: 'banner', + cpm: 1.52, + originalCpm: 1.52, + dealId: 'the-deal-id', + dealChannel: 'PMP', + mi: 'matched-impression', + seatBidId: 'aaaa-bbbb-cccc-dddd', + adserverTargeting: { + 'hb_bidder': 'pubmatic', + 'hb_adid': '3bd4ebb1c900e2', + 'hb_pb': '1.500', + 'hb_size': '728x90', + 'hb_source': 'server' + } +}); + +const MOCK = { + SET_TARGETING: { + [BID.adUnitCode]: BID.adserverTargeting, + [BID2.adUnitCode]: BID2.adserverTargeting + }, + AUCTION_INIT: { + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa', + 'timestamp': 1519767010567, + 'auctionStatus': 'inProgress', + 'adUnits': [ { + 'code': '/19968336/header-bid-tag-1', + 'sizes': [[640, 480]], + 'bids': [ { + 'bidder': 'pubmatic', + 'params': { + 'publisherId': '1001' + } + } ], + 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014' + } + ], + 'adUnitCodes': ['/19968336/header-bid-tag-1'], + 'bidderRequests': [ { + 'bidderCode': 'pubmatic', + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa', + 'bidderRequestId': '1be65d7958826a', + 'bids': [ { + 'bidder': 'pubmatic', + 'params': { + 'publisherId': '1001', + 'kgpv': 'this-is-a-kgpv' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[640, 480]] + } + }, + 'adUnitCode': '/19968336/header-bid-tag-1', + 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014', + 'sizes': [[640, 480]], + 'bidId': '2ecff0db240757', + 'bidderRequestId': '1be65d7958826a', + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa', + 'src': 'client', + 'bidRequestsCount': 1 + } + ], + 'timeout': 3000, + 'refererInfo': { + 'referer': 'http://www.test.com/page.html', 'reachedTop': true, 'numIframes': 0, 'stack': ['http://www.test.com/page.html'] + } + } + ], + 'bidsReceived': [], + 'winningBids': [], + 'timeout': 3000 + }, + BID_REQUESTED: { + 'bidder': 'pubmatic', + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa', + 'bidderRequestId': '1be65d7958826a', + 'bids': [ + { + 'bidder': 'pubmatic', + 'params': { + 'publisherId': '1001', + 'video': { + 'minduration': 30, + 'skippable': true + } + }, + 'mediaType': 'video', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014', + 'sizes': [[640, 480]], + 'bidId': '2ecff0db240757', + 'bidderRequestId': '1be65d7958826a', + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa' + }, + { + 'bidder': 'pubmatic', + 'params': { + 'publisherId': '1001', + 'kgpv': 'this-is-a-kgpv' + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[1000, 300], [970, 250], [728, 90]] + } + }, + 'adUnitCode': '/19968336/header-bid-tag-1', + 'transactionId': 'c116413c-9e3f-401a-bee1-d56aec29a1d4', + 'sizes': [[1000, 300], [970, 250], [728, 90]], + 'bidId': '3bd4ebb1c900e2', + 'seatBidId': 'aaaa-bbbb-cccc-dddd', + 'bidderRequestId': '1be65d7958826a', + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa' + } + ], + 'auctionStart': 1519149536560, + 'timeout': 5000, + 'start': 1519149562216, + 'refererInfo': { + 'referer': 'http://www.test.com/page.html', 'reachedTop': true, 'numIframes': 0, 'stack': ['http://www.test.com/page.html'] + }, + 'gdprConsent': { + 'consentString': 'here-goes-gdpr-consent-string', + 'gdprApplies': true + } + }, + BID_RESPONSE: [ + BID, + BID2 + ], + AUCTION_END: { + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa' + }, + BID_WON: [ + Object.assign({}, BID, { + 'status': 'rendered' + }), + Object.assign({}, BID2, { + 'status': 'rendered' + }) + ], + BIDDER_DONE: { + 'bidderCode': 'pubmatic', + 'bids': [ + BID, + Object.assign({}, BID2, { + 'serverResponseTimeMs': 42, + }) + ] + }, + BID_TIMEOUT: [ + { + 'bidId': '3bd4ebb1c900e2', + 'bidder': 'pubmatic', + 'adUnitCode': '/19968336/header-bid-tag-1', + 'auctionId': '25c6d7f5-699a-4bfc-87c9-996f915341fa' + } + ] +}; + +function getLoggerJsonFromRequest(requestBody) { + return JSON.parse(decodeURIComponent(requestBody.split('json=')[1])); +} + +describe('pubmatic analytics adapter', function () { + let sandbox; + let xhr; + let requests; + let oldScreen; + let clock; + + beforeEach(function () { + sandbox = sinon.sandbox.create(); + + xhr = sandbox.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = request => requests.push(request); + + sandbox.stub(events, 'getEvents').returns([]); + + clock = sandbox.useFakeTimers(1519767013781); + + config.setConfig({ + s2sConfig: { + timeout: 1000, + accountId: 10000, + bidders: ['pubmatic'] + } + }) + }); + + afterEach(function () { + sandbox.restore(); + config.resetConfig(); + }); + + it('should require publisherId', function () { + sandbox.stub(utils, 'logError'); + pubmaticAnalyticsAdapter.enableAnalytics({ + options: {} + }); + expect(utils.logError.called).to.equal(true); + }); + + describe('when handling events', function() { + beforeEach(function () { + pubmaticAnalyticsAdapter.enableAnalytics({ + options: { + publisherId: 9999, + profileId: 1111, + profileVersionId: 20 + } + }); + }); + + afterEach(function () { + pubmaticAnalyticsAdapter.disableAnalytics(); + }); + + 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]); + events.emit(BID_RESPONSE, MOCK.BID_RESPONSE[1]); + 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&gdEn=1'); + let data = getLoggerJsonFromRequest(request.requestBody); + expect(data.pubid).to.equal('9999'); + expect(data.pid).to.equal('1111'); + expect(data.pdvid).to.equal('20'); + expect(data.iid).to.equal('25c6d7f5-699a-4bfc-87c9-996f915341fa'); + expect(data.to).to.equal('3000'); + 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 + 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].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'); + expect(data.s[0].ps[0].psz).to.equal('640x480'); + expect(data.s[0].ps[0].eg).to.equal(1.23); + expect(data.s[0].ps[0].en).to.equal(1.23); + expect(data.s[0].ps[0].di).to.equal(''); + expect(data.s[0].ps[0].dc).to.equal(''); + expect(data.s[0].ps[0].l1).to.equal(3214); + expect(data.s[0].ps[0].l2).to.equal(0); + expect(data.s[0].ps[0].ss).to.equal(1); + expect(data.s[0].ps[0].t).to.equal(0); + 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'); + // slot 2 + 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'); + 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'); + expect(data.s[1].ps[0].psz).to.equal('728x90'); + expect(data.s[1].ps[0].eg).to.equal(1.52); + expect(data.s[1].ps[0].en).to.equal(1.52); + 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'); + expect(data.s[1].ps[0].l1).to.equal(3214); + 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(0); + expect(data.s[1].ps[0].wb).to.equal(1); + 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'); + + // 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(decodeURIComponent(data.purl)).to.equal('http://www.test.com/page.html'); + expect(data.tst).to.equal('1519767014'); + expect(data.iid).to.equal('25c6d7f5-699a-4bfc-87c9-996f915341fa'); + expect(data.bidid).to.equal('2ecff0db240757'); + expect(data.pid).to.equal('1111'); + expect(data.pdvid).to.equal('20'); + expect(decodeURIComponent(data.slot)).to.equal('/19968336/header-bid-tag-0'); + expect(decodeURIComponent(data.kgpv)).to.equal('/19968336/header-bid-tag-0'); + 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&gdEn=1'); + 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&gdEn=1'); + 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]); + 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]); + + clock.tick(2000 + 1000); + 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'); + 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].db).to.equal(1); + 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('0x0'); + expect(data.s[1].ps[0].eg).to.equal(0); + expect(data.s[1].ps[0].en).to.equal(0); + expect(data.s[1].ps[0].di).to.equal(''); + expect(data.s[1].ps[0].dc).to.equal(''); + expect(data.s[1].ps[0].mi).to.equal(undefined); + expect(data.s[1].ps[0].l1).to.equal(0); + 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(0); + expect(data.s[1].ps[0].wb).to.equal(0); + expect(data.s[1].ps[0].af).to.equal(undefined); + expect(data.s[1].ps[0].ocpm).to.equal(0); + expect(data.s[1].ps[0].ocry).to.equal('USD'); + }); + + it('Logger: post-timeout check without bid response', function() { + // db = 1 and t = 1 means bidder did NOT respond with a bid but we got a timeout notification + events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BID_TIMEOUT, MOCK.BID_TIMEOUT); + events.emit(AUCTION_END, MOCK.AUCTION_END); + clock.tick(2000 + 1000); + + expect(requests.length).to.equal(1); // 1 logger and 0 win-tracker + let request = requests[0]; + 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']); + expect(data.s[1].ps).to.be.an('array'); + 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].db).to.equal(1); + 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('0x0'); + expect(data.s[1].ps[0].eg).to.equal(0); + expect(data.s[1].ps[0].en).to.equal(0); + expect(data.s[1].ps[0].di).to.equal(''); + expect(data.s[1].ps[0].dc).to.equal(''); + expect(data.s[1].ps[0].mi).to.equal(undefined); + expect(data.s[1].ps[0].l1).to.equal(0); + 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(0); + expect(data.s[1].ps[0].af).to.equal(undefined); + expect(data.s[1].ps[0].ocpm).to.equal(0); + expect(data.s[1].ps[0].ocry).to.equal('USD'); + }); + + 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]); + events.emit(BID_TIMEOUT, MOCK.BID_TIMEOUT); + events.emit(AUCTION_END, MOCK.AUCTION_END); + clock.tick(2000 + 1000); + + expect(requests.length).to.equal(1); // 1 logger and 0 win-tracker + let request = requests[0]; + 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']); + expect(data.s[1].ps).to.be.an('array'); + 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].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'); + expect(data.s[1].ps[0].psz).to.equal('728x90'); + expect(data.s[1].ps[0].eg).to.equal(1.52); + expect(data.s[1].ps[0].en).to.equal(1.52); + 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'); + expect(data.s[1].ps[0].l1).to.equal(3214); + 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); // 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'); + }); + + it('Logger: currency conversion check', function() { + setConfig({ + adServerCurrency: 'JPY', + rates: { + USD: { + JPY: 100 + } + } + }); + const bidCopy = utils.deepClone(BID2); + bidCopy.currency = 'JPY'; + bidCopy.cpm = 100; + bidCopy.originalCpm = 100; + bidCopy.originalCurrency = 'JPY'; + + 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(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&gdEn=1'); + 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']); + expect(data.s[1].ps).to.be.an('array'); + 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].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'); + expect(data.s[1].ps[0].psz).to.equal('728x90'); + 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'); + expect(data.s[1].ps[0].l1).to.equal(3214); + 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(0); + expect(data.s[1].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[1].ps[0].af).to.equal('banner'); + 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 902f8b1fd73..abc440ac8ea 100644 --- a/test/spec/modules/pubmaticBidAdapter_spec.js +++ b/test/spec/modules/pubmaticBidAdapter_spec.js @@ -1,7 +1,8 @@ import {expect} from 'chai'; -import {spec} from 'modules/pubmaticBidAdapter'; -import * as utils from 'src/utils'; -import {config} from 'src/config'; +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 () { @@ -533,6 +534,10 @@ describe('PubMatic adapter', function () { 'body': { 'id': '93D3BAD6-E2E2-49FB-9D89-920B1761C865', 'seatbid': [{ + 'seat': 'seat-id', + 'ext': { + 'buyid': 'BUYER-ID-987' + }, 'bid': [{ 'id': '74858439-49D7-4169-BA5D-44A046315B2F', 'impid': '22bddb28db77d', @@ -548,6 +553,9 @@ describe('PubMatic adapter', function () { } }] }, { + 'ext': { + 'buyid': 'BUYER-ID-789' + }, 'bid': [{ 'id': '74858439-49D7-4169-BA5D-44A046315BEF', 'impid': '22bddb28db77e', @@ -725,7 +733,9 @@ describe('PubMatic adapter', function () { expect(data.test).to.equal(undefined); }); - it('test flag set to 1 when pubmaticTest=true is present in page url', function() { + // disabled this test case as it refreshes the whole suite when in karma watch mode + // todo: needs a fix + 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); @@ -766,6 +776,70 @@ describe('PubMatic adapter', function () { expect(data.source.ext.schain).to.deep.equal(bidRequests[0].schain); }); + it('Merge the device info from config', function() { + let sandbox = sinon.sandbox.create(); + sandbox.stub(config, 'getConfig').callsFake((key) => { + var config = { + device: { + 'newkey': 'new-device-data' + } + }; + return config[key]; + }); + let request = spec.buildRequests(bidRequests); + 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); + expect(data.device.h).to.equal(screen.height); + expect(data.device.w).to.equal(screen.width); + expect(data.device.language).to.equal(navigator.language); + expect(data.device.newkey).to.equal('new-device-data');// additional data from config + sandbox.restore(); + }); + + it('Merge the device info from config; data from config overrides the info we have gathered', function() { + let sandbox = sinon.sandbox.create(); + sandbox.stub(config, 'getConfig').callsFake((key) => { + var config = { + device: { + newkey: 'new-device-data', + language: 'MARATHI' + } + }; + return config[key]; + }); + let request = spec.buildRequests(bidRequests); + 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); + expect(data.device.h).to.equal(screen.height); + expect(data.device.w).to.equal(screen.width); + expect(data.device.language).to.equal('MARATHI');// // data overriding from config + expect(data.device.newkey).to.equal('new-device-data');// additional data from config + sandbox.restore(); + }); + + it('Set app from config, copy publisher and ext from site, unset site', function() { + let sandbox = sinon.sandbox.create(); + sandbox.stub(config, 'getConfig').callsFake((key) => { + var config = { + app: { + bundle: 'org.prebid.mobile.demoapp', + domain: 'prebid.org' + } + }; + return config[key]; + }); + let request = spec.buildRequests(bidRequests); + 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('Request params check: without adSlot', function () { delete bidRequests[0].params.adSlot; let request = spec.buildRequests(bidRequests); @@ -1034,318 +1108,132 @@ 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() + 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; }); - 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, {}); + 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); 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); + data = data.imp[0]; + expect(data.bidfloor).to.equal(undefined); }); - 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, {}); + 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); 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); + data = data.imp[0]; + expect(data.bidfloor).to.equal(2.5); // video will be lowest now }); - 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, {}); + 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); 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); + data = data.imp[0]; + expect(data.bidfloor).to.equal(2.5); // video will be lowest now }); - 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, {}); + it('kadfloor is not passed, use minimum from floorModule', function() { + newRequest[0].params.kadfloor = undefined; + let request = spec.buildRequests(newRequest); 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); + 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, {}); + 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); 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); - } + data = data.imp[0]; + expect(data.bidfloor).to.equal(3); }); - 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, {}); + 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); 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); - } + data = data.imp[0]; + expect(data.bidfloor).to.equal(1.5); }); }); - 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' - } - }] - }]); - }); - - 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]; - }); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); - }); - - 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('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); + } + }); - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.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('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]; - }); - - let request = spec.buildRequests(bidRequests, {}); - let data = JSON.parse(request.data); - expect(data.user.eids).to.deep.equal(undefined); + 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() { @@ -1361,6 +1249,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([{ @@ -1388,6 +1277,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([{ @@ -1418,161 +1308,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([{ @@ -1587,54 +1328,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); @@ -1645,6 +1354,7 @@ describe('PubMatic adapter', function () { it('send the id5 id if it is present', function() { bidRequests[0].userId = {}; bidRequests[0].userId.id5id = '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([{ @@ -1659,18 +1369,22 @@ describe('PubMatic adapter', function () { it('do not pass if not string', function() { bidRequests[0].userId = {}; bidRequests[0].userId.id5id = 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].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].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].userIdAsEids = createEidsArray(bidRequests[0].userId); request = spec.buildRequests(bidRequests, {}); data = JSON.parse(request.data); expect(data.user.eids).to.equal(undefined); @@ -1681,6 +1395,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([{ @@ -1695,18 +1410,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); @@ -1717,6 +1436,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([{ @@ -1731,18 +1451,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); @@ -1753,6 +1477,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([{ @@ -1767,18 +1492,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); @@ -1789,6 +1518,7 @@ describe('PubMatic adapter', function () { it('send the Parrable id if it is present', function() { bidRequests[0].userId = {}; bidRequests[0].userId.parrableid = '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([{ @@ -1803,18 +1533,22 @@ describe('PubMatic adapter', function () { it('do not pass if not string', 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); @@ -1825,6 +1559,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([{ @@ -1839,18 +1574,63 @@ 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); + }); + }); + + describe('NetId', 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([{ + 'source': 'netid.de', + 'uids': [{ + 'id': 'netid-user-id', + 'atype': 1 + }] + }]); + }); + + 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); @@ -2299,6 +2079,112 @@ describe('PubMatic adapter', function () { expect(data.site.ext).to.not.exist; }); + it('Request params deals check', function () { + let multipleBidRequests = [ + { + bidder: 'pubmatic', + params: { + publisherId: '301', + adSlot: '/15671365/DMDemo@300x250:0', + kadfloor: '1.2', + pmzoneid: 'aabc, ddef', + kadpageurl: 'www.publisher.com', + yob: '1986', + gender: 'M', + lat: '12.3', + lon: '23.7', + wiid: '1234567890', + profId: '100', + verId: '200', + currency: 'AUD', + deals: ['deal-id-1', 'deal-id-2', 'dea'] // "dea" will not be passed as more than 3 characters needed + }, + placementCode: '/19968336/header-bid-tag-1', + sizes: [[300, 250], [300, 600]], + bidId: '23acc48ad47af5', + requestId: '0fb4905b-9456-4152-86be-c6f6d259ba99', + bidderRequestId: '1c56ad30b9b8ca8', + transactionId: '92489f71-1bf2-49a0-adf9-000cea934729' + }, + { + bidder: 'pubmatic', + params: { + publisherId: '301', + adSlot: '/15671365/DMDemo@300x250:0', + kadfloor: '1.2', + pmzoneid: 'aabc, ddef', + kadpageurl: 'www.publisher.com', + yob: '1986', + gender: 'M', + lat: '12.3', + lon: '23.7', + wiid: '1234567890', + profId: '100', + verId: '200', + currency: 'GBP', + deals: ['deal-id-100', 'deal-id-200'] + }, + placementCode: '/19968336/header-bid-tag-1', + sizes: [[300, 250], [300, 600]], + bidId: '23acc48ad47af5', + requestId: '0fb4905b-9456-4152-86be-c6f6d259ba99', + bidderRequestId: '1c56ad30b9b8ca8', + transactionId: '92489f71-1bf2-49a0-adf9-000cea934729' + } + ]; + + let request = spec.buildRequests(multipleBidRequests); + let data = JSON.parse(request.data); + // case 1 - deals are passed as expected, ['', ''] , in both adUnits + expect(data.imp[0].pmp).to.deep.equal({ + 'private_auction': 0, + 'deals': [ + { + 'id': 'deal-id-1' + }, + { + 'id': 'deal-id-2' + } + ] + }); + expect(data.imp[1].pmp).to.deep.equal({ + 'private_auction': 0, + 'deals': [ + { + 'id': 'deal-id-100' + }, + { + 'id': 'deal-id-200' + } + ] + }); + + // case 2 - deals not present in adunit[0] + delete multipleBidRequests[0].params.deals; + request = spec.buildRequests(multipleBidRequests); + 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); + 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); + data = JSON.parse(request.data); + expect(data.imp[0].pmp).to.deep.equal({ + 'private_auction': 0, + 'deals': [ + { + 'id': 'deal-id-1' + } + ] + }); + }); + describe('Request param bcat checking', function() { let multipleBidRequests = [ { @@ -2413,10 +2299,14 @@ describe('PubMatic adapter', function () { expect(response[0].netRevenue).to.equal(false); expect(response[0].ttl).to.equal(300); expect(response[0].meta.networkId).to.equal(123); + 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].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)); @@ -2432,10 +2322,14 @@ describe('PubMatic adapter', function () { expect(response[1].netRevenue).to.equal(false); expect(response[1].ttl).to.equal(300); expect(response[1].meta.networkId).to.equal(422); + 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].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 () { @@ -2498,37 +2392,53 @@ describe('PubMatic adapter', function () { }); describe('getUserSyncs', function() { - const syncurl = 'https://ads.pubmatic.com/AdServer/js/showad.js#PIX&kdntuid=1&p=5670'; + const syncurl_iframe = 'https://ads.pubmatic.com/AdServer/js/showad.js#PIX&kdntuid=1&p=5670'; + const syncurl_image = 'https://image8.pubmatic.com/AdServer/ImgSync?p=5670'; let sandbox; beforeEach(function () { sandbox = sinon.sandbox.create(); }); afterEach(function() { sandbox.restore(); - }) + }); - it('execute only if iframeEnabled', function() { + it('execute as per config', function() { expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, undefined)).to.deep.equal([{ - type: 'iframe', url: syncurl + type: 'iframe', url: syncurl_iframe + }]); + expect(spec.getUserSyncs({ iframeEnabled: false }, {}, undefined, undefined)).to.deep.equal([{ + type: 'image', url: syncurl_image }]); - expect(spec.getUserSyncs({ iframeEnabled: false }, {}, undefined, undefined)).to.equal(undefined); }); it('CCPA/USP', function() { expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, '1NYN')).to.deep.equal([{ - type: 'iframe', url: `${syncurl}&us_privacy=1NYN` + type: 'iframe', url: `${syncurl_iframe}&us_privacy=1NYN` + }]); + expect(spec.getUserSyncs({ iframeEnabled: false }, {}, undefined, '1NYN')).to.deep.equal([{ + type: 'image', url: `${syncurl_image}&us_privacy=1NYN` }]); }); it('GDPR', function() { expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, undefined)).to.deep.equal([{ - type: 'iframe', url: `${syncurl}&gdpr=1&gdpr_consent=foo` + type: 'iframe', url: `${syncurl_iframe}&gdpr=1&gdpr_consent=foo` }]); expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: false, consentString: 'foo'}, undefined)).to.deep.equal([{ - type: 'iframe', url: `${syncurl}&gdpr=0&gdpr_consent=foo` + type: 'iframe', url: `${syncurl_iframe}&gdpr=0&gdpr_consent=foo` }]); expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: true, consentString: undefined}, undefined)).to.deep.equal([{ - type: 'iframe', url: `${syncurl}&gdpr=1&gdpr_consent=` + type: 'iframe', url: `${syncurl_iframe}&gdpr=1&gdpr_consent=` + }]); + + expect(spec.getUserSyncs({ iframeEnabled: false }, {}, {gdprApplies: true, consentString: 'foo'}, undefined)).to.deep.equal([{ + type: 'image', url: `${syncurl_image}&gdpr=1&gdpr_consent=foo` + }]); + expect(spec.getUserSyncs({ iframeEnabled: false }, {}, {gdprApplies: false, consentString: 'foo'}, undefined)).to.deep.equal([{ + type: 'image', url: `${syncurl_image}&gdpr=0&gdpr_consent=foo` + }]); + expect(spec.getUserSyncs({ iframeEnabled: false }, {}, {gdprApplies: true, consentString: undefined}, undefined)).to.deep.equal([{ + type: 'image', url: `${syncurl_image}&gdpr=1&gdpr_consent=` }]); }); @@ -2540,7 +2450,10 @@ describe('PubMatic adapter', function () { return config[key]; }); expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, undefined)).to.deep.equal([{ - type: 'iframe', url: `${syncurl}&coppa=1` + type: 'iframe', url: `${syncurl_iframe}&coppa=1` + }]); + expect(spec.getUserSyncs({ iframeEnabled: false }, {}, undefined, undefined)).to.deep.equal([{ + type: 'image', url: `${syncurl_image}&coppa=1` }]); }); @@ -2552,7 +2465,10 @@ describe('PubMatic adapter', function () { return config[key]; }); expect(spec.getUserSyncs({ iframeEnabled: true }, {}, undefined, undefined)).to.deep.equal([{ - type: 'iframe', url: `${syncurl}` + type: 'iframe', url: `${syncurl_iframe}` + }]); + expect(spec.getUserSyncs({ iframeEnabled: false }, {}, undefined, undefined)).to.deep.equal([{ + type: 'image', url: `${syncurl_image}` }]); }); @@ -2564,7 +2480,10 @@ describe('PubMatic adapter', function () { return config[key]; }); expect(spec.getUserSyncs({ iframeEnabled: true }, {}, {gdprApplies: true, consentString: 'foo'}, '1NYN')).to.deep.equal([{ - type: 'iframe', url: `${syncurl}&gdpr=1&gdpr_consent=foo&us_privacy=1NYN&coppa=1` + type: 'iframe', url: `${syncurl_iframe}&gdpr=1&gdpr_consent=foo&us_privacy=1NYN&coppa=1` + }]); + expect(spec.getUserSyncs({ iframeEnabled: false }, {}, {gdprApplies: true, consentString: 'foo'}, '1NYN')).to.deep.equal([{ + type: 'image', url: `${syncurl_image}&gdpr=1&gdpr_consent=foo&us_privacy=1NYN&coppa=1` }]); }); }); diff --git a/test/spec/modules/pubstackAnalyticsAdapter_spec.js b/test/spec/modules/pubstackAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..e3db334c888 --- /dev/null +++ b/test/spec/modules/pubstackAnalyticsAdapter_spec.js @@ -0,0 +1,38 @@ +import * as utils from 'src/utils.js'; +import pubstackAnalytics from '../../../modules/pubstackAnalyticsAdapter.js'; +import adapterManager from 'src/adapterManager'; +import events from 'src/events'; +import constants from 'src/constants.json' + +describe('Pubstack Analytics Adapter', () => { + const scope = utils.getWindowSelf(); + let queue = []; + + beforeEach(() => { + scope.PubstackAnalytics = (...args) => queue.push(args); + adapterManager.enableAnalytics({ + provider: 'pubstack' + }); + queue = [] + }); + + afterEach(() => { + pubstackAnalytics.disableAnalytics(); + }); + + it('should forward all events to the queue', () => { + // Given + const args = 'any-args' + + // When + events.emit(constants.EVENTS.AUCTION_END, args) + events.emit(constants.EVENTS.BID_REQUESTED, args) + events.emit(constants.EVENTS.BID_ADJUSTMENT, args) + events.emit(constants.EVENTS.BID_RESPONSE, args) + events.emit(constants.EVENTS.BID_WON, args) + events.emit(constants.EVENTS.NO_BID, args) + + // Then + expect(queue.length).to.eql(6); + }); +}); diff --git a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js index b2235212cbf..5e4b2be894e 100644 --- a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js +++ b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js @@ -1,4 +1,4 @@ -import pubwiseAnalytics from 'modules/pubwiseAnalyticsAdapter'; +import pubwiseAnalytics from 'modules/pubwiseAnalyticsAdapter.js'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; let constants = require('src/constants.json'); diff --git a/test/spec/modules/pulsepointBidAdapter_spec.js b/test/spec/modules/pulsepointBidAdapter_spec.js index 80cf00d2ff8..4b21856b68e 100644 --- a/test/spec/modules/pulsepointBidAdapter_spec.js +++ b/test/spec/modules/pulsepointBidAdapter_spec.js @@ -1,11 +1,16 @@ /* eslint dot-notation:0, quote-props:0 */ import {expect} from 'chai'; -import {spec} from 'modules/pulsepointBidAdapter'; -import {deepClone} from 'src/utils'; +import {spec} from 'modules/pulsepointBidAdapter.js'; +import {deepClone} from 'src/utils.js'; describe('PulsePoint Adapter Tests', function () { const slotConfigs = [{ placementCode: '/DfpAccount1/slot1', + mediaTypes: { + banner: { + sizes: [[728, 90], [160, 600]] + } + }, bidId: 'bid12345', params: { cp: 'p10000', @@ -655,4 +660,45 @@ describe('PulsePoint Adapter Tests', function () { userVerify(ortbRequest.user.ext.eids[4], 'parrable.com', 'parrable_id234'); userVerify(ortbRequest.user.ext.eids[5], 'liveintent.com', 'liveintent_id123'); }); + it('Verify multiple adsizes', function () { + const bidRequests = deepClone(slotConfigs); + const request = spec.buildRequests(bidRequests, bidderRequest); + expect(request).to.be.not.null; + expect(request.data).to.be.not.null; + const ortbRequest = request.data; + expect(ortbRequest.imp).to.have.lengthOf(2); + // first impression has multi sizes + expect(ortbRequest.imp[0].banner).to.not.be.null; + expect(ortbRequest.imp[0].banner.w).to.equal(300); + expect(ortbRequest.imp[0].banner.h).to.equal(250); + expect(ortbRequest.imp[0].banner.format).to.not.be.null; + expect(ortbRequest.imp[0].banner.format).to.have.lengthOf(2); + expect(ortbRequest.imp[0].banner.format[0].w).to.equal(728); + expect(ortbRequest.imp[0].banner.format[0].h).to.equal(90); + expect(ortbRequest.imp[0].banner.format[1].w).to.equal(160); + expect(ortbRequest.imp[0].banner.format[1].h).to.equal(600); + // slot 2 + expect(ortbRequest.imp[1].banner).to.not.be.null; + expect(ortbRequest.imp[1].banner.w).to.equal(728); + expect(ortbRequest.imp[1].banner.h).to.equal(90); + expect(ortbRequest.imp[1].banner.format).to.be.null; + // adsize on response + const ortbResponse = { + seatbid: [{ + bid: [{ + impid: ortbRequest.imp[0].id, + price: 1.25, + adm: 'This is an Ad', + crid: 'Creative#123', + w: 728, + h: 90 + }] + }] + }; + const bids = spec.interpretResponse({ body: ortbResponse }, request); + expect(bids).to.have.lengthOf(1); + const bid = bids[0]; + expect(bid.width).to.equal(728); + expect(bid.height).to.equal(90); + }); }); diff --git a/test/spec/modules/playgroundxyzBidAdapter_spec.js b/test/spec/modules/pxyzBidAdapter_spec.js similarity index 80% rename from test/spec/modules/playgroundxyzBidAdapter_spec.js rename to test/spec/modules/pxyzBidAdapter_spec.js index 5d02cede9af..6d8c6056076 100644 --- a/test/spec/modules/playgroundxyzBidAdapter_spec.js +++ b/test/spec/modules/pxyzBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; -import { spec } from 'modules/playgroundxyzBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; -import { deepClone } from 'src/utils'; +import { spec } from 'modules/pxyzBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import { deepClone } from 'src/utils.js'; const URL = 'https://ads.playground.xyz/host-config/prebid?v=2'; const GDPR_CONSENT = 'XYZ-CONSENT'; @@ -12,7 +12,7 @@ const BIDDER_REQUEST = { } }; -describe('playgroundxyzBidAdapter', function () { +describe('pxyzBidAdapter', function () { const adapter = newBidder(spec); describe('inherited functions', function () { @@ -23,7 +23,7 @@ describe('playgroundxyzBidAdapter', function () { describe('isBidRequestValid', function () { let bid = { - 'bidder': 'playgroundxyz', + 'bidder': 'pxyz', 'params': { 'placementId': '10433394' }, @@ -51,7 +51,7 @@ describe('playgroundxyzBidAdapter', function () { describe('buildRequests', function () { let bidRequests = [ { - 'bidder': 'playgroundxyz', + 'bidder': 'pxyz', 'params': { 'placementId': '10433394' }, @@ -75,13 +75,35 @@ describe('playgroundxyzBidAdapter', function () { expect(request.method).to.equal('POST'); }); + describe('CCPA', function () { + describe('when USP consent object is NOT present in bidder request', function () { + const request = spec.buildRequests(bidRequests, BIDDER_REQUEST); + const data = JSON.parse(request.data); + it('should not populate ext.gdpr or ext.consent', function () { + expect(data).to.not.have.property('Regs.ext.us_privacy'); + }); + }); + + describe('when USP consent object is present in bidder request', function () { + describe('when GDPR is applicable', function () { + const request = spec.buildRequests( + bidRequests, + Object.assign({}, BIDDER_REQUEST, { uspConsent: '1YYY' }) + ); + const data = JSON.parse(request.data); + it('should set Regs.ext.us_privacy with the correct value', function () { + expect(data.Regs.ext['us_privacy']).to.equal('1YYY'); + }); + }); + }); + }); + describe('GDPR', function () { describe('when no GDPR consent object is present in bidder request', function () { const request = spec.buildRequests(bidRequests, BIDDER_REQUEST); const data = JSON.parse(request.data); it('should not populate ext.gdpr or ext.consent', function () { - expect(data).to.not.have.property('user'); - expect(data).to.not.have.property('regs'); + expect(data).to.not.have.property('Regs.ext.consent'); }); }); @@ -95,10 +117,10 @@ describe('playgroundxyzBidAdapter', function () { ); const data = JSON.parse(request.data); it('should set ext.gdpr with 1', function () { - expect(data.regs.ext.gdpr).to.equal(1); + expect(data.Regs.ext.gdpr).to.equal(1); }); it('should set ext.consent', function () { - expect(data.user.ext.consent).to.equal('XYZ-CONSENT'); + expect(data.User.ext.consent).to.equal('XYZ-CONSENT'); }); }); describe('when GDPR is NOT applicable', function () { @@ -110,10 +132,10 @@ describe('playgroundxyzBidAdapter', function () { ); const data = JSON.parse(request.data); it('should set ext.gdpr to 0', function () { - expect(data.regs.ext.gdpr).to.equal(0); + expect(data.Regs.ext.gdpr).to.equal(0); }); it('should populate ext.consent', function () { - expect(data.user.ext.consent).to.equal('XYZ-CONSENT'); + expect(data.User.ext.consent).to.equal('XYZ-CONSENT'); }); }); }); @@ -154,7 +176,7 @@ describe('playgroundxyzBidAdapter', function () { }; let bidderRequest = { - 'bidderCode': 'playgroundxyz' + 'bidderCode': 'pxyz' }; it('should get correct bid response', function () { diff --git a/test/spec/modules/quantcastBidAdapter_spec.js b/test/spec/modules/quantcastBidAdapter_spec.js index 7e7d47d3644..cd168ec61e6 100644 --- a/test/spec/modules/quantcastBidAdapter_spec.js +++ b/test/spec/modules/quantcastBidAdapter_spec.js @@ -8,9 +8,10 @@ import { QUANTCAST_PROTOCOL, QUANTCAST_PORT, spec as qcSpec -} from '../../../modules/quantcastBidAdapter'; -import { newBidder } from '../../../src/adapters/bidderFactory'; -import { parse } from 'src/url'; +} from '../../../modules/quantcastBidAdapter.js'; +import { newBidder } from '../../../src/adapters/bidderFactory.js'; +import { parseUrl } from 'src/utils.js'; +import { config } from 'src/config.js'; describe('Quantcast adapter', function () { const quantcastAdapter = newBidder(qcSpec); @@ -89,13 +90,13 @@ describe('Quantcast adapter', function () { describe('`buildRequests`', function () { it('sends secure bid requests', function () { const requests = qcSpec.buildRequests([bidRequest]); - const url = parse(requests[0]['url']); + const url = parseUrl(requests[0]['url']); expect(url.protocol).to.equal('https'); }); it('sends bid requests to Quantcast Canary Endpoint if `publisherId` is `test-publisher`', function () { const requests = qcSpec.buildRequests([bidRequest]); - const url = parse(requests[0]['url']); + const url = parseUrl(requests[0]['url']); expect(url.hostname).to.equal(QUANTCAST_TEST_DOMAIN); }); @@ -138,6 +139,7 @@ describe('Quantcast adapter', function () { bidId: '2f7b179d443f14', gdprSignal: 0, uspSignal: 0, + coppa: 0, prebidJsVersion: '$prebid.version$' }; @@ -205,6 +207,7 @@ describe('Quantcast adapter', function () { bidId: '2f7b179d443f14', gdprSignal: 0, uspSignal: 0, + coppa: 0, prebidJsVersion: '$prebid.version$' }; @@ -240,6 +243,7 @@ describe('Quantcast adapter', function () { bidId: '2f7b179d443f14', gdprSignal: 0, uspSignal: 0, + coppa: 0, prebidJsVersion: '$prebid.version$' }; @@ -271,6 +275,7 @@ describe('Quantcast adapter', function () { bidId: '2f7b179d443f14', gdprSignal: 0, uspSignal: 0, + coppa: 0, prebidJsVersion: '$prebid.version$' }; @@ -334,6 +339,7 @@ describe('Quantcast adapter', function () { bidId: '2f7b179d443f14', gdprSignal: 0, uspSignal: 0, + coppa: 0, prebidJsVersion: '$prebid.version$' }; @@ -342,13 +348,254 @@ describe('Quantcast adapter', function () { }); it('propagates GDPR consent string and signal', function () { - const bidderRequest = { gdprConsent: { gdprApplies: true, consentString: 'consentString' } } + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentString' + } + }; + + 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 v1 request with consent for purpose 1', function () { + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + vendorConsents: { + '11': true + }, + purposeConsents: { + '1': true + } + }, + apiVersion: 1 + } + }; + + 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('blocks TCF v1 request without vendor consent', function () { + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + vendorConsents: { + '11': false + }, + purposeConsents: { + '1': true + } + }, + apiVersion: 1 + } + }; + + const requests = qcSpec.buildRequests([bidRequest], bidderRequest); + + expect(requests).to.equal(undefined); + }); + + it('blocks TCF v1 request without consent for purpose 1', function () { + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + vendorConsents: { + '11': true + }, + purposeConsents: { + '1': false + } + }, + apiVersion: 1 + } + }; + + const requests = qcSpec.buildRequests([bidRequest], bidderRequest); + + 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: { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + vendor: { + consents: { + '11': true + } + }, + purpose: { + consents: { + '1': 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('blocks TCF v2 request when no consent for Quantcast', function() { + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + vendor: { + consents: { + '11': false + } + }, + purpose: { + consents: { + '1': true + } + } + }, + apiVersion: 2 + } + }; + + const requests = qcSpec.buildRequests([bidRequest], bidderRequest); + + expect(requests).to.equal(undefined); + }); + + it('blocks TCF v2 request when no consent for purpose 1', function() { + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + vendor: { + consents: { + '11': true + } + }, + purpose: { + consents: { + '1': false + } + } + }, + apiVersion: 2 + } + }; + + const requests = qcSpec.buildRequests([bidRequest], bidderRequest); + + expect(requests).to.equal(undefined); + }); + + it('blocks TCF v2 request when Quantcast not allowed by publisher', function () { + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + vendor: { + consents: { + '11': true + } + }, + purpose: { + consents: { + '1': true + } + }, + publisher: { + restrictions: { + '1': { + '11': 0 + } + } + } + }, + apiVersion: 2 + } + }; + + const requests = qcSpec.buildRequests([bidRequest], bidderRequest); + + expect(requests).to.equal(undefined); + }); + + it('blocks TCF v2 request when legitimate interest required', function () { + const bidderRequest = { + gdprConsent: { + gdprApplies: true, + consentString: 'consentString', + vendorData: { + vendor: { + consents: { + '11': true + } + }, + purpose: { + consents: { + '1': true + } + }, + publisher: { + restrictions: { + '1': { + '11': 2 + } + } + } + }, + apiVersion: 2 + } + }; + + const requests = qcSpec.buildRequests([bidRequest], bidderRequest); + + expect(requests).to.equal(undefined); + }); + it('propagates US Privacy/CCPA consent information', function () { const bidderRequest = { uspConsent: 'consentString' } const requests = qcSpec.buildRequests([bidRequest], bidderRequest); @@ -357,6 +604,50 @@ describe('Quantcast adapter', function () { expect(parsed.uspConsent).to.equal('consentString'); }); + describe('propagates coppa', function() { + let sandbox; + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('propagates coppa as 1 if coppa param is set to true in the bid request', function () { + bidRequest.params = { + publisherId: 'test_publisher_id', + coppa: true + }; + sandbox.stub(config, 'getConfig').callsFake((key) => { + const config = { + 'coppa': true + }; + return config[key]; + }); + const requests = qcSpec.buildRequests([bidRequest], bidderRequest); + expect(JSON.parse(requests[0].data).coppa).to.equal(1); + }); + + it('propagates coppa as 0 if there is no coppa param or coppa is set to false in the bid request', function () { + const requestsWithoutCoppa = qcSpec.buildRequests([bidRequest], bidderRequest); + expect(JSON.parse(requestsWithoutCoppa[0].data).coppa).to.equal(0); + + bidRequest.params = { + publisherId: 'test_publisher_id', + coppa: false + }; + sandbox.stub(config, 'getConfig').callsFake((key) => { + const config = { + 'coppa': false + }; + return config[key]; + }); + const requestsWithFalseCoppa = qcSpec.buildRequests([bidRequest], bidderRequest); + expect(JSON.parse(requestsWithFalseCoppa[0].data).coppa).to.equal(0); + }); + }); + describe('`interpretResponse`', function () { // The sample response is from https://wiki.corp.qc/display/adinf/QCX const body = { @@ -492,5 +783,67 @@ describe('Quantcast adapter', function () { expect(interpretedResponse.length).to.equal(0); }); + + it('should return pixel url when available userSync available', function () { + const syncOptions = { + pixelEnabled: true + }; + const serverResponses = [ + { + body: { + userSync: { + url: 'http://quantcast.com/pixelUrl' + } + } + }, + { + body: { + + } + } + ]; + + const actualSyncs = qcSpec.getUserSyncs(syncOptions, serverResponses); + const expectedSync = { + type: 'image', + url: 'http://quantcast.com/pixelUrl' + }; + expect(actualSyncs.length).to.equal(1); + expect(actualSyncs[0]).to.deep.equal(expectedSync); + qcSpec.resetUserSync(); + }); + + it('should not return user syncs if done already', function () { + const syncOptions = { + pixelEnabled: true + }; + const serverResponses = [ + { + body: { + userSync: { + url: 'http://quantcast.com/pixelUrl' + } + } + }, + { + body: { + + } + } + ]; + + let actualSyncs = qcSpec.getUserSyncs(syncOptions, serverResponses); + const expectedSync = { + type: 'image', + url: 'http://quantcast.com/pixelUrl' + }; + expect(actualSyncs.length).to.equal(1); + expect(actualSyncs[0]).to.deep.equal(expectedSync); + + actualSyncs = qcSpec.getUserSyncs(syncOptions, serverResponses); + expect(actualSyncs.length).to.equal(0); + + qcSpec.resetUserSync(); + }); }); }); diff --git a/test/spec/modules/quantumBidAdapter_spec.js b/test/spec/modules/quantumBidAdapter_spec.js index ba020fbc536..c03d74ea52e 100644 --- a/test/spec/modules/quantumBidAdapter_spec.js +++ b/test/spec/modules/quantumBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai' -import { spec } from 'modules/quantumBidAdapter' -import { newBidder } from 'src/adapters/bidderFactory' +import { spec } from 'modules/quantumBidAdapter.js' +import { newBidder } from 'src/adapters/bidderFactory.js' const ENDPOINT = 'https://s.sspqns.com/hb' const REQUEST = { diff --git a/test/spec/modules/quantumdexBidAdapter_spec.js b/test/spec/modules/quantumdexBidAdapter_spec.js new file mode 100644 index 00000000000..82429cbedae --- /dev/null +++ b/test/spec/modules/quantumdexBidAdapter_spec.js @@ -0,0 +1,604 @@ +import { expect } from 'chai' +import { spec } from 'modules/quantumdexBidAdapter.js' +import { newBidder } from 'src/adapters/bidderFactory.js' +import { userSync } from '../../../src/userSync.js'; + +describe('QuantumdexBidAdapter', function () { + const adapter = newBidder(spec) + + describe('.code', function () { + it('should return a bidder code of quantumdex', function () { + expect(spec.code).to.equal('quantumdex') + }) + }) + + 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': 'quantumdex', + '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': 'quantumdex', + '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': 'quantumdex', + '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': 'quantumdex', + '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': 'quantumdex', + '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': 'quantumdex', + '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': 'quantumdex', + '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': 'quantumdex', + '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': 'quantumdex', + 'params': { + 'siteId': '1a2b3c4d5e6f1a2b3c4d', + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'targetKey': 0, + 'bidId': '30b31c1838de1f', + }, + { + 'bidder': 'quantumdex', + '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]], + 'targetKey': 1, + '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://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/quantumdex') + 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://useast.quantumdex.io/auction/quantumdex') + 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://useast.quantumdex.io/auction/quantumdex') + 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://useast.quantumdex.io/auction/quantumdex') + 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://useast.quantumdex.io/auction/quantumdex', + '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.example.com/page', + 'referrer': '', + 'hostname': 'www.example.com' + } + }, + 'bidderRequests': [ + { + 'bidder': 'quantumdex', + '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': 'quantumdex', + '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': 'quantumdex', + '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': `
Quantumdex AD
`, + 'ttl': 500, + 'creativeId': '1234abcd', + 'netRevenue': true, + 'currency': 'USD', + 'dealId': 'quantumdex', + 'mediaType': 'banner' + }, + { + 'requestId': '30024615be22ef66a', + 'cpm': 1, + 'width': 300, + 'height': 250, + 'ad': `
Quantumdex AD
`, + 'ttl': 500, + 'creativeId': '1234abcd', + 'netRevenue': true, + 'currency': 'USD', + 'dealId': 'quantumdex', + 'mediaType': 'banner' + }, + { + 'requestId': '1854b40107d6745c', + 'cpm': 1.25, + 'width': 300, + 'height': 250, + 'vastXml': 'quantumdex', + 'ttl': 500, + 'creativeId': '30292e432662bd5f86d90774b944b038', + 'netRevenue': true, + 'currency': 'USD', + 'dealId': 'quantumdex', + 'mediaType': 'video' + } + ], + 'pixel': [{ + 'url': 'https://example.com/pixel.png', + 'type': 'image' + }] + } + }; + + let prebidResponse = [ + { + 'requestId': '3000aa31c41a29c21', + 'cpm': 1.07, + 'width': 160, + 'height': 600, + 'ad': `
Quantumdex AD
`, + 'ttl': 500, + 'creativeId': '1234abcd', + 'netRevenue': true, + 'currency': 'USD', + 'dealId': 'quantumdex', + 'mediaType': 'banner' + }, + { + 'requestId': '30024615be22ef66a', + 'cpm': 1, + 'width': 300, + 'height': 250, + 'ad': `
Quantumdex AD
`, + 'ttl': 500, + 'creativeId': '1234abcd', + 'netRevenue': true, + 'currency': 'USD', + 'dealId': 'quantumdex', + 'mediaType': 'banner' + }, + { + 'requestId': '1854b40107d6745c', + 'cpm': 1.25, + 'width': 300, + 'height': 250, + 'vastXml': 'quantumdex', + 'ttl': 500, + 'creativeId': '30292e432662bd5f86d90774b944b038', + 'netRevenue': true, + 'currency': 'USD', + 'dealId': 'quantumdex', + '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('quantumdex')).to.be.greaterThan(0); + } + if (resp.mediaType === 'banner') { + expect(resp.ad.indexOf('Quantumdex 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/radsBidAdapter_spec.js b/test/spec/modules/radsBidAdapter_spec.js index 6981955f261..c629daf3da5 100644 --- a/test/spec/modules/radsBidAdapter_spec.js +++ b/test/spec/modules/radsBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/radsBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/radsBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const RADS_ENDPOINT_URL = 'https://rads.recognified.net/md.request.php'; diff --git a/test/spec/modules/rakutenBidAdapter_spec.js b/test/spec/modules/rakutenBidAdapter_spec.js new file mode 100644 index 00000000000..15b22afbe29 --- /dev/null +++ b/test/spec/modules/rakutenBidAdapter_spec.js @@ -0,0 +1,171 @@ +import { expect } from 'chai' +import { spec } from 'modules/rakutenBidAdapter/index.js' +import { newBidder } from 'src/adapters/bidderFactory.js' +import {config} from '../../../src/config.js'; + +describe('rakutenBidAdapter', function() { + const adapter = newBidder(spec); + const ENDPOINT = 'https://s-bid.rmp.rakuten.com/h'; + let sandbox; + + beforeEach(function() { + config.resetConfig(); + }); + + afterEach(function () { + config.resetConfig(); + }); + + describe('inherited functions', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function') + }) + }); + + describe('isBidRequestValid', () => { + let bid = { + bidder: 'rakuten', + params: { + adSpotId: '56789' + } + }; + + it('should return true when required params found', () => { + expect(spec.isBidRequestValid(bid)).to.equal(true) + }); + + it('should return false when required params are not passed', () => { + bid.params.adSpotId = ''; + expect(spec.isBidRequestValid(bid)).to.equal(false) + }); + + it('should return false when required params are not passed', () => { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false) + }) + }); + + describe('buildRequests', () => { + const bidRequests = [ + { + // banner + params: { + adSpotId: '58278' + } + } + ]; + + const bidderRequest = { + bids: bidRequests, + refererInfo: { + referer: 'http://test.com', + stack: ['http://test.com'] + }, + gdprConsent: { + consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + vendorData: {}, + gdprApplies: true + }, + uspConsent: '1YN-' + }; + + it('sends bid request to ENDPOINT via GET', () => { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.url).to.equal(ENDPOINT); + expect(request.method).to.equal('GET') + expect(request.data.gdpr).to.equal(1); + expect(request.data.cd).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A=='); + expect(request.data.ccpa).to.equal('1YN-'); + }); + + it('allows url override', () => { + config.setConfig({ + rakuten: { + endpoint: '//test.rakuten.com' + } + }); + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.url).to.equal('//test.rakuten.com'); + }) + }); + + describe('interpretResponse', () => { + const bidRequests = { + banner: { + method: 'GET', + url: '', + data: { + t: '56789', + s: 'https', + ua: + 'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Mobile Safari/537.36', + l: 'ja', + d: 'examples.com', + tp: 'https://examples.com/foo/fuga', + pp: 'https://examples.com/hoge/muga' + } + } + }; + + const serverResponse = { + noAd: [], + noAd2: { + requestId: 'biequa9oaph4we' + }, + banner: { + requestId: 'biequa9oaph4we', + cpm: 37.66, + width: 300, + height: 250, + creativeId: 140281, + dealId: 'phoh3pad-ai4ah-xoh7x-ahk7cheasae3oh', + currency: 'USD', + netRevenue: 300, + ttl: 3000, + ad: '' + } + }; + + it('handles nobid responses', () => { + const result = spec.interpretResponse( + { body: serverResponse.noAd }, + bidRequests.banner + ); + expect(result.length).to.equal(0); + + const result2 = spec.interpretResponse( + { body: serverResponse.noAd2 }, + bidRequests.banner + ); + expect(result2.length).to.equal(0); + }) + }); + describe('spec.getUserSyncs', function () { + const syncResponse = [{ + body: { + request_id: 'biequa9oaph4we', + sync_urls: ['https://rdn1.test/sync?uid=9876543210', 'https://rdn2.test/sync?uid=9876543210'] + } + }]; + const nosyncResponse = [{ + body: { + request_id: 'biequa9oaph4we', + sync_urls: [] + } + }]; + let syncOptions + beforeEach(function () { + syncOptions = { + pixelEnabled: true + } + }); + it('sucess usersync url', function () { + const result = []; + result.push({type: 'image', url: 'https://rdn1.test/sync?uid=9876543210'}); + result.push({type: 'image', url: 'https://rdn2.test/sync?uid=9876543210'}); + expect(spec.getUserSyncs(syncOptions, syncResponse)).to.deep.equal(result); + }); + }); +}); diff --git a/test/spec/modules/readpeakBidAdapter_spec.js b/test/spec/modules/readpeakBidAdapter_spec.js index 06971169e2a..eb9077fac39 100644 --- a/test/spec/modules/readpeakBidAdapter_spec.js +++ b/test/spec/modules/readpeakBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; -import { spec, ENDPOINT } from 'modules/readpeakBidAdapter'; -import { config } from 'src/config'; -import { parse as parseUrl } from 'src/url'; +import { spec, ENDPOINT } from 'modules/readpeakBidAdapter.js'; +import { config } from 'src/config.js'; +import { parseUrl } from 'src/utils.js'; describe('ReadPeakAdapter', function() { let bidRequest; diff --git a/test/spec/modules/realTimeModule_spec.js b/test/spec/modules/realTimeModule_spec.js index 6f54df01c51..ca149fe7a44 100644 --- a/test/spec/modules/realTimeModule_spec.js +++ b/test/spec/modules/realTimeModule_spec.js @@ -2,20 +2,26 @@ import { init, requestBidsHook, setTargetsAfterRequestBids, - deepMerge -} from 'modules/rtdModule/index'; + deepMerge, + validateProviderDataForGPT +} from 'modules/rtdModule/index.js'; import { init as browsiInit, addBrowsiTag, isIdMatchingAdUnit, - setData -} from 'modules/browsiRtdProvider'; -import {config} from 'src/config'; -import {makeSlot} from '../integration/faker/googletag'; + setData, + getMacroId +} from 'modules/browsiRtdProvider.js'; +import { + init as audigentInit, + setData as setAudigentData +} from 'modules/audigentRtdProvider.js'; +import { config } from 'src/config.js'; +import { makeSlot } from '../integration/faker/googletag.js'; let expect = require('chai').expect; -describe('Real time module', function() { +describe('Real time module', function () { const conf = { 'realTimeData': { 'auctionDelay': 250, @@ -27,13 +33,14 @@ describe('Real time module', function() { 'pubKey': 'testPub', 'keyName': 'bv' } + }, { + 'name': 'audigent' }] - } }; - const predictions = - {p: { + const predictions = { + p: { 'browsiAd_2': { 'w': [ '/57778053/Browsi_Demo_Low', @@ -56,27 +63,36 @@ describe('Real time module', function() { 'p': 0.85 } } - }; + }; + + const audigentSegments = { + audigent_segments: { 'a': 1, 'b': 2 } + } function getAdUnitMock(code = 'adUnit-code') { return { code, - mediaTypes: {banner: {}, native: {}}, + mediaTypes: { banner: {}, native: {} }, sizes: [[300, 200], [300, 600]], - bids: [{bidder: 'sampleBidder', params: {placementId: 'banner-only-bidder'}}] + bids: [{ bidder: 'sampleBidder', params: { placementId: 'banner-only-bidder' } }] }; } function createSlots() { - const slot1 = makeSlot({code: '/57778053/Browsi_Demo_300x250', divId: 'browsiAd_1'}); - return [slot1]; + const slot1 = makeSlot({ code: '/57778053/Browsi_Demo_300x250', divId: 'browsiAd_1' }); + const slot2 = makeSlot({ code: '/57778053/Browsi', divId: 'browsiAd_1' }); + return [slot1, slot2]; } - describe('Real time module with browsi provider', function() { + describe('Real time module with browsi provider', function () { afterEach(function () { $$PREBID_GLOBAL$$.requestBids.removeAll(); }); + after(function () { + config.resetConfig(); + }); + it('check module using bidsBackCallback', function () { let adUnits1 = [getAdUnitMock('browsiAd_1')]; let targeting = []; @@ -96,12 +112,10 @@ describe('Real time module', function() { targeting.push(Object.keys(value).toString()); }); }); - } - setTargetsAfterRequestBids(afterBidHook, adUnits1, true); - setTimeout(() => { expect(targeting.indexOf('bv')).to.be.greaterThan(-1); - }, 200); + } + setTargetsAfterRequestBids(afterBidHook, adUnits1, true); }); it('check module using requestBidsHook', function () { @@ -121,16 +135,15 @@ describe('Real time module', function() { targeting.push(Object.keys(value).toString()); }); }); - } - requestBidsHook(afterBidHook, {adUnits: adUnits1}); - setTimeout(() => { + expect(targeting.indexOf('bv')).to.be.greaterThan(-1); dataReceived.adUnits.forEach(unit => { unit.bids.forEach(bid => { expect(bid.realTimeData).to.have.property('bv'); }); }); - }, 200); + } + requestBidsHook(afterBidHook, { adUnits: adUnits1 }); }); it('check object deep merge', function () { @@ -171,6 +184,28 @@ describe('Real time module', function() { assert.deepEqual(expected, merged); }); + it('check data validation for GPT targeting', function () { + // non strings values should be removed + const obj = { + valid: {'key': 'value'}, + invalid: {'key': ['value']}, + combine: { + 'a': 'value', + 'b': [] + } + }; + + const expected = { + valid: {'key': 'value'}, + invalid: {}, + combine: { + 'a': 'value', + } + }; + const validationResult = validateProviderDataForGPT(obj); + assert.deepEqual(expected, validationResult); + }); + it('check browsi sub module', function () { const script = addBrowsiTag('scriptUrl.com'); expect(script.getAttribute('data-sitekey')).to.equal('testKey'); @@ -178,15 +213,70 @@ describe('Real time module', function() { expect(script.async).to.equal(true); const slots = createSlots(); - const test1 = isIdMatchingAdUnit('browsiAd_1', slots, ['/57778053/Browsi_Demo_300x250']); // true - const test2 = isIdMatchingAdUnit('browsiAd_1', slots, ['/57778053/Browsi_Demo_300x250', '/57778053/Browsi']); // true - const test3 = isIdMatchingAdUnit('browsiAd_1', slots, ['/57778053/Browsi_Demo_Low']); // false - const test4 = isIdMatchingAdUnit('browsiAd_1', slots, []); // true + const test1 = isIdMatchingAdUnit(slots[0], ['/57778053/Browsi_Demo_300x250']); // true + const test2 = isIdMatchingAdUnit(slots[0], ['/57778053/Browsi_Demo_300x250', '/57778053/Browsi']); // true + const test3 = isIdMatchingAdUnit(slots[0], ['/57778053/Browsi_Demo_Low']); // false + const test4 = isIdMatchingAdUnit(slots[0], []); // true expect(test1).to.equal(true); expect(test2).to.equal(true); expect(test3).to.equal(false); expect(test4).to.equal(true); + + // macro results + slots[0].setTargeting('test', ['test', 'value']); + // slot getTargeting doesn't act like GPT so we can't expect real value + const macroResult = getMacroId({p: '/'}, slots[0]); + expect(macroResult).to.equal('/57778053/Browsi_Demo_300x250/NA'); + + const macroResultB = getMacroId({}, slots[0]); + expect(macroResultB).to.equal('browsiAd_1'); + + const macroResultC = getMacroId({p: '', s: {s: 0, e: 1}}, slots[0]); + expect(macroResultC).to.equal('/'); }) }); + + describe('Real time module with Audigent provider', function () { + before(function () { + init(config); + audigentInit(config); + config.setConfig(conf); + setAudigentData(audigentSegments); + }); + + afterEach(function () { + $$PREBID_GLOBAL$$.requestBids.removeAll(); + config.resetConfig(); + }); + + 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); + }); + }); + } + + requestBidsHook(afterBidHook, { adUnits: adUnits1 }); + }); + }); }); diff --git a/test/spec/modules/realvuAnalyticsAdapter_spec.js b/test/spec/modules/realvuAnalyticsAdapter_spec.js index 359fb329359..e51a4e2e3a2 100644 --- a/test/spec/modules/realvuAnalyticsAdapter_spec.js +++ b/test/spec/modules/realvuAnalyticsAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import realvuAnalyticsAdapter, { lib } from 'modules/realvuAnalyticsAdapter'; +import realvuAnalyticsAdapter, { lib } from 'modules/realvuAnalyticsAdapter.js'; import CONSTANTS from 'src/constants.json'; function addDiv(id) { @@ -71,7 +71,7 @@ describe('RealVu', function() { ] }; let result = realvuAnalyticsAdapter.checkIn(bid, '1Y'); - const b = window.top1.realvu_aa; + const b = Object.assign({}, window.top1.realvu_aa); let a = b.ads[0]; // console.log('a: ' + a.x + ', ' + a.y + ', ' + a.w + ', ' + a.h); // console.log('b: ' + b.x1 + ', ' + b.y1 + ', ' + b.x2 + ', ' + b.y2); @@ -116,7 +116,7 @@ describe('RealVu', function() { eventType: CONSTANTS.EVENTS.BID_RESPONSE, args: args }); - const boost = window.top1.realvu_aa; + const boost = Object.assign({}, window.top1.realvu_aa); expect(boost.ads[boost.len - 1].bids.length).to.equal(1); realvuAnalyticsAdapter.track({ @@ -128,8 +128,11 @@ describe('RealVu', function() { }); describe('Boost.', function () { - const boost = window.top1.realvu_aa; - + // const boost = window.top1.realvu_aa; + let boost; + beforeEach(function() { + boost = Object.assign({}, window.top1.realvu_aa); + }); it('brd', function () { let a1 = document.getElementById('ad1'); let p = boost.brd(a1, 'Left'); diff --git a/test/spec/modules/reklamstoreBidAdapter_spec.js b/test/spec/modules/reklamstoreBidAdapter_spec.js index 92f309fd54f..1dcd6c17ca4 100644 --- a/test/spec/modules/reklamstoreBidAdapter_spec.js +++ b/test/spec/modules/reklamstoreBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/reklamstoreBidAdapter'; +import { spec } from 'modules/reklamstoreBidAdapter.js'; describe('reklamstoreBidAdapterTests', function() { let bidRequestData = { diff --git a/test/spec/modules/relaidoBidAdapter_spec.js b/test/spec/modules/relaidoBidAdapter_spec.js new file mode 100644 index 00000000000..cd4918460db --- /dev/null +++ b/test/spec/modules/relaidoBidAdapter_spec.js @@ -0,0 +1,332 @@ +import { expect } from 'chai'; +import { spec } from 'modules/relaidoBidAdapter.js'; +import * as utils from 'src/utils.js'; + +const UUID_KEY = 'relaido_uuid'; +const DEFAULT_USER_AGENT = window.navigator.userAgent; +const MOBILE_USER_AGENT = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1'; + +const setUADefault = () => { window.navigator.__defineGetter__('userAgent', function () { return DEFAULT_USER_AGENT }) }; +const setUAMobile = () => { window.navigator.__defineGetter__('userAgent', function () { return MOBILE_USER_AGENT }) }; + +describe('RelaidoAdapter', function () { + const relaido_uuid = 'hogehoge'; + let bidRequest; + let bidderRequest; + let serverResponse; + let serverRequest; + + beforeEach(function () { + bidRequest = { + bidder: 'relaido', + params: { + placementId: '100000', + }, + mediaTypes: { + video: { + context: 'outstream', + playerSize: [ + [640, 360] + ] + } + }, + adUnitCode: 'test', + bidId: '2ed93003f7bb99', + bidderRequestId: '1c50443387a1f2', + auctionId: '413ed000-8c7a-4ba1-a1fa-9732e006f8c3', + transactionId: '5c2d064c-7b76-42e8-a383-983603afdc45', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0 + }; + bidderRequest = { + timeout: 1000, + refererInfo: { + referer: 'https://publisher.com/home' + } + }; + serverResponse = { + body: { + status: 'ok', + price: 500, + model: 'vcpm', + currency: 'JPY', + creativeId: 1000, + uuid: relaido_uuid, + vast: '', + playerUrl: 'https://relaido/player.js', + syncUrl: 'https://relaido/sync.html' + } + }; + serverRequest = { + method: 'GET', + bidId: bidRequest.bidId, + width: bidRequest.mediaTypes.video.playerSize[0][0], + height: bidRequest.mediaTypes.video.playerSize[0][1], + mediaType: 'video', + }; + localStorage.setItem(UUID_KEY, relaido_uuid); + }); + + describe('spec.isBidRequestValid', function () { + it('should return true when the required params are passed by video', function () { + expect(spec.isBidRequestValid(bidRequest)).to.equal(true); + }); + + it('should return true when the required params are passed by banner', function () { + setUAMobile(); + bidRequest.mediaTypes = { + banner: { + sizes: [ + [300, 250] + ] + } + }; + expect(spec.isBidRequestValid(bidRequest)).to.equal(true); + setUADefault(); + }); + + it('should return false when the uuid are missing', function () { + localStorage.removeItem(UUID_KEY); + const result = !!(utils.isSafariBrowser()); + expect(spec.isBidRequestValid(bidRequest)).to.equal(result); + }); + + it('should return false when the placementId params are missing', function () { + bidRequest.params.placementId = undefined; + expect(spec.isBidRequestValid(bidRequest)).to.equal(false); + }); + + it('should return false when the mediaType video params are missing', function () { + bidRequest.mediaTypes = { + video: {} + }; + expect(spec.isBidRequestValid(bidRequest)).to.equal(false); + }); + + it('should return false when the mediaType banner params are missing', function () { + setUAMobile(); + bidRequest.mediaTypes = { + banner: {} + }; + expect(spec.isBidRequestValid(bidRequest)).to.equal(false); + setUADefault(); + }); + + it('should return false when the non-mobile', function () { + bidRequest.mediaTypes = { + banner: { + sizes: [ + [300, 250] + ] + } + }; + expect(spec.isBidRequestValid(bidRequest)).to.equal(false); + }); + + it('should return false when the mediaTypes params are missing', function () { + bidRequest.mediaTypes = {}; + expect(spec.isBidRequestValid(bidRequest)).to.equal(false); + }); + }); + + describe('spec.buildRequests', function () { + it('should build bid requests by video', function () { + const bidRequests = spec.buildRequests([bidRequest], bidderRequest); + 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/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]); + expect(request.mediaType).to.equal('video'); + expect(request.data.ref).to.equal(bidderRequest.refererInfo.referer); + expect(request.data.timeout_ms).to.equal(bidderRequest.timeout); + expect(request.data.ad_unit_code).to.equal(bidRequest.adUnitCode); + expect(request.data.auction_id).to.equal(bidRequest.auctionId); + expect(request.data.bidder).to.equal(bidRequest.bidder); + expect(request.data.bidder_request_id).to.equal(bidRequest.bidderRequestId); + expect(request.data.bid_requests_count).to.equal(bidRequest.bidRequestsCount); + expect(request.data.bid_id).to.equal(bidRequest.bidId); + expect(request.data.transaction_id).to.equal(bidRequest.transactionId); + expect(request.data.media_type).to.equal('video'); + expect(request.data.uuid).to.equal(relaido_uuid); + expect(request.data.width).to.equal(bidRequest.mediaTypes.video.playerSize[0][0]); + expect(request.data.height).to.equal(bidRequest.mediaTypes.video.playerSize[0][1]); + }); + + it('should build bid requests by banner', function () { + bidRequest.mediaTypes = { + banner: { + sizes: [ + [640, 360] + ] + } + }; + const bidRequests = spec.buildRequests([bidRequest], bidderRequest); + expect(bidRequests).to.have.lengthOf(1); + 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 () { + it('should build bid response by video', function () { + const bidResponses = spec.interpretResponse(serverResponse, serverRequest); + expect(bidResponses).to.have.lengthOf(1); + const response = bidResponses[0]; + expect(response.requestId).to.equal(serverRequest.bidId); + expect(response.width).to.equal(serverRequest.width); + expect(response.height).to.equal(serverRequest.height); + expect(response.cpm).to.equal(serverResponse.body.price); + expect(response.currency).to.equal(serverResponse.body.currency); + expect(response.creativeId).to.equal(serverResponse.body.creativeId); + expect(response.vastXml).to.equal(serverResponse.body.vast); + expect(response.ad).to.be.undefined; + }); + + it('should build bid response by banner', function () { + serverRequest.mediaType = 'banner'; + const bidResponses = spec.interpretResponse(serverResponse, serverRequest); + expect(bidResponses).to.have.lengthOf(1); + const response = bidResponses[0]; + expect(response.requestId).to.equal(serverRequest.bidId); + expect(response.width).to.equal(serverRequest.width); + expect(response.height).to.equal(serverRequest.height); + expect(response.cpm).to.equal(serverResponse.body.price); + expect(response.currency).to.equal(serverResponse.body.currency); + expect(response.creativeId).to.equal(serverResponse.body.creativeId); + expect(response.vastXml).to.be.undefined; + expect(response.ad).to.include(`
`); + expect(response.ad).to.include(``); + expect(response.ad).to.include(`window.RelaidoPlayer.renderAd`); + }); + + it('should not build bid response', function () { + serverResponse = {}; + const bidResponses = spec.interpretResponse(serverResponse, serverRequest); + expect(bidResponses).to.have.lengthOf(0); + }); + + it('should not build bid response', function () { + serverResponse = { + body: { + status: 'no_ad', + } + }; + const bidResponses = spec.interpretResponse(serverResponse, serverRequest); + expect(bidResponses).to.have.lengthOf(0); + }); + }); + + describe('spec.getUserSyncs', function () { + it('should choose iframe sync urls', function () { + let userSyncs = spec.getUserSyncs({iframeEnabled: true}, [serverResponse]); + expect(userSyncs).to.deep.equal([{ + type: 'iframe', + url: serverResponse.body.syncUrl + }]); + }); + + it('should choose iframe sync urls if serverResponse are empty', function () { + let userSyncs = spec.getUserSyncs({iframeEnabled: true}, []); + expect(userSyncs).to.deep.equal([{ + type: 'iframe', + url: 'https://api.relaido.jp/tr/v1/prebid/sync.html' + }]); + }); + + it('should choose iframe sync urls if syncUrl are undefined', function () { + serverResponse.body.syncUrl = undefined; + let userSyncs = spec.getUserSyncs({iframeEnabled: true}, [serverResponse]); + expect(userSyncs).to.deep.equal([{ + type: 'iframe', + url: 'https://api.relaido.jp/tr/v1/prebid/sync.html' + }]); + }); + + it('should return empty if iframeEnabled are false', function () { + let userSyncs = spec.getUserSyncs({iframeEnabled: false}, [serverResponse]); + expect(userSyncs).to.have.lengthOf(0); + }); + }); + + describe('spec.onBidWon', function () { + let stub; + beforeEach(() => { + stub = sinon.stub(utils, 'triggerPixel'); + }); + afterEach(() => { + stub.restore(); + }); + + it('Should create nurl pixel if bid nurl', function () { + let bid = { + bidder: bidRequest.bidder, + creativeId: serverResponse.body.creativeId, + cpm: serverResponse.body.price, + params: [bidRequest.params], + auctionId: bidRequest.auctionId, + requestId: bidRequest.bidId, + adId: '3b286a4db7031f', + adUnitCode: bidRequest.adUnitCode, + ref: window.location.href, + } + spec.onBidWon(bid); + const parser = utils.parseUrl(stub.getCall(0).args[0]); + const query = parser.search; + expect(parser.hostname).to.equal('api.relaido.jp'); + expect(parser.pathname).to.equal('/tr/v1/prebid/win.gif'); + expect(query.placement_id).to.equal('100000'); + expect(query.creative_id).to.equal('1000'); + expect(query.price).to.equal('500'); + expect(query.auction_id).to.equal('413ed000-8c7a-4ba1-a1fa-9732e006f8c3'); + expect(query.bid_id).to.equal('2ed93003f7bb99'); + expect(query.ad_id).to.equal('3b286a4db7031f'); + expect(query.ad_unit_code).to.equal('test'); + expect(query.ref).to.include(window.location.href); + }); + }); + + describe('spec.onTimeout', function () { + let stub; + beforeEach(() => { + stub = sinon.stub(utils, 'triggerPixel'); + }); + afterEach(() => { + stub.restore(); + }); + + it('Should create nurl pixel if bid nurl', function () { + const data = [{ + bidder: bidRequest.bidder, + bidId: bidRequest.bidId, + adUnitCode: bidRequest.adUnitCode, + auctionId: bidRequest.auctionId, + params: [bidRequest.params], + timeout: bidderRequest.timeout, + }]; + spec.onTimeout(data); + const parser = utils.parseUrl(stub.getCall(0).args[0]); + const query = parser.search; + expect(parser.hostname).to.equal('api.relaido.jp'); + expect(parser.pathname).to.equal('/tr/v1/prebid/timeout.gif'); + expect(query.placement_id).to.equal('100000'); + expect(query.timeout).to.equal('1000'); + expect(query.auction_id).to.equal('413ed000-8c7a-4ba1-a1fa-9732e006f8c3'); + expect(query.bid_id).to.equal('2ed93003f7bb99'); + expect(query.ad_unit_code).to.equal('test'); + expect(query.ref).to.include(window.location.href); + }); + }); +}); diff --git a/test/spec/modules/reloadBidAdapter_spec.js b/test/spec/modules/reloadBidAdapter_spec.js index 674c810d48a..b22dd9e7b92 100644 --- a/test/spec/modules/reloadBidAdapter_spec.js +++ b/test/spec/modules/reloadBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/reloadBidAdapter'; +import { spec } from 'modules/reloadBidAdapter.js'; let getParams = () => { return JSON.parse(JSON.stringify({ diff --git a/test/spec/modules/resultsmediaBidAdapter_spec.js b/test/spec/modules/resultsmediaBidAdapter_spec.js new file mode 100644 index 00000000000..0e2d4c0013a --- /dev/null +++ b/test/spec/modules/resultsmediaBidAdapter_spec.js @@ -0,0 +1,574 @@ +import {spec} from '../../../modules/resultsmediaBidAdapter.js'; +import * as utils from '../../../src/utils.js'; +import * as sinon from 'sinon'; + +var r1adapter = spec; + +describe('resultsmedia adapter tests', function () { + beforeEach(function() { + this.defaultBidderRequest = { + 'refererInfo': { + 'referer': 'Reference Page', + 'stack': [ + 'aodomain.dvl', + 'page.dvl' + ] + } + }; + }); + + describe('Verify 1.0 POST Banner Bid Request', function () { + it('buildRequests works', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaType': 'banner', + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'sizes': [[300, 250]], + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + + expect(bidRequest.url).to.have.string('https://bid306.rtbsrv.com/bidder/?bid=3mhdom&zoneId=9999&hbv='); + expect(bidRequest.method).to.equal('POST'); + const openrtbRequest = JSON.parse(bidRequest.data); + expect(openrtbRequest.site).to.not.equal(null); + expect(openrtbRequest.site.ref).to.equal('Reference Page'); + expect(openrtbRequest.device).to.not.equal(null); + expect(openrtbRequest.device.ua).to.equal(navigator.userAgent); + expect(openrtbRequest.device.dnt).to.equal(0); + expect(openrtbRequest.imp[0].banner).to.not.equal(null); + expect(openrtbRequest.imp[0].banner.format[0].w).to.equal(300); + expect(openrtbRequest.imp[0].banner.format[0].h).to.equal(250); + expect(openrtbRequest.imp[0].ext.bidder.zoneId).to.equal(9999); + }); + + it('interpretResponse works', function() { + var bidList = { + 'body': [ + { + 'impid': 'div-gpt-ad-1438287399331-0', + 'w': 300, + 'h': 250, + 'adm': '
My Compelling Ad
', + 'price': 1, + 'crid': 'cr-cfy24' + } + ] + }; + + var bannerBids = r1adapter.interpretResponse(bidList); + + expect(bannerBids.length).to.equal(1); + const bid = bannerBids[0]; + expect(bid.width).to.equal(300); + expect(bid.height).to.equal(250); + expect(bid.creativeId).to.equal('cr-cfy24'); + expect(bid.currency).to.equal('USD'); + expect(bid.netRevenue).to.equal(true); + expect(bid.cpm).to.equal(1.0); + expect(bid.ttl).to.equal(350); + }); + }); + + describe('Verify POST Video Bid Request', function() { + it('buildRequests works', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'video': { + 'playerSize': [640, 480], + 'context': 'instream' + } + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-1', + 'sizes': [ + [300, 250] + ], + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + + expect(bidRequest.url).to.have.string('https://bid306.rtbsrv.com/bidder/?bid=3mhdom&zoneId=9999&hbv='); + expect(bidRequest.method).to.equal('POST'); + const openrtbRequest = JSON.parse(bidRequest.data); + expect(openrtbRequest.site).to.not.equal(null); + expect(openrtbRequest.device).to.not.equal(null); + expect(openrtbRequest.device.ua).to.equal(navigator.userAgent); + expect(openrtbRequest.device).to.have.property('dnt'); + expect(openrtbRequest.imp[0].video).to.not.equal(null); + expect(openrtbRequest.imp[0].video.w).to.equal(640); + expect(openrtbRequest.imp[0].video.h).to.equal(480); + expect(openrtbRequest.imp[0].video.mimes[0]).to.equal('video/mp4'); + expect(openrtbRequest.imp[0].video.protocols).to.eql([2, 3, 5, 6]); + expect(openrtbRequest.imp[0].video.startdelay).to.equal(0); + expect(openrtbRequest.imp[0].video.skip).to.equal(0); + expect(openrtbRequest.imp[0].video.playbackmethod).to.eql([1, 2, 3, 4]); + expect(openrtbRequest.imp[0].video.delivery[0]).to.equal(1); + expect(openrtbRequest.imp[0].video.api).to.eql([1, 2, 5]); + }); + + it('interpretResponse works', function() { + var bidList = { + 'body': [ + { + 'impid': 'div-gpt-ad-1438287399331-1', + 'price': 1, + 'adm': 'https://example.com/', + 'adomain': [ + 'test.com' + ], + 'cid': '467415', + 'crid': 'cr-vid', + 'w': 800, + 'h': 600 + } + ] + }; + + var videoBids = r1adapter.interpretResponse(bidList); + + expect(videoBids.length).to.equal(1); + const bid = videoBids[0]; + expect(bid.width).to.equal(800); + expect(bid.height).to.equal(600); + expect(bid.vastUrl).to.equal('https://example.com/'); + expect(bid.mediaType).to.equal('video'); + expect(bid.creativeId).to.equal('cr-vid'); + expect(bid.currency).to.equal('USD'); + expect(bid.netRevenue).to.equal(true); + expect(bid.cpm).to.equal(1.0); + expect(bid.ttl).to.equal(600); + }); + }); + + describe('misc buildRequests', function() { + it('should send GDPR Consent data to resultsmedia tag', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + } + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-3', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var consentString = 'testConsentString'; + var gdprBidderRequest = this.defaultBidderRequest; + gdprBidderRequest.gdprConsent = { + 'gdprApplies': true, + 'consentString': consentString + }; + + var bidRequest = r1adapter.buildRequests(bidRequestList, gdprBidderRequest); + + const openrtbRequest = JSON.parse(bidRequest.data); + expect(openrtbRequest.user.ext.consent).to.equal(consentString); + expect(openrtbRequest.regs.ext.gdpr).to.equal(true); + }); + + it('prefer 2.0 sizes', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 600]] + } + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'sizes': [[300, 250]], + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + + const openrtbRequest = JSON.parse(bidRequest.data); + expect(openrtbRequest.imp[0].banner.format[0].w).to.equal(300); + expect(openrtbRequest.imp[0].banner.format[0].h).to.equal(600); + }); + + it('does not return request for invalid banner size configuration', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300]] + } + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + expect(bidRequest.method).to.be.undefined; + }); + + it('does not return request for missing banner size configuration', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'banner': {} + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + expect(bidRequest.method).to.be.undefined; + }); + + it('reject bad sizes', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'banner': {'sizes': [['400', '500'], ['4n0', '5g0']]} + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + const openrtbRequest = JSON.parse(bidRequest.data); + expect(openrtbRequest.imp[0].banner.format.length).to.equal(1); + }); + + it('dnt is correctly set to 1', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 600]] + } + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var dntStub = sinon.stub(utils, 'getDNT').returns(1); + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + + dntStub.restore(); + + const openrtbRequest = JSON.parse(bidRequest.data); + expect(openrtbRequest.device.dnt).to.equal(1); + }); + + it('supports string video sizes', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'video': { + 'context': 'instream', + 'playerSize': ['600', '300'] + } + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-1', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + + const openrtbRequest = JSON.parse(bidRequest.data); + expect(openrtbRequest.imp[0].video.w).to.equal(600); + expect(openrtbRequest.imp[0].video.h).to.equal(300); + }); + + it('rejects bad video sizes', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'video': { + 'context': 'instream', + 'playerSize': ['badWidth', 'badHeight'] + } + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-1', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + + const openrtbRequest = JSON.parse(bidRequest.data); + expect(openrtbRequest.imp[0].video.w).to.be.undefined; + expect(openrtbRequest.imp[0].video.h).to.be.undefined; + }); + + it('supports missing video size', function () { + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'video': { + 'context': 'instream' + } + }, + 'adUnitCode': 'div-gpt-ad-1438287399331-1', + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + + const openrtbRequest = JSON.parse(bidRequest.data); + expect(openrtbRequest.imp[0].video.w).to.be.undefined; + expect(openrtbRequest.imp[0].video.h).to.be.undefined; + }); + + it('should return empty site data when refererInfo is missing', function() { + delete this.defaultBidderRequest.refererInfo; + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaType': 'banner', + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'sizes': [[300, 250]], + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + const openrtbRequest = JSON.parse(bidRequest.data); + + expect(openrtbRequest.site.domain).to.equal(''); + expect(openrtbRequest.site.page).to.equal(''); + expect(openrtbRequest.site.ref).to.equal(''); + }); + }); + + it('should return empty site.domain and site.page when refererInfo.stack is empty', function() { + this.defaultBidderRequest.refererInfo.stack = []; + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaType': 'banner', + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'sizes': [[300, 250]], + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + const openrtbRequest = JSON.parse(bidRequest.data); + + expect(openrtbRequest.site.domain).to.equal(''); + expect(openrtbRequest.site.page).to.equal(''); + expect(openrtbRequest.site.ref).to.equal('Reference Page'); + }); + + it('should secure correctly', function() { + this.defaultBidderRequest.refererInfo.stack[0] = ['https://securesite.dvl']; + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaType': 'banner', + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'sizes': [[300, 250]], + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead' + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + const openrtbRequest = JSON.parse(bidRequest.data); + + expect(openrtbRequest.imp[0].secure).to.equal(1); + }); + + it('should pass schain', function() { + var schain = { + 'ver': '1.0', + 'complete': 1, + 'nodes': [{ + 'asi': 'indirectseller.com', + 'sid': '00001', + 'hp': 1 + }, { + 'asi': 'indirectseller-2.com', + 'sid': '00002', + 'hp': 1 + }] + }; + var bidRequestList = [ + { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaType': 'banner', + 'adUnitCode': 'div-gpt-ad-1438287399331-0', + 'sizes': [[300, 250]], + 'transactionId': 'd7b773de-ceaa-484d-89ca-d9f51b8d61ec', + 'bidderRequestId': '418b37f85e772c', + 'auctionId': '18fd8b8b0bd757', + 'bidRequestsCount': 1, + 'bidId': '51ef8751f9aead', + 'schain': schain + } + ]; + + var bidRequest = r1adapter.buildRequests(bidRequestList, this.defaultBidderRequest); + const openrtbRequest = JSON.parse(bidRequest.data); + + expect(openrtbRequest.source.ext.schain).to.deep.equal(schain); + }); + + describe('misc interpretResponse', function () { + it('No bid response', function() { + var noBidResponse = r1adapter.interpretResponse({ + 'body': '' + }); + expect(noBidResponse.length).to.equal(0); + }); + }); + + describe('isBidRequestValid', function () { + var bid = { + 'bidder': 'resultsmedia', + 'params': { + 'zoneId': 9999 + }, + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + } + }, + 'adUnitCode': 'bannerDiv' + }; + + it('should return true when required params found', function () { + expect(r1adapter.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when placementId missing', function () { + delete bid.params.zoneId; + expect(r1adapter.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('getUserSyncs', function () { + it('returns an empty string', function () { + expect(r1adapter.getUserSyncs()).to.deep.equal([]); + }); + }); +}); diff --git a/test/spec/modules/revcontentBidAdapter_spec.js b/test/spec/modules/revcontentBidAdapter_spec.js index a3574a06eb3..0a0263837c6 100644 --- a/test/spec/modules/revcontentBidAdapter_spec.js +++ b/test/spec/modules/revcontentBidAdapter_spec.js @@ -1,9 +1,9 @@ // jshint esversion: 6, es3: false, node: true import {assert, expect} from 'chai'; -import * as url from 'src/url'; -import {spec} from 'modules/revcontentBidAdapter'; -import { NATIVE } from 'src/mediaTypes'; -import { config } from 'src/config'; +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; @@ -74,7 +74,7 @@ describe('revcontent adapter', function () { assert.deepEqual(keys, data); }); - it('should send info about device', function () { + it('should send info about device and unique bidfloor', function () { let validBidRequests = [{ bidder: 'revcontent', nativeParams: {}, @@ -83,15 +83,17 @@ describe('revcontent adapter', function () { apiKey: '8a33fa9cf220ae685dcc3544f847cdda858d3b1c', userId: 673, domain: 'test.com', - endpoint: 'trends-s0.revcontent.com' + endpoint: 'trends-s0.revcontent.com', + bidfloor: 0.05 } }]; let request = spec.buildRequests(validBidRequests, {refererInfo: {referer: 'page'}}); request = JSON.parse(request[0].data); + assert.equal(request.imp[0].bidfloor, 0.05); assert.equal(request.device.ua, navigator.userAgent); }); - it('should send info about the site', function () { + it('should send info about the site and default bidfloor', function () { let validBidRequests = [{ bidder: 'revcontent', nativeParams: { @@ -123,7 +125,7 @@ describe('revcontent adapter', function () { let request = spec.buildRequests(validBidRequests, {refererInfo}); request = JSON.parse(request[0].data); - + assert.equal(request.imp[0].bidfloor, 0.1); assert.deepEqual(request.site, { domain: 'test.com', page: 'page', @@ -326,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/rhythmoneBidAdapter_spec.js b/test/spec/modules/rhythmoneBidAdapter_spec.js index 80cbdb4a0af..d9342332e61 100644 --- a/test/spec/modules/rhythmoneBidAdapter_spec.js +++ b/test/spec/modules/rhythmoneBidAdapter_spec.js @@ -1,5 +1,5 @@ -import {spec} from '../../../modules/rhythmoneBidAdapter'; -import * as utils from '../../../src/utils'; +import {spec} from '../../../modules/rhythmoneBidAdapter.js'; +import * as utils from '../../../src/utils.js'; import * as sinon from 'sinon'; var r1adapter = spec; diff --git a/test/spec/modules/richaudienceBidAdapter_spec.js b/test/spec/modules/richaudienceBidAdapter_spec.js index cd6690e3276..f18e67a3ac5 100644 --- a/test/spec/modules/richaudienceBidAdapter_spec.js +++ b/test/spec/modules/richaudienceBidAdapter_spec.js @@ -2,20 +2,20 @@ import {expect} from 'chai'; // may prefer 'assert' in place of 'expect' import { spec -} from 'modules/richaudienceBidAdapter'; -import {config} from 'src/config'; -import * as utils from 'src/utils'; +} from 'modules/richaudienceBidAdapter.js'; +import {config} from 'src/config.js'; +import * as utils from 'src/utils.js'; describe('Richaudience adapter tests', function () { - var DEFAULT_PARAMS = [{ + var DEFAULT_PARAMS_NEW_SIZES = [{ adUnitCode: 'test-div', bidId: '2c7c8e9c900244', - sizes: [ - [300, 250], - [300, 600], - [728, 90], - [970, 250] - ], + mediaTypes: { + banner: { + sizes: [ + [300, 250], [300, 600], [728, 90], [970, 250]] + } + }, bidder: 'richaudience', params: { bidfloor: 0.5, @@ -29,13 +29,37 @@ describe('Richaudience adapter tests', function () { user: {} }]; - var DEFAULT_PARAMS_NEW_SIZES = [{ + var DEFAULT_PARAMS_VIDEO_IN = [{ adUnitCode: 'test-div', bidId: '2c7c8e9c900244', mediaTypes: { - banner: { - sizes: [ - [300, 250], [300, 600], [728, 90], [970, 250]] + video: { + context: 'instream', + 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 = [{ + adUnitCode: 'test-div', + bidId: '2c7c8e9c900244', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480], + mimes: ['video/mp4'] } }, bidder: 'richaudience', @@ -51,6 +75,34 @@ describe('Richaudience adapter tests', function () { 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', @@ -135,34 +187,12 @@ describe('Richaudience adapter tests', function () { } } - it('Verify build request', function () { - config.setConfig({ - 'currency': { - 'adServerCurrency': 'USD' - } - }); - - const request = spec.buildRequests(DEFAULT_PARAMS, DEFAULT_PARAMS_GDPR); - - expect(request[0]).to.have.property('method').and.to.equal('POST'); - const requestContent = JSON.parse(request[0].data); - expect(requestContent).to.have.property('sizes'); - expect(requestContent.sizes[0]).to.have.property('w').and.to.equal(300); - expect(requestContent.sizes[0]).to.have.property('h').and.to.equal(250); - expect(requestContent.sizes[1]).to.have.property('w').and.to.equal(300); - expect(requestContent.sizes[1]).to.have.property('h').and.to.equal(600); - expect(requestContent.sizes[2]).to.have.property('w').and.to.equal(728); - expect(requestContent.sizes[2]).to.have.property('h').and.to.equal(90); - expect(requestContent.sizes[3]).to.have.property('w').and.to.equal(970); - expect(requestContent.sizes[3]).to.have.property('h').and.to.equal(250); - }); - it('Referer undefined', function() { config.setConfig({ 'currency': {'adServerCurrency': 'USD'} }) - const request = spec.buildRequests(DEFAULT_PARAMS, { + 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 @@ -174,7 +204,7 @@ describe('Richaudience adapter tests', function () { expect(requestContent).to.have.property('referer').and.to.equal(null); }) - it('Verify build request to prebid 3.0', function() { + 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', @@ -212,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({ @@ -497,7 +566,7 @@ describe('Richaudience adapter tests', function () { }); it('Verify interprete response', function () { - const request = spec.buildRequests(DEFAULT_PARAMS, { + 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 @@ -523,8 +592,26 @@ describe('Richaudience adapter tests', function () { expect(bid.dealId).to.equal('dealId'); }); - it('no banner media response', function () { - const request = spec.buildRequests(DEFAULT_PARAMS, { + 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 @@ -537,7 +624,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 () { @@ -550,7 +639,7 @@ describe('Richaudience adapter tests', function () { }); it('Verifies if bid request is valid', function () { - expect(spec.isBidRequestValid(DEFAULT_PARAMS[0])).to.equal(true); + 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({ @@ -612,13 +701,14 @@ describe('Richaudience adapter tests', function () { })).to.equal(true); }); - it('Verifies user sync', function () { + it('Verifies user syncs iframe', function () { var syncs = spec.getUserSyncs({ iframeEnabled: 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', gdprApplies: true }); + expect(syncs).to.have.lengthOf(1); expect(syncs[0].type).to.equal('iframe'); syncs = spec.getUserSyncs({ @@ -647,10 +737,13 @@ describe('Richaudience adapter tests', function () { pixelEnabled: true } }); + }); - syncs = spec.getUserSyncs({ + 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 @@ -659,13 +752,25 @@ describe('Richaudience adapter tests', function () { 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/rivrAnalyticsAdapter_spec.js b/test/spec/modules/rivrAnalyticsAdapter_spec.js index 2676c3a59b6..9add7ed5f7d 100644 --- a/test/spec/modules/rivrAnalyticsAdapter_spec.js +++ b/test/spec/modules/rivrAnalyticsAdapter_spec.js @@ -1,5 +1,5 @@ -import * as utils from 'src/utils'; -import analyticsAdapter from 'modules/rivrAnalyticsAdapter'; +import * as utils from 'src/utils.js'; +import analyticsAdapter from 'modules/rivrAnalyticsAdapter.js'; import { sendImpressions, handleClickEventWithClosureScope, @@ -15,10 +15,10 @@ import { storeAndReturnRivrUsrIdCookie, arrayDifference, activelyWaitForBannersToRender, -} from 'modules/rivrAnalyticsAdapter'; +} from 'modules/rivrAnalyticsAdapter.js'; import {expect} from 'chai'; -import adapterManager from 'src/adapterManager'; -import * as ajax from 'src/ajax'; +import adapterManager from 'src/adapterManager.js'; +import * as ajax from 'src/ajax.js'; import CONSTANTS from 'src/constants.json'; const events = require('../../../src/events'); diff --git a/test/spec/modules/roxotAnalyticsAdapter_spec.js b/test/spec/modules/roxotAnalyticsAdapter_spec.js index 1ad6ba2e86a..79c58e36735 100644 --- a/test/spec/modules/roxotAnalyticsAdapter_spec.js +++ b/test/spec/modules/roxotAnalyticsAdapter_spec.js @@ -1,6 +1,6 @@ -import roxotAnalytic from 'modules/roxotAnalyticsAdapter'; +import roxotAnalytic from 'modules/roxotAnalyticsAdapter.js'; import {expect} from 'chai'; -import {server} from 'test/mocks/xhr'; +import {server} from 'test/mocks/xhr.js'; let events = require('src/events'); let constants = require('src/constants.json'); diff --git a/test/spec/modules/rtbdemandBidAdapter_spec.js b/test/spec/modules/rtbdemandBidAdapter_spec.js index 6b5ef215162..be9872ec01b 100644 --- a/test/spec/modules/rtbdemandBidAdapter_spec.js +++ b/test/spec/modules/rtbdemandBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/rtbdemandBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/rtbdemandBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('rtbdemandAdapter', function () { const adapter = newBidder(spec); diff --git a/test/spec/modules/rtbhouseBidAdapter_spec.js b/test/spec/modules/rtbhouseBidAdapter_spec.js index 6c6faf4e4d0..efaed87dd15 100644 --- a/test/spec/modules/rtbhouseBidAdapter_spec.js +++ b/test/spec/modules/rtbhouseBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { OPENRTB, spec } from 'modules/rtbhouseBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { OPENRTB, spec } from 'modules/rtbhouseBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('RTBHouseAdapter', () => { const adapter = newBidder(spec); @@ -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/rtbsolutionsBidAdapter_spec.js b/test/spec/modules/rtbsolutionsBidAdapter_spec.js index a9ffcd2ce4b..c47b086fe50 100644 --- a/test/spec/modules/rtbsolutionsBidAdapter_spec.js +++ b/test/spec/modules/rtbsolutionsBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/rtbsolutionsBidAdapter'; +import { spec } from 'modules/rtbsolutionsBidAdapter.js'; describe('rtbsolutionsBidAdapterTests', function () { it('validate_pub_params_1', function () { diff --git a/test/spec/modules/rubiconAnalyticsAdapter_spec.js b/test/spec/modules/rubiconAnalyticsAdapter_spec.js index 6a652a6ab86..1639389fe24 100644 --- a/test/spec/modules/rubiconAnalyticsAdapter_spec.js +++ b/test/spec/modules/rubiconAnalyticsAdapter_spec.js @@ -1,12 +1,16 @@ -import rubiconAnalyticsAdapter, { SEND_TIMEOUT, parseBidResponse } from 'modules/rubiconAnalyticsAdapter'; +import rubiconAnalyticsAdapter, { + SEND_TIMEOUT, + parseBidResponse, + getHostNameFromReferer, +} from 'modules/rubiconAnalyticsAdapter.js'; import CONSTANTS from 'src/constants.json'; -import { config } from 'src/config'; -import { server } from 'test/mocks/xhr'; +import { config } from 'src/config.js'; +import { server } from 'test/mocks/xhr.js'; import { setConfig, addBidResponseHook, -} from 'modules/currency'; +} from 'modules/currency.js'; let Ajv = require('ajv'); let schema = require('./rubiconAnalyticsSchema.json'); @@ -21,10 +25,9 @@ function validate(message) { expect(validator.errors).to.deep.equal(null); } -// using es6 "import * as events from 'src/events'" causes the events.getEvents stub not to work... -let events = require('src/events'); -let ajax = require('src/ajax'); -let utils = require('src/utils'); +// using es6 "import * as events from 'src/events.js'" causes the events.getEvents stub not to work... +let events = require('src/events.js'); +let utils = require('src/utils.js'); const { EVENTS: { @@ -274,6 +277,7 @@ const ANALYTICS_MESSAGE = { 'integration': 'pbjs', 'version': '$prebid.version$', 'referrerUri': 'http://www.test.com/page.html', + 'referrerHostname': 'www.test.com', 'auctions': [ { 'clientTimeoutMillis': 3000, @@ -476,7 +480,6 @@ function performStandardAuction() { describe('rubicon analytics adapter', function () { let sandbox; - let oldScreen; let clock; beforeEach(function () { @@ -486,6 +489,8 @@ describe('rubicon analytics adapter', function () { clock = sandbox.useFakeTimers(1519767013781); + rubiconAnalyticsAdapter.referrerHostname = ''; + config.setConfig({ s2sConfig: { timeout: 1000, @@ -654,6 +659,106 @@ describe('rubicon analytics adapter', function () { expect(message).to.deep.equal(ANALYTICS_MESSAGE); }); + it('should capture price floor information correctly', function () { + let auctionInit = utils.deepClone(MOCK.AUCTION_INIT); + auctionInit.bidderRequests[0].bids[0].floorData = { + skipped: false, + modelVersion: 'someModelName', + location: 'setConfig', + skipRate: 15, + fetchStatus: 'error' + }; + let flooredResponse = { + ...BID, + floorData: { + floorValue: 4, + floorRule: '12345/sports|video', + floorCurrency: 'USD', + cpmAfterAdjustments: 2.1, + enforcements: { + enforceJS: true, + enforcePBS: false, + floorDeals: false, + bidAdjustment: true + }, + matchedFields: { + gptSlot: '12345/sports', + mediaType: 'video' + } + }, + status: 'bidRejected', + cpm: 0, + getStatusCode() { + return 2; + } + }; + + let notFlooredResponse = { + ...BID2, + floorData: { + floorValue: 1, + floorRule: '12345/news|banner', + floorCurrency: 'USD', + cpmAfterAdjustments: 1.55, + enforcements: { + enforceJS: true, + enforcePBS: false, + floorDeals: false, + bidAdjustment: true + }, + matchedFields: { + gptSlot: '12345/news', + mediaType: 'banner' + } + } + }; + + // spoof the auction with just our duplicates + events.emit(AUCTION_INIT, auctionInit); + events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); + events.emit(BID_RESPONSE, flooredResponse); + events.emit(BID_RESPONSE, notFlooredResponse); + events.emit(AUCTION_END, MOCK.AUCTION_END); + events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(BID_WON, MOCK.BID_WON[1]); + clock.tick(SEND_TIMEOUT + 1000); + + expect(server.requests.length).to.equal(1); + + let message = JSON.parse(server.requests[0].requestBody); + validate(message); + + // 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' + }); + // first adUnit's adSlot + expect(message.auctions[0].adUnits[0].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].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'); + // 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 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); @@ -840,4 +945,19 @@ describe('rubicon analytics adapter', function () { rubiconAnalyticsAdapter.disableAnalytics(); }); }); + + it('getHostNameFromReferer correctly grabs hostname from an input URL', function () { + let inputUrl = 'https://www.prebid.org/some/path?pbjs_debug=true'; + expect(getHostNameFromReferer(inputUrl)).to.equal('www.prebid.org'); + inputUrl = 'https://www.prebid.com/some/path?pbjs_debug=true'; + expect(getHostNameFromReferer(inputUrl)).to.equal('www.prebid.com'); + inputUrl = 'https://prebid.org/some/path?pbjs_debug=true'; + expect(getHostNameFromReferer(inputUrl)).to.equal('prebid.org'); + inputUrl = 'http://xn--p8j9a0d9c9a.xn--q9jyb4c/'; + expect(typeof getHostNameFromReferer(inputUrl)).to.equal('string'); + + // not non-UTF char's in query / path which break if noDecodeWholeURL not set + inputUrl = 'https://prebid.org/search_results/%95x%8Em%92%CA/?category=000'; + expect(getHostNameFromReferer(inputUrl)).to.equal('prebid.org'); + }); }); diff --git a/test/spec/modules/rubiconAnalyticsSchema.json b/test/spec/modules/rubiconAnalyticsSchema.json index 686aced840f..16cca629d8c 100644 --- a/test/spec/modules/rubiconAnalyticsSchema.json +++ b/test/spec/modules/rubiconAnalyticsSchema.json @@ -292,7 +292,8 @@ "enum": [ "success", "no-bid", - "error" + "error", + "rejected" ] }, "error": { diff --git a/test/spec/modules/rubiconBidAdapter_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js index 5a9e2968309..11ed17df5f8 100644 --- a/test/spec/modules/rubiconBidAdapter_spec.js +++ b/test/spec/modules/rubiconBidAdapter_spec.js @@ -1,21 +1,19 @@ import {expect} from 'chai'; -import adapterManager from 'src/adapterManager'; -import {spec, getPriceGranularity, masSizeOrdering, resetUserSync, hasVideoMediaType, FASTLANE_ENDPOINT} from 'modules/rubiconBidAdapter'; +import adapterManager from 'src/adapterManager.js'; +import {spec, getPriceGranularity, masSizeOrdering, resetUserSync, hasVideoMediaType, FASTLANE_ENDPOINT} from 'modules/rubiconBidAdapter.js'; import {parse as parseQuery} from 'querystring'; -import {newBidder} from 'src/adapters/bidderFactory'; -import {userSync} from 'src/userSync'; -import {config} from 'src/config'; -import * as utils from 'src/utils'; -import find from 'core-js/library/fn/array/find'; - -var CONSTANTS = require('src/constants.json'); +import {config} from 'src/config.js'; +import * as utils from 'src/utils.js'; +import find from 'core-js-pure/features/array/find.js'; const INTEGRATION = `pbjs_lite_v$prebid.version$`; // $prebid.version$ will be substituted in by gulp in built prebid +const PBS_INTEGRATION = 'pbjs'; describe('the rubicon adapter', function () { let sandbox, bidderRequest, - sizeMap; + sizeMap, + getFloorResponse; /** * @typedef {Object} sizeMapConverted @@ -224,8 +222,10 @@ describe('the rubicon adapter', function () { lipb: { lipbid: '0000-1111-2222-3333', segments: ['segA', 'segB'] - } - } + }, + idl_env: '1111-2222-3333-4444' + }; + bid.storedAuctionResponse = 11111; } function createVideoBidderRequestNoVideo() { @@ -272,7 +272,7 @@ describe('the rubicon adapter', function () { beforeEach(function () { sandbox = sinon.sandbox.create(); - + getFloorResponse = {}; bidderRequest = { bidderCode: 'rubicon', auctionId: 'c45dd708-a418-42ec-b8a7-b70a6c6fab0a', @@ -409,6 +409,43 @@ 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; + let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + let data = parseQuery(request.data); + expect(data.rp_hard_floor).to.be.undefined; + + // not an object should work and not send + getFloorResponse = undefined; + [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + data = parseQuery(request.data); + expect(data.rp_hard_floor).to.be.undefined; + + // make it respond with a non USD floor should not send it + getFloorResponse = {currency: 'EUR', floor: 1.0}; + [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + data = parseQuery(request.data); + expect(data.rp_hard_floor).to.be.undefined; + + // make it respond with a non USD floor should not send it + getFloorResponse = {currency: 'EUR'}; + [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + data = parseQuery(request.data); + expect(data.rp_hard_floor).to.be.undefined; + + // make it respond with USD floor and string floor + getFloorResponse = {currency: 'USD', floor: '1.23'}; + [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + data = parseQuery(request.data); + expect(data.rp_hard_floor).to.equal('1.23'); + + // make it respond with USD floor and num floor + getFloorResponse = {currency: 'USD', floor: 1.23}; + [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + 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; @@ -979,6 +1016,51 @@ describe('the rubicon adapter', function () { expect(data[key]).to.equal(value); }); }); + + it('should use first party data from getConfig over the bid params, if present', () => { + const context = { + keywords: ['e', 'f'], + rating: '4-star' + }; + const user = { + keywords: ['d'], + gender: 'M', + yob: '1984', + geo: { country: 'ca' } + }; + + sandbox.stub(config, 'getConfig').callsFake(key => { + const config = { + fpd: { + context, + user + } + }; + return utils.deepAccess(config, key); + }); + + const expectedQuery = { + 'kw': 'a,b,c,d,e,f', + 'tg_v.ucat': 'new', + 'tg_v.lastsearch': 'iphone', + 'tg_v.likes': 'sports,video games', + 'tg_v.gender': 'M', + 'tg_v.yob': '1984', + 'tg_v.geo': '{"country":"ca"}', + 'tg_i.rating': '4-star', + 'tg_i.prodtype': 'tech,mobile', + }; + + // get the built request + let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + let data = parseQuery(request.data); + + // make sure that tg_v, tg_i, and kw values are correct + Object.keys(expectedQuery).forEach(key => { + let value = expectedQuery[key]; + expect(data[key]).to.deep.equal(value); + }); + }); }); describe('singleRequest config', function () { @@ -1259,6 +1341,19 @@ describe('the rubicon adapter', function () { expect(unescapedData.indexOf('&tg_v.LIseg=segD,segE&') !== -1).to.equal(true); }); }); + + describe('LiveRamp support', function () { + it('should send tpid_liveramp.com when userId defines idl_env', function () { + const clonedBid = utils.deepClone(bidderRequest.bids[0]); + clonedBid.userId = { + idl_env: '1111-2222-3333-4444' + }; + let [request] = spec.buildRequests([clonedBid], bidderRequest); + let data = parseQuery(request.data); + + expect(data['tpid_liveramp.com']).to.equal('1111-2222-3333-4444'); + }); + }); }) describe('Prebid AdSlot', function () { @@ -1366,12 +1461,16 @@ 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=='); 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.tpid.source).to.equal('liveintent.com'); expect(post.user.ext.tpid.uid).to.equal('0000-1111-2222-3333'); + // 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'); @@ -1381,12 +1480,46 @@ describe('the rubicon adapter', function () { 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).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); }); + it('should correctly set bidfloor on imp when getfloor in scope', function () { + createVideoBidderRequest(); + // default getFloor response is empty object so should not break and not send hard_floor + bidderRequest.bids[0].getFloor = () => getFloorResponse; + sandbox.stub(Date, 'now').callsFake(() => + bidderRequest.auctionStart + 100 + ); + + let [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + + // not an object should work and not send + expect(request.data.imp[0].bidfloor).to.be.undefined; + + // make it respond with a non USD floor should not send it + getFloorResponse = {currency: 'EUR', floor: 1.0}; + [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + expect(request.data.imp[0].bidfloor).to.be.undefined; + + // make it respond with a non USD floor should not send it + getFloorResponse = {currency: 'EUR'}; + [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + expect(request.data.imp[0].bidfloor).to.be.undefined; + + // make it respond with USD floor and string floor + getFloorResponse = {currency: 'USD', floor: '1.23'}; + [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + expect(request.data.imp[0].bidfloor).to.equal(1.23); + + // make it respond with USD floor and num floor + getFloorResponse = {currency: 'USD', floor: 1.23}; + [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() { createVideoBidderRequest(); @@ -1640,6 +1773,60 @@ describe('the rubicon adapter', function () { expect(request.data.regs.coppa).to.equal(1); }); + it('should include first party data', () => { + createVideoBidderRequest(); + + const context = { + keywords: ['e', 'f'], + rating: '4-star' + }; + const user = { + keywords: ['d'], + gender: 'M', + yob: '1984', + geo: { country: 'ca' } + }; + + sandbox.stub(config, 'getConfig').callsFake(key => { + const config = { + fpd: { + context, + user + } + }; + return utils.deepAccess(config, key); + }); + + const expected = [{ + bidders: [ 'rubicon' ], + config: { + fpd: { + site: Object.assign({}, bidderRequest.bids[0].params.inventory, context), + user: Object.assign({}, bidderRequest.bids[0].params.visitor, user) + } + } + }]; + + const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + expect(request.data.ext.prebid.bidderconfig).to.deep.equal(expected); + }); + + it('should include storedAuctionResponse in video bid request', function () { + createVideoBidderRequest(); + + sandbox.stub(Date, 'now').callsFake(() => + bidderRequest.auctionStart + 100 + ); + + const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); + expect(request.data.imp).to.exist.and.to.be.a('array'); + expect(request.data.imp).to.have.lengthOf(1); + expect(request.data.imp[0].ext).to.exist.and.to.be.a('object'); + expect(request.data.imp[0].ext.prebid).to.exist.and.to.be.a('object'); + expect(request.data.imp[0].ext.prebid.storedauctionresponse).to.exist.and.to.be.a('object'); + expect(request.data.imp[0].ext.prebid.storedauctionresponse.id).to.equal('11111'); + }); + it('should include pbAdSlot in bid request', function () { createVideoBidderRequest(); bidderRequest.bids[0].fpd = { @@ -1655,6 +1842,18 @@ describe('the rubicon adapter', function () { const [request] = spec.buildRequests(bidderRequest.bids, bidderRequest); expect(request.data.imp[0].ext.context.data.adslot).to.equal('1234567890'); }); + + 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]; + }); + 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 () { @@ -1736,6 +1935,12 @@ describe('the rubicon adapter', function () { } }); }); + + it('should not fail if keywords param is not an array', function () { + bidderRequest.bids[0].params.keywords = 'a,b,c'; + const slotParams = spec.createSlotParams(bidderRequest.bids[0], bidderRequest); + expect(slotParams.kw).to.equal(''); + }); }); describe('hasVideoMediaType', function () { diff --git a/test/spec/modules/s2sTesting_spec.js b/test/spec/modules/s2sTesting_spec.js index 52377dcabf2..5c7f3004dee 100644 --- a/test/spec/modules/s2sTesting_spec.js +++ b/test/spec/modules/s2sTesting_spec.js @@ -1,5 +1,5 @@ -import s2sTesting from 'modules/s2sTesting'; -import { config } from 'src/config'; +import s2sTesting from 'modules/s2sTesting.js'; +import { config } from 'src/config.js'; var expect = require('chai').expect; diff --git a/test/spec/modules/scaleableAnalyticsAdapter_spec.js b/test/spec/modules/scaleableAnalyticsAdapter_spec.js index f26d91f7aa1..70b94a2b807 100644 --- a/test/spec/modules/scaleableAnalyticsAdapter_spec.js +++ b/test/spec/modules/scaleableAnalyticsAdapter_spec.js @@ -1,24 +1,49 @@ -import scaleableAnalytics from 'modules/scaleableAnalyticsAdapter'; +import scaleableAnalytics from 'modules/scaleableAnalyticsAdapter.js'; import { expect } from 'chai'; -import events from 'src/events'; +import events from 'src/events.js'; import CONSTANTS from 'src/constants.json'; -import { server } from 'test/mocks/xhr'; +import { server } from 'test/mocks/xhr.js'; const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; const AUCTION_INIT = CONSTANTS.EVENTS.AUCTION_INIT; -const BID_RESPONSE = CONSTANTS.EVENTS.BID_RESPONSE; const BID_WON = CONSTANTS.EVENTS.BID_WON; const AUCTION_END = CONSTANTS.EVENTS.AUCTION_END; describe('Scaleable Analytics Adapter', function() { + const bidsReceivedObj = { + adUnitCode: '12345', + bidderCode: 'test-code', + cpm: 3.14, + currency: 'USD', + dealId: null, + mediaType: 'banner', + timeToRespond: 285, + size: '300x250' + }; + const MOCK_DATA = { adUnitCode: '12345', + auctionEnd: { + bidsReceived: [bidsReceivedObj] + }, + bidderRequests: [{ + bids: [{ + adUnitCode: '12345', + bidder: 'test-code', + params: { + test: 'value' + } + }] + }], site: '5c4fab7a829e955d6c265e72', bidResponse: { adUnitCode: '12345', bidderCode: 'test-code', cpm: 3.14, - timeToRespond: 285 + timeToRespond: 285, + params: [{ + test: 'value' + }] }, bidTimeout: [ { @@ -28,25 +53,52 @@ describe('Scaleable Analytics Adapter', function() { ] }; - MOCK_DATA.expectedBidResponse = { - event: 'bids', - bids: [{ - code: MOCK_DATA.bidResponse.bidderCode, - cpm: MOCK_DATA.bidResponse.cpm, - ttr: MOCK_DATA.bidResponse.timeToRespond - }], - adunit: MOCK_DATA.adUnitCode, - site: MOCK_DATA.site - }; + const bidObj = MOCK_DATA.bidderRequests[0].bids[0]; + + const expectedBidRequests = [{bidder: 'scaleable_adunit_request'}].concat([ + { + bidder: bidObj.bidder, + params: bidObj.params + } + ]); + + MOCK_DATA.expectedRequestResponse = { + event: 'request', + site: MOCK_DATA.site, + adunits: [{ + code: bidObj.adUnitCode, + bidRequests: expectedBidRequests + }] + } MOCK_DATA.expectedBidTimeout = { - event: 'bids', - bids: [], - timeouts: [MOCK_DATA.bidTimeout[0].bidder], - adunit: MOCK_DATA.bidTimeout[0].adUnitCode, - site: MOCK_DATA.site + [MOCK_DATA.bidTimeout[0].adUnitCode]: [{ + timeouts: 1, + bidder: MOCK_DATA.bidTimeout[0].bidder + }] }; + MOCK_DATA.expectedAuctionEndResponse = { + event: 'bids', + site: MOCK_DATA.site, + adunits: [{ + code: MOCK_DATA.auctionEnd.bidsReceived[0].adUnitCode, + bidData: [{ + bidder: bidsReceivedObj.bidderCode, + cpm: bidsReceivedObj.cpm, + currency: bidsReceivedObj.currency, + dealId: bidsReceivedObj.dealId, + type: bidsReceivedObj.mediaType, + ttr: bidsReceivedObj.timeToRespond, + size: bidsReceivedObj.size + }] + }, + { + bidData: MOCK_DATA.expectedBidTimeout[MOCK_DATA.bidTimeout[0].adUnitCode], + code: MOCK_DATA.bidTimeout[0].adUnitCode + }] + } + describe('Event Handling', function() { beforeEach(function() { sinon.stub(events, 'getEvents').returns([]); @@ -66,33 +118,22 @@ describe('Scaleable Analytics Adapter', function() { it('should handle the auction init event', function(done) { events.emit(AUCTION_INIT, { - adUnitCodes: [MOCK_DATA.adUnitCode] + adUnitCodes: [MOCK_DATA.adUnitCode], + bidderRequests: MOCK_DATA.bidderRequests }); const result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal({ - event: 'request', - site: MOCK_DATA.site, - adunit: MOCK_DATA.adUnitCode - }); + expect(result).to.deep.equal(MOCK_DATA.expectedRequestResponse); done(); }); - it('should handle the bid response event', function() { - events.emit(BID_RESPONSE, MOCK_DATA.bidResponse); - - const actual = scaleableAnalytics.getAuctionData(); - - expect(actual[MOCK_DATA.adUnitCode]).to.deep.equal(MOCK_DATA.expectedBidResponse); - }); - it('should handle the bid timeout event', function() { events.emit(BID_TIMEOUT, MOCK_DATA.bidTimeout); const actual = scaleableAnalytics.getAuctionData(); - expect(actual[MOCK_DATA.bidTimeout[0].adUnitCode]).to.deep.equal(MOCK_DATA.expectedBidTimeout); + expect(actual).to.deep.equal(MOCK_DATA.expectedBidTimeout); }); it('should handle the bid won event', function(done) { @@ -104,6 +145,7 @@ describe('Scaleable Analytics Adapter', function() { code: MOCK_DATA.bidResponse.bidderCode, cpm: MOCK_DATA.bidResponse.cpm, ttr: MOCK_DATA.bidResponse.timeToRespond, + params: MOCK_DATA.bidResponse.params, event: 'win', site: MOCK_DATA.site }); @@ -112,10 +154,10 @@ describe('Scaleable Analytics Adapter', function() { }); it('should handle the auction end event', function(done) { - events.emit(AUCTION_END, {}); + events.emit(AUCTION_END, MOCK_DATA.auctionEnd); const result = JSON.parse(server.requests[0].requestBody); - expect(result).to.deep.equal(MOCK_DATA.expectedBidResponse); + expect(result).to.deep.equal(MOCK_DATA.expectedAuctionEndResponse); done(); }); diff --git a/test/spec/modules/schain_spec.js b/test/spec/modules/schain_spec.js index 6e8d6839efe..34d0cff9a60 100644 --- a/test/spec/modules/schain_spec.js +++ b/test/spec/modules/schain_spec.js @@ -1,6 +1,6 @@ -import { isValidSchainConfig, isSchainObjectValid, makeBidRequestsHook } from '../../../modules/schain'; -import { deepClone } from '../../../src/utils'; -import {config} from '../../../src/config'; +import { isValidSchainConfig, isSchainObjectValid, makeBidRequestsHook } from '../../../modules/schain.js'; +import { deepClone } from '../../../src/utils.js'; +import {config} from '../../../src/config.js'; import { expect } from 'chai'; describe('#isValidSchainConfig: module config validation', function() { diff --git a/test/spec/modules/seedingAllianceAdapter_spec.js b/test/spec/modules/seedingAllianceAdapter_spec.js index e7915bc2d22..e6f96c92fd9 100755 --- a/test/spec/modules/seedingAllianceAdapter_spec.js +++ b/test/spec/modules/seedingAllianceAdapter_spec.js @@ -1,9 +1,8 @@ // jshint esversion: 6, es3: false, node: true import {assert, expect} from 'chai'; -import * as url from 'src/url'; -import {spec} from 'modules/seedingAllianceBidAdapter'; -import { NATIVE } from 'src/mediaTypes'; -import { config } from 'src/config'; +import {spec} from 'modules/seedingAllianceBidAdapter.js'; +import { NATIVE } from 'src/mediaTypes.js'; +import { config } from 'src/config.js'; describe('SeedingAlliance adapter', function () { let serverResponse, bidRequest, bidResponses; @@ -88,6 +87,12 @@ describe('SeedingAlliance adapter', function () { }, sponsoredBy: { required: true + }, + cta: { + required: true + }, + icon: { + required: true } } }]; @@ -98,6 +103,8 @@ describe('SeedingAlliance adapter', function () { assert.equal(assets[1].id, 3); assert.equal(assets[2].id, 0); assert.equal(assets[3].id, 2); + assert.equal(assets[4].id, 4); + assert.equal(assets[5].id, 5); }); }); diff --git a/test/spec/modules/seedtagBidAdapter_spec.js b/test/spec/modules/seedtagBidAdapter_spec.js index 4bd4b599c55..5c8c58196f7 100644 --- a/test/spec/modules/seedtagBidAdapter_spec.js +++ b/test/spec/modules/seedtagBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai' -import { spec, getTimeoutUrl } from 'modules/seedtagBidAdapter' +import { spec, getTimeoutUrl } from 'modules/seedtagBidAdapter.js' function getSlotConfigs(mediaTypes, params) { return { diff --git a/test/spec/modules/segmentoBidAdapter_spec.js b/test/spec/modules/segmentoBidAdapter_spec.js index 96f356b0ee2..17ad424f73f 100644 --- a/test/spec/modules/segmentoBidAdapter_spec.js +++ b/test/spec/modules/segmentoBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from '../../../modules/segmentoBidAdapter'; +import { spec } from '../../../modules/segmentoBidAdapter.js'; const BIDDER_CODE = 'segmento'; const URL = 'https://prebid-bidder.rutarget.ru/bid'; diff --git a/test/spec/modules/sekindoUMBidAdapter_spec.js b/test/spec/modules/sekindoUMBidAdapter_spec.js index 2718d26b2b4..2c361c21303 100644 --- a/test/spec/modules/sekindoUMBidAdapter_spec.js +++ b/test/spec/modules/sekindoUMBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/sekindoUMBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/sekindoUMBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; describe('sekindoUMAdapter', function () { const adapter = newBidder(spec); diff --git a/test/spec/modules/shareUserIds_spec.js b/test/spec/modules/shareUserIds_spec.js index 4ae5f93a1a6..451892919cb 100644 --- a/test/spec/modules/shareUserIds_spec.js +++ b/test/spec/modules/shareUserIds_spec.js @@ -1,4 +1,4 @@ -import {userIdTargeting} from '../../../modules/userIdTargeting'; +import {userIdTargeting} from '../../../modules/userIdTargeting.js'; import { expect } from 'chai'; describe('#userIdTargeting', function() { @@ -22,7 +22,7 @@ describe('#userIdTargeting', function() { pubads.clearTargeting(); pubads.setTargeting('test', ['TEST']); userIdTargeting(userIds, JSON.stringify(config)); - expect(pubads.getTargeting()).to.deep.equal({test: ['TEST']}); + expect(pubads.getTargeting('test')).to.deep.equal(['TEST']); }); it('all UserIds are passed as is with GAM: true', function() { @@ -31,7 +31,8 @@ describe('#userIdTargeting', function() { pubads.setTargeting('test', ['TEST']); delete config.GAM_KEYS; userIdTargeting(userIds, config); - expect(pubads.getTargeting()).to.deep.equal({test: ['TEST'], tdid: ['my-tdid']}); + expect(pubads.getTargeting('test')).to.deep.equal(['TEST']); + expect(pubads.getTargeting('tdid')).to.deep.equal(['my-tdid']); }) it('Publisher prefered key-names are used', function() { @@ -39,7 +40,8 @@ describe('#userIdTargeting', function() { pubads.clearTargeting(); pubads.setTargeting('test', ['TEST']); userIdTargeting(userIds, config); - expect(pubads.getTargeting()).to.deep.equal({test: ['TEST'], 'TD_ID': ['my-tdid']}); + expect(pubads.getTargeting('test')).to.deep.equal(['TEST']); + expect(pubads.getTargeting('TD_ID')).to.deep.equal(['my-tdid']); }); it('Publisher does not want to pass an id', function() { @@ -48,6 +50,6 @@ describe('#userIdTargeting', function() { pubads.setTargeting('test', ['TEST']); config.GAM_KEYS.tdid = ''; userIdTargeting(userIds, config); - expect(pubads.getTargeting()).to.deep.equal({test: ['TEST']}); + expect(pubads.getTargeting('test')).to.deep.equal(['TEST']); }); }); diff --git a/test/spec/modules/sharethroughBidAdapter_spec.js b/test/spec/modules/sharethroughBidAdapter_spec.js index 1dbd0abb169..92f9fd11eeb 100644 --- a/test/spec/modules/sharethroughBidAdapter_spec.js +++ b/test/spec/modules/sharethroughBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { sharethroughAdapterSpec, sharethroughInternal } from 'modules/sharethroughBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { sharethroughAdapterSpec, sharethroughInternal } from 'modules/sharethroughBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const spec = newBidder(sharethroughAdapterSpec).getSpec(); const bidRequests = [ @@ -457,7 +457,7 @@ describe('sharethrough adapter spec', function () { /data-str-native-key="pKey" data-stx-response-name="str_response_bidId"/); expect(!!adMarkup.indexOf(resp)).to.eql(true); expect(adMarkup).to.match( - /"'; diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js index caa806f9ccc..2faad47aca8 100644 --- a/test/spec/modules/smartadserverBidAdapter_spec.js +++ b/test/spec/modules/smartadserverBidAdapter_spec.js @@ -3,15 +3,15 @@ import { } from 'chai'; import { spec -} from 'modules/smartadserverBidAdapter'; +} from 'modules/smartadserverBidAdapter.js'; import { newBidder -} from 'src/adapters/bidderFactory'; +} from 'src/adapters/bidderFactory.js'; import { config -} from 'src/config'; -import * as utils from 'src/utils'; -import { requestBidsHook } from 'modules/consentManagement'; +} from 'src/config.js'; +import * as utils from 'src/utils.js'; +import { requestBidsHook } from 'modules/consentManagement.js'; // Default params with optional ones describe('Smart bid adapter tests', function () { @@ -42,7 +42,46 @@ describe('Smart bid adapter tests', function () { transactionId: 'zsfgzzg' }]; - // Default params without optional ones + 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: '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', bidId: 'abcd1234', @@ -271,6 +310,35 @@ describe('Smart bid adapter tests', function () { }); }); + describe('ccpa/us privacy tests', function () { + afterEach(function () { + config.resetConfig(); + $$PREBID_GLOBAL$$.requestBids.removeAll(); + }); + + it('Verify build request with us privacy', function () { + config.setConfig({ + 'currency': { + 'adServerCurrency': 'EUR' + }, + consentManagement: { + cmp: 'iab', + consentRequired: true, + timeout: 1000, + allowAuctionWithoutConsent: true + } + }); + + const uspConsentValue = '1YNN' + const request = spec.buildRequests(DEFAULT_PARAMS_WO_OPTIONAL, { + uspConsent: uspConsentValue + }); + const requestContent = JSON.parse(request[0].data); + + expect(requestContent).to.have.property('us_privacy').and.to.equal(uspConsentValue); + }); + }); + describe('Instream video tests', function () { afterEach(function () { config.resetConfig(); @@ -404,4 +472,76 @@ describe('Smart bid adapter tests', function () { expect(request[1]).to.not.be.empty; }); }); + + 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 = { + 'ver': '1.0', + 'complete': 1, + 'nodes': [ + { + 'asi': 'exchange1.com', + 'sid': '1234', + 'hp': 1, + 'rid': 'bid-request-1', + 'name': 'publisher', + 'domain': 'publisher.com' + }, + { + 'asi': 'exchange2.com', + 'sid': 'abcd', + 'hp': 1, + 'rid': 'bid-request-2', + 'name': 'intermediary', + 'domain': 'intermediary.com' + } + ] + }; + + let serializedSchain = spec.serializeSupplyChain(schain); + expect(serializedSchain).to.equal('1.0,1!exchange1.com,1234,1,bid-request-1,publisher,publisher.com!exchange2.com,abcd,1,bid-request-2,intermediary,intermediary.com'); + }); + + it('Verifiy that null schain produce null result', function () { + let actual = spec.serializeSupplyChain(null); + expect(null, actual); + }); + + it('Verifiy that schain with null nodes produce null result', function () { + let schain = { + 'ver': '1.0', + 'complete': 1 + + }; + let actual = spec.serializeSupplyChain(null); + expect(null, actual); + }); + }); }); diff --git a/test/spec/modules/smartrtbBidAdapter_spec.js b/test/spec/modules/smartrtbBidAdapter_spec.js index 955dd3ba471..cb5ceee0870 100644 --- a/test/spec/modules/smartrtbBidAdapter_spec.js +++ b/test/spec/modules/smartrtbBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai' -import { spec, _getPlatform } from 'modules/smartrtbBidAdapter' -import { newBidder } from 'src/adapters/bidderFactory' +import { spec, _getPlatform } from 'modules/smartrtbBidAdapter.js' +import { newBidder } from 'src/adapters/bidderFactory.js' const br = { body: { diff --git a/test/spec/modules/smartyadsBidAdapter_spec.js b/test/spec/modules/smartyadsBidAdapter_spec.js new file mode 100644 index 00000000000..2780e88255d --- /dev/null +++ b/test/spec/modules/smartyadsBidAdapter_spec.js @@ -0,0 +1,231 @@ +import {expect} from 'chai'; +import {spec} from '../../../modules/smartyadsBidAdapter.js'; + +describe('SmartyadsAdapter', function () { + let bid = { + bidId: '23fhj33i987f', + bidder: 'smartyads', + params: { + placementId: 0, + traffic: 'banner' + } + }; + + 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]); + 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-nj.webtradehub.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'); + let placement = data['placements'][0]; + expect(placement).to.have.keys('placementId', 'bidId', 'traffic', 'sizes'); + expect(placement.placementId).to.equal(0); + expect(placement.bidId).to.equal('23fhj33i987f'); + expect(placement.traffic).to.equal('banner'); + }); + 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://ssp-nj.webtradehub.com/?c=o&m=cookie'); + }); + }); +}); diff --git a/test/spec/modules/smilewantedBidAdapter_spec.js b/test/spec/modules/smilewantedBidAdapter_spec.js index 78a793137b6..0ac242ce0e1 100644 --- a/test/spec/modules/smilewantedBidAdapter_spec.js +++ b/test/spec/modules/smilewantedBidAdapter_spec.js @@ -1,9 +1,9 @@ import { expect } from 'chai'; -import { spec } from 'modules/smilewantedBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; -import { config } from 'src/config'; -import * as utils from 'src/utils'; -import { requestBidsHook } from 'modules/consentManagement'; +import { spec } from 'modules/smilewantedBidAdapter.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'; const DISPLAY_REQUEST = [{ adUnitCode: 'sw_300x250', diff --git a/test/spec/modules/smmsBidAdapter_spec.js b/test/spec/modules/smmsBidAdapter_spec.js index 3ed952811ea..3cbeb91cf5a 100644 --- a/test/spec/modules/smmsBidAdapter_spec.js +++ b/test/spec/modules/smmsBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; -import {spec, _getUrlVars} from 'modules/smmsBidAdapter'; -import * as utils from 'src/utils'; +import {spec, _getUrlVars} from 'modules/smmsBidAdapter.js'; +import * as utils from 'src/utils.js'; const BASE_URI = 'https://bidder.mediams.mb.softbank.jp/api/v1/prebid/banner' const NATIVE_BASE_URI = 'https://bidder.mediams.mb.softbank.jp/api/v1/prebid/native' diff --git a/test/spec/modules/somoBidAdapter_spec.js b/test/spec/modules/somoBidAdapter_spec.js index 8ffed99a16a..32e9c6c5323 100644 --- a/test/spec/modules/somoBidAdapter_spec.js +++ b/test/spec/modules/somoBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; -import {spec} from 'modules/somoBidAdapter'; -import * as utils from 'src/utils'; +import {spec} from 'modules/somoBidAdapter.js'; +import * as utils from 'src/utils.js'; describe('Somo Audience Adapter Tests', function () { describe('isBidRequestValid', function () { diff --git a/test/spec/modules/sonobiAnalyticsAdapter_spec.js b/test/spec/modules/sonobiAnalyticsAdapter_spec.js index d857c060f90..76ff88836d4 100644 --- a/test/spec/modules/sonobiAnalyticsAdapter_spec.js +++ b/test/spec/modules/sonobiAnalyticsAdapter_spec.js @@ -1,6 +1,6 @@ -import sonobiAnalytics from 'modules/sonobiAnalyticsAdapter'; +import sonobiAnalytics from 'modules/sonobiAnalyticsAdapter.js'; import {expect} from 'chai'; -import {server} from 'test/mocks/xhr'; +import {server} from 'test/mocks/xhr.js'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; let constants = require('src/constants.json'); diff --git a/test/spec/modules/sonobiBidAdapter_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js index eacd854f55e..52821072a21 100644 --- a/test/spec/modules/sonobiBidAdapter_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai' -import { spec, _getPlatform } from 'modules/sonobiBidAdapter' -import { newBidder } from 'src/adapters/bidderFactory' -import {userSync} from '../../../src/userSync'; +import { spec, _getPlatform } from 'modules/sonobiBidAdapter.js' +import { newBidder } from 'src/adapters/bidderFactory.js' +import {userSync} from '../../../src/userSync.js'; describe('SonobiBidAdapter', function () { const adapter = newBidder(spec) @@ -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) @@ -497,6 +456,20 @@ describe('SonobiBidAdapter', function () { const bidRequests = spec.buildRequests(bidRequest, bidderRequests); expect(bidRequests.data.us_privacy).to.equal('someCCPAString'); }); + + it('should make a request to the url defined in the bidder param', function() { + const bRequest = [ + { + ...bidRequest[0], + params: { + ...bidRequest[0].params, + bid_request_url: 'https://iad-2-apex.go.sonobi.com/trinity.json' + } + } + ]; + const bidRequests = spec.buildRequests(bRequest, bidderRequests); + expect(bidRequests.url).to.equal('https://iad-2-apex.go.sonobi.com/trinity.json'); + }) }); describe('.interpretResponse', function () { diff --git a/test/spec/modules/sortableAnalyticsAdapter_spec.js b/test/spec/modules/sortableAnalyticsAdapter_spec.js index 866f3fcb512..258c4b8f74d 100644 --- a/test/spec/modules/sortableAnalyticsAdapter_spec.js +++ b/test/spec/modules/sortableAnalyticsAdapter_spec.js @@ -1,9 +1,9 @@ import {expect} from 'chai'; -import sortableAnalyticsAdapter, {TIMEOUT_FOR_REGISTRY, DEFAULT_PBID_TIMEOUT} from 'modules/sortableAnalyticsAdapter'; -import events from 'src/events'; +import sortableAnalyticsAdapter, {TIMEOUT_FOR_REGISTRY, DEFAULT_PBID_TIMEOUT} from 'modules/sortableAnalyticsAdapter.js'; +import events from 'src/events.js'; import CONSTANTS from 'src/constants.json'; -import * as prebidGlobal from 'src/prebidGlobal'; -import {server} from 'test/mocks/xhr'; +import * as prebidGlobal from 'src/prebidGlobal.js'; +import {server} from 'test/mocks/xhr.js'; describe('Sortable Analytics Adapter', function() { let sandbox; @@ -154,6 +154,7 @@ describe('Sortable Analytics Adapter', function() { afterEach(function() { sandbox.restore(); + clock.restore(); sortableAnalyticsAdapter.disableAnalytics(); }); @@ -175,6 +176,9 @@ describe('Sortable Analytics Adapter', function() { }); describe('events tracking', function() { + beforeEach(function() { + server.requests = []; + }); it('should send the PBID event', function() { events.emit(CONSTANTS.EVENTS.AUCTION_INIT, TEST_DATA.AUCTION_INIT); events.emit(CONSTANTS.EVENTS.BID_REQUESTED, TEST_DATA.BID_REQUESTED); diff --git a/test/spec/modules/sortableBidAdapter_spec.js b/test/spec/modules/sortableBidAdapter_spec.js new file mode 100644 index 00000000000..8d2b4eea87d --- /dev/null +++ b/test/spec/modules/sortableBidAdapter_spec.js @@ -0,0 +1,539 @@ +import { expect } from 'chai'; +import { spec } from 'modules/sortableBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import * as utils from 'src/utils.js'; + +describe('sortableBidAdapter', function() { + const adapter = newBidder(spec); + + describe('isBidRequestValid', function () { + function makeBid() { + return { + 'bidder': 'sortable', + 'params': { + 'tagId': '403370', + 'siteId': 'example.com', + 'keywords': { + 'key1': 'val1', + 'key2': 'val2' + }, + 'floorSizeMap': { + '728x90': 0.15, + '300x250': 1.20 + } + }, + 'adUnitCode': 'adunit-code', + 'sizes': [ + [300, 250] + ], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }; + } + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(makeBid())).to.equal(true); + }); + + it('should return false when tagId not passed correctly', function () { + let bid = makeBid(); + delete bid.params.tagId; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when sizes not passed correctly', function () { + let bid = makeBid(); + delete bid.sizes; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when sizes are wrong length', function () { + let bid = makeBid(); + bid.sizes = [[300]]; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when sizes are empty', function () { + let bid = makeBid(); + bid.sizes = []; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when require params are not passed', function () { + let bid = makeBid(); + bid.params = {}; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return false when the floorSizeMap is invalid', function () { + let bid = makeBid(); + bid.params.floorSizeMap = { + 'sixforty by foureighty': 1234 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + bid.params.floorSizeMap = { + '728x90': 'three' + } + expect(spec.isBidRequestValid(bid)).to.equal(false); + bid.params.floorSizeMap = 'a'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return true when the floorSizeMap is missing or empty', function () { + let bid = makeBid(); + bid.params.floorSizeMap = {}; + expect(spec.isBidRequestValid(bid)).to.equal(true); + delete bid.params.floorSizeMap; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + it('should return false when the keywords are invalid', function () { + let bid = makeBid(); + bid.params.keywords = { + 'badval': 1234 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + bid.params.keywords = 'a'; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + + it('should return true when the keywords are missing or empty', function () { + let bid = makeBid(); + bid.params.keywords = {}; + expect(spec.isBidRequestValid(bid)).to.equal(true); + delete bid.params.keywords; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return true with video media type', () => { + const videoBid = { + 'bidder': 'sortable', + 'params': { + 'tagId': '403370', + 'siteId': 'example.com', + }, + 'adUnitCode': 'adunit-code', + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'mediaTypes': { + 'video': { + } + } + }; + expect(spec.isBidRequestValid(videoBid)).to.equal(true); + }); + }); + + describe('buildRequests', function () { + const bidRequests = [{ + 'bidder': 'sortable', + 'params': { + 'tagId': '403370', + 'siteId': 'example.com', + 'floor': 0.21, + 'keywords': { + 'key1': 'val1', + 'key2': 'val2' + }, + 'floorSizeMap': { + '728x90': 0.15, + '300x250': 1.20 + } + }, + 'sizes': [ + [300, 250] + ], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475' + }, { + 'bidder': 'sortable', + 'params': { + 'tagId': '403371', + 'siteId': 'example.com', + 'floor': 0.21 + }, + 'sizes': [ + [300, 250] + ], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'mediaTypes': { + 'native': { + 'body': {'required': true, 'sendId': true}, + 'clickUrl': {'required': true, 'sendId': true}, + 'cta': {'required': true, 'sendId': true}, + 'icon': {'required': true, 'sendId': true}, + 'image': {'required': true, 'sendId': true}, + 'sponsoredBy': {'required': true, 'sendId': true}, + 'title': {'required': true, 'sendId': true, 'len': 100} + } + } + }]; + + const request = spec.buildRequests(bidRequests, {refererInfo: { referer: 'http://example.com/page?param=val' }}); + const requestBody = JSON.parse(request.data); + + it('sends bid request to our endpoint via POST', function () { + expect(request.method).to.equal('POST'); + }); + + it('attaches source and version to endpoint URL as query params', function () { + const ENDPOINT = `https://c.deployads.com/openrtb2/auction?src=$$REPO_AND_VERSION$$&host=example.com`; + expect(request.url).to.equal(ENDPOINT); + }); + + it('sends screen dimensions', function () { + expect(requestBody.site.device.w).to.equal(screen.width); + expect(requestBody.site.device.h).to.equal(screen.height); + }); + + it('includes the ad size in the bid request', function () { + expect(requestBody.imp[0].banner.format[0].w).to.equal(300); + expect(requestBody.imp[0].banner.format[0].h).to.equal(250); + }); + + it('includes the params in the bid request', function () { + expect(requestBody.imp[0].ext.keywords).to.deep.equal( + {'key1': 'val1', + 'key2': 'val2'} + ); + expect(requestBody.site.publisher.id).to.equal('example.com'); + expect(requestBody.imp[0].tagid).to.equal('403370'); + expect(requestBody.imp[0].bidfloor).to.equal(0.21); + }); + + it('should have the floor size map set', function () { + expect(requestBody.imp[0].ext.floorSizeMap).to.deep.equal({ + '728x90': 0.15, + '300x250': 1.20 + }); + }); + + it('sets domain and href correctly', function () { + expect(requestBody.site.domain).to.equal('example.com'); + expect(requestBody.site.page).to.equal('http://example.com/page?param=val'); + }); + + it('should have the version in native object set for native bid', function() { + expect(requestBody.imp[1].native.ver).to.equal('1'); + }); + + it('should have the assets set for native bid', function() { + const assets = JSON.parse(requestBody.imp[1].native.request).assets; + expect(assets[0]).to.deep.equal({'title': {'len': 100}, 'required': 1, 'id': 0}); + expect(assets[1]).to.deep.equal({'img': {'type': 3, 'wmin': 1, 'hmin': 1}, 'required': 1, 'id': 1}); + expect(assets[2]).to.deep.equal({'img': {'type': 1, 'wmin': 1, 'hmin': 1}, 'required': 1, 'id': 2}); + expect(assets[3]).to.deep.equal({'data': {'type': 2}, 'required': 1, 'id': 3}); + expect(assets[4]).to.deep.equal({'data': {'type': 12}, 'required': 1, 'id': 4}); + expect(assets[5]).to.deep.equal({'data': {'type': 1}, 'required': 1, 'id': 5}); + }); + + const videoBidRequests = [{ + 'bidder': 'sortable', + 'params': { + 'tagId': '403370', + 'siteId': 'example.com', + 'video': { + 'minduration': 5, + 'maxduration': 10, + 'startdelay': 0 + } + }, + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + 'mediaTypes': { + 'video': { + 'context': 'instream', + 'mimes': ['video/x-ms-wmv'], + 'playerSize': [[400, 300]], + 'api': [0], + 'protocols': [2, 3], + 'playbackmethod': [1] + } + } + }]; + + const videoRequest = spec.buildRequests(videoBidRequests, {refererInfo: { referer: 'http://localhost:9876/' }}); + const videoRequestBody = JSON.parse(videoRequest.data); + + it('should include video params', () => { + const video = videoRequestBody.imp[0].video; + expect(video.mimes).to.deep.equal(['video/x-ms-wmv']); + expect(video.w).to.equal(400); + expect(video.h).to.equal(300); + expect(video.api).to.deep.equal([0]); + expect(video.protocols).to.deep.equal([2, 3]); + expect(video.playbackmethod).to.deep.equal([1]); + expect(video.minduration).to.equal(5); + expect(video.maxduration).to.equal(10); + expect(video.startdelay).to.equal(0); + }); + + it('sets domain and href correctly', function () { + expect(videoRequestBody.site.domain).to.equal('localhost'); + expect(videoRequestBody.site.page).to.equal('http://localhost:9876/'); + }); + + const gdprBidRequests = [{ + 'bidder': 'sortable', + 'params': { + 'tagId': '403370', + 'siteId': 'example.com', + 'floor': 0.21, + 'keywords': {}, + 'floorSizeMap': {} + }, + 'sizes': [ + [300, 250] + ], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475' + }]; + const consentString = 'BOJ/P2HOJ/P2HABABMAAAAAZ+A=='; + + function getGdprRequestBody(gdprApplies, consentString) { + const gdprRequest = spec.buildRequests(gdprBidRequests, {'gdprConsent': { + 'gdprApplies': gdprApplies, + 'consentString': consentString + }, + refererInfo: { + referer: 'http://localhost:9876/' + }}); + return JSON.parse(gdprRequest.data); + } + + it('should handle gdprApplies being present and true', function() { + const gdprRequestBody = getGdprRequestBody(true, consentString); + expect(gdprRequestBody.regs.ext.gdpr).to.equal(1); + expect(gdprRequestBody.user.ext.consent).to.equal(consentString); + }) + + it('should handle gdprApplies being present and false', function() { + const gdprRequestBody = getGdprRequestBody(false, consentString); + expect(gdprRequestBody.regs.ext.gdpr).to.equal(0); + expect(gdprRequestBody.user.ext.consent).to.equal(consentString); + }) + + it('should handle gdprApplies being undefined', function() { + const gdprRequestBody = getGdprRequestBody(undefined, consentString); + expect(gdprRequestBody.regs).to.deep.equal({ext: {}}); + expect(gdprRequestBody.user.ext.consent).to.equal(consentString); + }) + + it('should handle gdprConsent being undefined', function() { + const gdprRequest = spec.buildRequests(gdprBidRequests, {refererInfo: { referer: 'http://localhost:9876/' }}); + const gdprRequestBody = JSON.parse(gdprRequest.data); + expect(gdprRequestBody.regs).to.deep.equal({ext: {}}); + expect(gdprRequestBody.user).to.equal(undefined); + }) + }); + + describe('interpretResponse', function () { + function makeResponse() { + return { + body: { + 'id': '5e5c23a5ba71e78', + 'seatbid': [ + { + 'bid': [ + { + 'id': '6vmb3isptf', + 'crid': 'sortablescreative', + 'impid': '322add653672f68', + 'price': 1.22, + 'adm': '', + 'attr': [5], + 'h': 90, + 'nurl': 'http://nurl', + 'w': 728 + } + ], + 'seat': 'MOCK' + } + ], + 'bidid': '5e5c23a5ba71e78' + } + }; + } + + function makeNativeResponse() { + return { + body: { + 'id': '5e5c23a5ba71e77', + 'seatbid': [ + { + 'bid': [ + { + 'id': '6vmb3isptf', + 'crid': 'sortablescreative', + 'impid': '322add653672f67', + 'price': 1.55, + 'adm': '{"native":{"link":{"clicktrackers":[],"url":"https://www.sortable.com/"},"assets":[{"title":{"text":"Ads With Sortable"},"id":1},{"img":{"w":790,"url":"https://path.to/image","h":294},"id":2},{"img":{"url":"https://path.to/icon"},"id":3},{"data":{"value":"Body here"},"id":4},{"data":{"value":"Learn More"},"id":5},{"data":{"value":"Sortable"},"id":6}],"imptrackers":[],"ver":1}}', + 'ext': {'ad_format': 'native'}, + 'h': 90, + 'nurl': 'http://nurl', + 'w': 728 + } + ], + 'seat': 'MOCK' + } + ], + 'bidid': '5e5c23a5ba71e77' + } + }; + } + + const expectedBid = { + 'requestId': '322add653672f68', + 'cpm': 1.22, + 'width': 728, + 'height': 90, + 'creativeId': 'sortablescreative', + 'dealId': null, + 'currency': 'USD', + 'netRevenue': true, + 'mediaType': 'banner', + 'ttl': 60, + 'ad': '
' + }; + + const expectedNativeBid = { + 'requestId': '322add653672f67', + 'cpm': 1.55, + 'width': 728, + 'height': 90, + 'creativeId': 'sortablescreative', + 'dealId': null, + 'currency': 'USD', + 'netRevenue': true, + 'sortable': { 'ad_format': 'native' }, + 'mediaType': 'native', + 'ttl': 60, + 'native': { + 'clickUrl': 'https://www.sortable.com/', + 'title': 'Ads With Sortable', + 'image': {'url': 'https://path.to/image', 'height': 294, 'width': 790}, + 'icon': 'https://path.to/icon', + 'body': 'Body here', + 'cta': 'Learn More', + 'sponsoredBy': 'Sortable' + } + }; + + it('should get the correct bid response', function () { + let result = spec.interpretResponse(makeResponse()); + expect(result.length).to.equal(1); + expect(result[0]).to.deep.equal(expectedBid); + }); + + it('should handle a missing crid', function () { + let noCridResponse = makeResponse(); + delete noCridResponse.body.seatbid[0].bid[0].crid; + const fallbackCrid = noCridResponse.body.seatbid[0].bid[0].id; + let noCridResult = Object.assign({}, expectedBid, {'creativeId': fallbackCrid}); + let result = spec.interpretResponse(noCridResponse); + expect(result.length).to.equal(1); + expect(result[0]).to.deep.equal(noCridResult); + }); + + it('should handle a missing nurl', function () { + let noNurlResponse = makeResponse(); + delete noNurlResponse.body.seatbid[0].bid[0].nurl; + let noNurlResult = Object.assign({}, expectedBid); + noNurlResult.ad = ''; + let result = spec.interpretResponse(noNurlResponse); + expect(result.length).to.equal(1); + expect(result[0]).to.deep.equal(noNurlResult); + }); + + it('should handle a missing adm', function () { + let noAdmResponse = makeResponse(); + delete noAdmResponse.body.seatbid[0].bid[0].adm; + let noAdmResult = Object.assign({}, expectedBid); + delete noAdmResult.ad; + noAdmResult.adUrl = 'http://nurl'; + let result = spec.interpretResponse(noAdmResponse); + expect(result.length).to.equal(1); + expect(result[0]).to.deep.equal(noAdmResult); + }); + + it('handles empty bid response', function () { + let response = { + body: { + 'id': '5e5c23a5ba71e78', + 'seatbid': [] + } + }; + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); + }); + + it('should get the correct native bid response', function () { + let result = spec.interpretResponse(makeNativeResponse()); + expect(result.length).to.equal(1); + expect(result[0]).to.deep.equal(expectedNativeBid); + }); + + it('fail to parse invalid native bid response', function () { + let response = makeNativeResponse(); + response.body.seatbid[0].bid[0].adm = ''; + let result = spec.interpretResponse(response); + expect(result.length).to.equal(0); + }); + + it('should keep custom properties', () => { + const customProperties = {test: 'a test message', param: {testParam: 1}}; + const expectedResult = Object.assign({}, expectedBid, {[spec.code]: customProperties}); + const response = makeResponse(); + response.body.seatbid[0].bid[0].ext = customProperties; + const result = spec.interpretResponse(response); + expect(result.length).to.equal(1); + expect(result[0]).to.deep.equal(expectedResult); + }); + + it('should handle instream response', () => { + const response = makeResponse(); + const bid = response.body.seatbid[0].bid[0]; + delete bid.nurl; + bid.ext = {ad_format: 'instream'}; + const result = spec.interpretResponse(response)[0]; + expect(result.mediaType).to.equal('video'); + expect(result.vastXml).to.equal(bid.adm); + }); + + it('should return iframe syncs', () => { + const syncResponse = { + ext: { + sync_dsps: [ + ['iframe', 'http://example-dsp/sync-iframe'], + ['image', 'http://example-dsp/sync-image'] + ] + } + }; + expect(spec.getUserSyncs({iframeEnabled: true}, [{body: syncResponse}])).to.deep.equal([{ + type: 'iframe', + url: 'http://example-dsp/sync-iframe' + }]); + }); + + it('should return image syncs', () => { + const syncResponse = { + ext: { + sync_dsps: [ + ['iframe', 'http://example-dsp/sync-iframe'], + ['image', 'http://example-dsp/sync-image'] + ] + } + }; + expect(spec.getUserSyncs({pixelEnabled: true}, [{body: syncResponse}])).to.deep.equal([{ + type: 'image', + url: 'http://example-dsp/sync-image' + }]); + }); + }); +}); diff --git a/test/spec/modules/sovrnAnalyticsAdapter_spec.js b/test/spec/modules/sovrnAnalyticsAdapter_spec.js index 25c615f0d5c..d6795331417 100644 --- a/test/spec/modules/sovrnAnalyticsAdapter_spec.js +++ b/test/spec/modules/sovrnAnalyticsAdapter_spec.js @@ -1,8 +1,8 @@ -import sovrnAnalyticsAdapter from '../../../modules/sovrnAnalyticsAdapter'; +import sovrnAnalyticsAdapter from '../../../modules/sovrnAnalyticsAdapter.js'; import { expect } from 'chai'; -import {config} from 'src/config'; -import adaptermanager from 'src/adapterManager'; -import { server } from 'test/mocks/xhr'; +import {config} from 'src/config.js'; +import adaptermanager from 'src/adapterManager.js'; +import { server } from 'test/mocks/xhr.js'; var assert = require('assert'); let events = require('src/events'); diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js index 0778b6487c2..54ccff870eb 100644 --- a/test/spec/modules/sovrnBidAdapter_spec.js +++ b/test/spec/modules/sovrnBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; -import {LogError, spec} from 'modules/sovrnBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; +import {LogError, spec} from 'modules/sovrnBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; const ENDPOINT = `https://ap.lijit.com/rtb/bid?src=$$REPO_AND_VERSION$$`; @@ -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 d9890a85154..78d17f35c69 100644 --- a/test/spec/modules/spotxBidAdapter_spec.js +++ b/test/spec/modules/spotxBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import {spec, GOOGLE_CONSENT} from 'modules/spotxBidAdapter'; +import {spec, GOOGLE_CONSENT} from 'modules/spotxBidAdapter.js'; describe('the spotx adapter', function () { function getValidBidObject() { @@ -144,7 +144,11 @@ 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 = { @@ -169,6 +173,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 +185,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); @@ -297,6 +307,30 @@ 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); + }); }); describe('interpretResponse', function() { diff --git a/test/spec/modules/staqAnalyticsAdapter_spec.js b/test/spec/modules/staqAnalyticsAdapter_spec.js index 1b35f491854..f8e3ba83bbe 100644 --- a/test/spec/modules/staqAnalyticsAdapter_spec.js +++ b/test/spec/modules/staqAnalyticsAdapter_spec.js @@ -1,6 +1,6 @@ -import analyticsAdapter, { ExpiringQueue, getUmtSource, storage } from 'modules/staqAnalyticsAdapter'; +import analyticsAdapter, { ExpiringQueue, getUmtSource, storage } from 'modules/staqAnalyticsAdapter.js'; import { expect } from 'chai'; -import adapterManager from 'src/adapterManager'; +import adapterManager from 'src/adapterManager.js'; import CONSTANTS from 'src/constants.json'; const events = require('../../../src/events'); diff --git a/test/spec/modules/stvBidAdapter_spec.js b/test/spec/modules/stvBidAdapter_spec.js index 72ea428304a..c2278313b2d 100644 --- a/test/spec/modules/stvBidAdapter_spec.js +++ b/test/spec/modules/stvBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/stvBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/stvBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const VADS_ENDPOINT_URL = 'https://ads.smartstream.tv/r/'; diff --git a/test/spec/modules/sublimeBidAdapter_spec.js b/test/spec/modules/sublimeBidAdapter_spec.js index 45173b09953..ae9e293a757 100644 --- a/test/spec/modules/sublimeBidAdapter_spec.js +++ b/test/spec/modules/sublimeBidAdapter_spec.js @@ -1,10 +1,30 @@ import { expect } from 'chai'; -import { spec } from 'modules/sublimeBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec, sendEvent, log, setState, state } from 'modules/sublimeBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; + +let utils = require('src/utils'); describe('Sublime Adapter', function() { const adapter = newBidder(spec); + describe('sendEvent', function() { + let sandbox; + + beforeEach(function () { + sandbox = sinon.sandbox.create(); + }); + + it('should trigger pixel', function () { + sandbox.spy(utils, 'triggerPixel'); + sendEvent('test', true); + expect(utils.triggerPixel.called).to.equal(true); + }); + + afterEach(function () { + sandbox.restore(); + }); + }) + describe('inherited functions', function() { it('exists and is a function', function() { expect(adapter.callBids).to.exist.and.to.be.a('function'); @@ -129,6 +149,7 @@ describe('Sublime Adapter', function() { currency: 'USD', netRevenue: true, ttl: 600, + pbav: '0.5.2', ad: '', }, ]; @@ -170,6 +191,7 @@ describe('Sublime Adapter', function() { netRevenue: true, ttl: 600, ad: '', + pbav: '0.5.2', }; expect(result[0]).to.deep.equal(expectedResponse); @@ -219,6 +241,7 @@ describe('Sublime Adapter', function() { netRevenue: true, ttl: 600, ad: '', + pbav: '0.5.2', }; expect(result[0]).to.deep.equal(expectedResponse); @@ -250,6 +273,10 @@ describe('Sublime Adapter', function() { let expectedResponse = []; expect(result).to.deep.equal(expectedResponse); + + describe('On bid Time out', function () { + spec.onTimeout(result); + }); }); }); }); diff --git a/test/spec/modules/synacormediaBidAdapter_spec.js b/test/spec/modules/synacormediaBidAdapter_spec.js index 918e4e394bd..e15481d47e5 100644 --- a/test/spec/modules/synacormediaBidAdapter_spec.js +++ b/test/spec/modules/synacormediaBidAdapter_spec.js @@ -1,6 +1,7 @@ import { assert, expect } from 'chai'; -import { BANNER } from 'src/mediaTypes'; -import { spec } from 'modules/synacormediaBidAdapter'; +import { BANNER } from 'src/mediaTypes.js'; +import {config} from 'src/config.js'; +import { spec } from 'modules/synacormediaBidAdapter.js'; describe('synacormediaBidAdapter ', function () { describe('isBidRequestValid', function () { @@ -67,9 +68,13 @@ describe('synacormediaBidAdapter ', function () { }, mediaTypes: { banner: { - h: 600, - pos: 0, - w: 300, + format: [ + { + w: 300, + h: 600 + } + ], + pos: 0 } }, }; @@ -172,21 +177,19 @@ describe('synacormediaBidAdapter ', function () { let expectedDataImp1 = { banner: { - h: 250, - pos: 0, - w: 300, - }, - id: 'b9876abcd-300x250', - tagid: '1234', - bidfloor: 0.5 - }; - let expectedDataImp2 = { - 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 }; @@ -200,7 +203,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); @@ -229,13 +232,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 }]); @@ -259,11 +266,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: 'bfoobar-300x250', + id: 'bfoobar', tagid: '5678', bidfloor: 0.5 } @@ -288,11 +299,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', } ]); @@ -315,11 +330,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', } ]); @@ -343,11 +362,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' } ]); @@ -370,11 +393,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' } ]); @@ -535,6 +562,109 @@ describe('synacormediaBidAdapter ', function () { }); }); + describe('Bid Requests with schain object ', function() { + let validBidReq = { + bidder: 'synacormedia', + params: { + seatId: 'prebid', + placementId: 'demo1', + pos: 1, + video: {} + }, + renderer: { + url: '../syncOutstreamPlayer.js' + }, + mediaTypes: { + video: { + playerSize: [[300, 250]], + context: 'outstream' + } + }, + adUnitCode: 'div-1', + transactionId: '0869f34e-090b-4b20-84ee-46ff41405a39', + sizes: [[300, 250]], + bidId: '22b3a2268d9f0e', + bidderRequestId: '1d195910597e13', + auctionId: '3375d336-2aea-4ee7-804c-6d26b621ad20', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + schain: { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + hp: 1 + } + ] + } + }; + let bidderRequest = { + refererInfo: { + referer: 'http://localhost:9999/' + }, + bidderCode: 'synacormedia', + auctionId: 'f8a75621-d672-4cbb-9275-3db7d74fb110', + bidderRequestId: '16d438671bfbec', + bids: [ + { + bidder: 'synacormedia', + params: { + seatId: 'prebid', + placementId: 'demo1', + pos: 1, + video: {} + }, + renderer: { + url: '../syncOutstreamPlayer.js' + }, + mediaTypes: { + video: { + playerSize: [[300, 250]], + context: 'outstream' + } + }, + adUnitCode: 'div-1', + sizes: [[300, 250]], + bidId: '211c0236bb8f4e', + bidderRequestId: '16d438671bfbec', + auctionId: 'f8a75621-d672-4cbb-9275-3db7d74fb110', + src: 'client', + bidRequestsCount: 1, + bidderRequestsCount: 1, + bidderWinsCount: 0, + schain: { + ver: '1.0', + complete: 1, + nodes: [ + { + asi: 'indirectseller.com', + sid: '00001', + hp: 1 + } + ] + } + } + ], + auctionStart: 1580310345205, + timeout: 1000, + start: 1580310345211 + }; + + it('should return valid bid request with schain object', function () { + let req = spec.buildRequests([validBidReq], bidderRequest); + expect(req).to.have.property('method', 'POST'); + expect(req).to.have.property('url'); + expect(req.url).to.contain('//prebid.technoratimedia.com/openrtb/bids/prebid?src=$$REPO_AND_VERSION$$'); + expect(req.data).to.have.property('source'); + expect(req.data.source).to.have.property('ext'); + expect(req.data.source.ext).to.have.property('schain'); + }); + }); + describe('interpretResponse', function () { let bidResponse = { id: '10865933907263896~9998~0', @@ -676,6 +806,44 @@ describe('synacormediaBidAdapter ', function () { expect(spec.interpretResponse({ body: null })).to.not.exist; expect(spec.interpretResponse({ body: 'some error text' })).to.not.exist; }); + + it('should not include videoCacheKey property on the returned response when cache url is present in the config', function () { + let sandbox = sinon.sandbox.create(); + let serverRespVideo = { + body: { + id: 'abcd1234', + seatbid: [ + { + bid: [ + { + id: '11339128001692337~9999~0', + impid: 'v2da7322b2df61f-640x480', + 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' + } + ] + } + }; + + sandbox.stub(config, 'getConfig').callsFake(key => { + const config = { + 'cache.url': 'faKeCacheUrl' + }; + return config[key]; + }); + + let resp = spec.interpretResponse(serverRespVideo); + sandbox.restore(); + expect(resp[0].videoCacheKey).to.not.exist; + }); }); describe('getUserSyncs', function () { it('should return a usersync when iframes is enabled', function () { diff --git a/test/spec/modules/taphypeBidAdapter_spec.js b/test/spec/modules/taphypeBidAdapter_spec.js index 2fcdd964520..6b36973814e 100644 --- a/test/spec/modules/taphypeBidAdapter_spec.js +++ b/test/spec/modules/taphypeBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/taphypeBidAdapter'; +import { spec } from 'modules/taphypeBidAdapter.js'; describe('taphypeBidAdapterTests', function () { it('validate_pub_params', function () { diff --git a/test/spec/modules/teadsBidAdapter_spec.js b/test/spec/modules/teadsBidAdapter_spec.js index c557eef7aca..cc5bbb840a9 100644 --- a/test/spec/modules/teadsBidAdapter_spec.js +++ b/test/spec/modules/teadsBidAdapter_spec.js @@ -1,6 +1,6 @@ import {expect} from 'chai'; -import {spec} from 'modules/teadsBidAdapter'; -import {newBidder} from 'src/adapters/bidderFactory'; +import {spec} from 'modules/teadsBidAdapter.js'; +import {newBidder} from 'src/adapters/bidderFactory.js'; const ENDPOINT = 'https://a.teads.tv/hb/bid-request'; const AD_SCRIPT = '"'; @@ -136,7 +136,8 @@ describe('teadsBidAdapter', () => { 'gdprApplies': true, 'vendorData': { 'hasGlobalConsent': false - } + }, + 'apiVersion': 1 } }; @@ -146,6 +147,7 @@ describe('teadsBidAdapter', () => { expect(payload.gdpr_iab).to.exist; expect(payload.gdpr_iab.consent).to.equal(consentString); expect(payload.gdpr_iab.status).to.equal(12); + expect(payload.gdpr_iab.apiVersion).to.equal(1); }); it('should add referer info to payload', function () { @@ -164,6 +166,29 @@ 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 send GDPR to endpoint with 11 status', function() { let consentString = 'JRJ8RKfDeBNsERRDCSAAZ+A=='; let bidderRequest = { @@ -175,7 +200,8 @@ describe('teadsBidAdapter', () => { 'gdprApplies': true, 'vendorData': { 'hasGlobalScope': true - } + }, + 'apiVersion': 1 } }; @@ -185,6 +211,32 @@ describe('teadsBidAdapter', () => { expect(payload.gdpr_iab).to.exist; expect(payload.gdpr_iab.consent).to.equal(consentString); expect(payload.gdpr_iab.status).to.equal(11); + expect(payload.gdpr_iab.apiVersion).to.equal(1); + }); + + it('should send GDPR TCF2 to endpoint with 12 status', function() { + let consentString = 'JRJ8RKfDeBNsERRDCSAAZ+A=='; + let bidderRequest = { + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gdprConsent': { + 'consentString': consentString, + 'gdprApplies': true, + 'vendorData': { + 'isServiceSpecific': true + }, + 'apiVersion': 2 + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.gdpr_iab).to.exist; + expect(payload.gdpr_iab.consent).to.equal(consentString); + expect(payload.gdpr_iab.status).to.equal(12); + expect(payload.gdpr_iab.apiVersion).to.equal(2); }); it('should send GDPR to endpoint with 22 status', function() { @@ -196,7 +248,8 @@ describe('teadsBidAdapter', () => { 'gdprConsent': { 'consentString': undefined, 'gdprApplies': undefined, - 'vendorData': undefined + 'vendorData': undefined, + 'apiVersion': 1 } }; @@ -206,6 +259,7 @@ describe('teadsBidAdapter', () => { expect(payload.gdpr_iab).to.exist; expect(payload.gdpr_iab.consent).to.equal(''); expect(payload.gdpr_iab.status).to.equal(22); + expect(payload.gdpr_iab.apiVersion).to.equal(1); }); it('should send GDPR to endpoint with 0 status', function() { @@ -219,7 +273,8 @@ describe('teadsBidAdapter', () => { 'gdprApplies': false, 'vendorData': { 'hasGlobalScope': false - } + }, + 'apiVersion': 1 } }; @@ -229,6 +284,55 @@ describe('teadsBidAdapter', () => { expect(payload.gdpr_iab).to.exist; expect(payload.gdpr_iab.consent).to.equal(consentString); expect(payload.gdpr_iab.status).to.equal(0); + expect(payload.gdpr_iab.apiVersion).to.equal(1); + }); + + it('should send GDPR to endpoint with 0 status when gdprApplies = false (vendorData = undefined)', function() { + let consentString = 'JRJ8RKfDeBNsERRDCSAAZ+A=='; + let bidderRequest = { + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gdprConsent': { + 'consentString': undefined, + 'gdprApplies': false, + 'vendorData': undefined, + 'apiVersion': 1 + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.gdpr_iab).to.exist; + expect(payload.gdpr_iab.consent).to.equal(''); + expect(payload.gdpr_iab.status).to.equal(0); + expect(payload.gdpr_iab.apiVersion).to.equal(1); + }); + + it('should send GDPR to endpoint with 12 status when apiVersion = 0', function() { + let consentString = 'JRJ8RKfDeBNsERRDCSAAZ+A=='; + let bidderRequest = { + 'auctionId': '1d1a030790a475', + 'bidderRequestId': '22edbae2733bf6', + 'timeout': 3000, + 'gdprConsent': { + 'consentString': consentString, + 'gdprApplies': true, + 'vendorData': { + 'hasGlobalScope': false + }, + 'apiVersion': 0 + } + }; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = JSON.parse(request.data); + + expect(payload.gdpr_iab).to.exist; + expect(payload.gdpr_iab.consent).to.equal(consentString); + expect(payload.gdpr_iab.status).to.equal(12); + expect(payload.gdpr_iab.apiVersion).to.equal(0); }); it('should use good mediaTypes video playerSizes', function() { @@ -322,39 +426,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() { @@ -368,71 +496,4 @@ describe('teadsBidAdapter', () => { expect(result.length).to.equal(0); }); }); - - it('should call userSync with good params', function() { - let bids = [{ - 'body': { - 'responses': [{ - 'ad': '', + 'adid': '144762342', + 'adomain': [ + 'https://dummydomain.com' + ], + 'iurl': 'iurl', + 'cid': '109', + 'crid': 'creativeId', + 'cat': [], + 'w': 300, + 'h': 250, + 'ext': { + 'prebid': { + 'type': 'banner' + }, + 'bidder': { + 'appnexus': { + 'brand_id': 334553, + 'auction_id': 514667951122925701, + 'bidder_id': 2, + 'bid_ad_type': 0 + } + } + } + }, + { + 'id': 'bidId2', + 'impid': 'bidId2', + 'price': 0.1, + 'adm': '', + 'adid': '144762342', + 'adomain': [ + 'https://dummydomain.com' + ], + 'iurl': 'iurl', + 'cid': '109', + 'crid': 'creativeId', + 'cat': [], + 'w': 300, + 'h': 250, + 'ext': { + 'prebid': { + 'type': 'banner' + }, + 'bidder': { + 'appnexus': { + 'brand_id': 386046, + 'auction_id': 517067951122925501, + 'bidder_id': 2, + 'bid_ad_type': 0 + } + } + } + } + ], + 'seat': 'yieldlift' + } + ], + 'ext': { + 'usersync': { + 'sovrn': { + 'status': 'none', + 'syncs': [ + { + 'url': 'urlsovrn', + 'type': 'iframe' + } + ] + }, + 'appnexus': { + 'status': 'none', + 'syncs': [ + { + 'url': 'urlappnexus', + 'type': 'pixel' + } + ] + } + }, + 'responsetimemillis': { + 'appnexus': 127 + } + } + } +}; + +describe('YieldLift', function () { + describe('isBidRequestValid', function () { + it('should accept request if only unitId is passed', function () { + let bid = { + bidder: 'yieldlift', + params: { + unitId: 'unitId', + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + it('should accept request if only networkId is passed', function () { + let bid = { + bidder: 'yieldlift', + params: { + networkId: 'networkId', + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + it('should accept request if only publisherId is passed', function () { + let bid = { + bidder: 'yieldlift', + params: { + publisherId: 'publisherId', + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('reject requests without params', function () { + let bid = { + bidder: 'yieldlift', + params: {} + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('buildRequests', function () { + it('creates request data', function () { + let request = spec.buildRequests(REQUEST.bidRequest, REQUEST); + + expect(request).to.exist.and.to.be.a('object'); + const payload = JSON.parse(request.data); + expect(payload.imp[0]).to.have.property('id', REQUEST.bidRequest[0].bidId); + expect(payload.imp[1]).to.have.property('id', REQUEST.bidRequest[1].bidId); + }); + + it('has gdpr data if applicable', function () { + const req = Object.assign({}, REQUEST, { + gdprConsent: { + consentString: 'consentString', + gdprApplies: true, + } + }); + let request = spec.buildRequests(REQUEST.bidRequest, req); + + const payload = JSON.parse(request.data); + expect(payload.user.ext).to.have.property('consent', req.gdprConsent.consentString); + expect(payload.regs.ext).to.have.property('gdpr', 1); + }); + }); + + describe('interpretResponse', function () { + it('have bids', function () { + let bids = spec.interpretResponse(RESPONSE, REQUEST); + expect(bids).to.be.an('array').that.is.not.empty; + validateBidOnIndex(0); + validateBidOnIndex(1); + + function validateBidOnIndex(index) { + expect(bids[index]).to.have.property('currency', 'USD'); + expect(bids[index]).to.have.property('requestId', RESPONSE.body.seatbid[0].bid[index].impid); + expect(bids[index]).to.have.property('cpm', RESPONSE.body.seatbid[0].bid[index].price); + expect(bids[index]).to.have.property('width', RESPONSE.body.seatbid[0].bid[index].w); + 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]).to.have.property('ttl', 30); + expect(bids[index]).to.have.property('netRevenue', true); + } + }); + + it('handles empty response', function () { + const EMPTY_RESP = Object.assign({}, RESPONSE, {'body': {}}); + const bids = spec.interpretResponse(EMPTY_RESP, REQUEST); + + expect(bids).to.be.empty; + }); + }); + + describe('getUserSyncs', function () { + it('handles no parameters', function () { + let opts = spec.getUserSyncs({}); + expect(opts).to.be.an('array').that.is.empty; + }); + it('returns non if sync is not allowed', function () { + let opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: false}); + + expect(opts).to.be.an('array').that.is.empty; + }); + + it('iframe sync enabled should return results', function () { + let opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: false}, [RESPONSE]); + + expect(opts.length).to.equal(1); + expect(opts[0].type).to.equal('iframe'); + expect(opts[0].url).to.equal(RESPONSE.body.ext.usersync['sovrn'].syncs[0].url); + }); + + it('pixel sync enabled should return results', function () { + let opts = spec.getUserSyncs({iframeEnabled: false, pixelEnabled: true}, [RESPONSE]); + + expect(opts.length).to.equal(1); + expect(opts[0].type).to.equal('image'); + expect(opts[0].url).to.equal(RESPONSE.body.ext.usersync['appnexus'].syncs[0].url); + }); + + it('all sync enabled should return all results', function () { + let opts = spec.getUserSyncs({iframeEnabled: true, pixelEnabled: true}, [RESPONSE]); + + expect(opts.length).to.equal(2); + }); + }); +}); diff --git a/test/spec/modules/yieldmoBidAdapter_spec.js b/test/spec/modules/yieldmoBidAdapter_spec.js index 6a4a142975f..1c4c4812680 100644 --- a/test/spec/modules/yieldmoBidAdapter_spec.js +++ b/test/spec/modules/yieldmoBidAdapter_spec.js @@ -1,51 +1,55 @@ import { expect } from 'chai'; -import { spec } from 'modules/yieldmoBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; -import * as utils from 'src/utils'; +import { spec } from 'modules/yieldmoBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; +import * as utils from 'src/utils.js'; describe('YieldmoAdapter', function () { const adapter = newBidder(spec); const ENDPOINT = 'https://ads.yieldmo.com/exchange/prebid'; let tdid = '8d146286-91d4-4958-aff4-7e489dd1abd6'; + let criteoId = 'aff4'; let bid = { bidder: 'yieldmo', params: { - bidFloor: 0.1 + bidFloor: 0.1, }, adUnitCode: 'adunit-code', mediaTypes: { banner: { - sizes: [[300, 250], [300, 600]] - } + sizes: [ + [300, 250], + [300, 600], + ], + }, }, bidId: '30b31c1838de1e', bidderRequestId: '22edbae2733bf6', auctionId: '1d1a030790a475', crumbs: { - pubcid: 'c604130c-0144-4b63-9bf2-c2bd8c8d86da' + pubcid: 'c604130c-0144-4b63-9bf2-c2bd8c8d86da', }, userId: { tdid, - } + }, }; let bidArray = [bid]; let bidderRequest = { - 'bidderCode': 'yieldmo', - 'auctionId': 'e3a336ad-2761-4a1c-b421-ecc7c5294a34', - 'bidderRequestId': '14c4ede8c693f', - 'bids': bidArray, - 'auctionStart': 1520001292880, - 'timeout': 3000, - 'start': 1520001292884, - 'doneCbCallCount': 0, - 'refererInfo': { - 'numIframes': 1, - 'reachedTop': true, - 'referer': 'yieldmo.com' - } - } + bidderCode: 'yieldmo', + auctionId: 'e3a336ad-2761-4a1c-b421-ecc7c5294a34', + bidderRequestId: '14c4ede8c693f', + bids: bidArray, + auctionStart: 1520001292880, + timeout: 3000, + start: 1520001292884, + doneCbCallCount: 0, + refererInfo: { + numIframes: 1, + reachedTop: true, + referer: 'yieldmo.com', + }, + }; describe('isBidRequestValid', function () { it('should return true when necessary information is found', function () { @@ -77,38 +81,44 @@ describe('YieldmoAdapter', function () { }); it('should not blow up if crumbs is undefined', function () { - let bidArray = [ - { ...bid, crumbs: undefined } - ] - expect(function () { spec.buildRequests(bidArray, bidderRequest) }).not.to.throw() - }) + let bidArray = [{ ...bid, crumbs: undefined }]; + expect(function () { + spec.buildRequests(bidArray, bidderRequest); + }).not.to.throw(); + }); it('should place bid information into the p parameter of data', function () { let placementInfo = spec.buildRequests(bidArray, bidderRequest).data.p; - expect(placementInfo).to.equal('[{"placement_id":"adunit-code","callback_id":"30b31c1838de1e","sizes":[[300,250],[300,600]],"bidFloor":0.1}]'); + expect(placementInfo).to.equal( + '[{"placement_id":"adunit-code","callback_id":"30b31c1838de1e","sizes":[[300,250],[300,600]],"bidFloor":0.1}]' + ); bidArray.push({ bidder: 'yieldmo', params: { - bidFloor: 0.2 + bidFloor: 0.2, }, adUnitCode: 'adunit-code-1', mediaTypes: { banner: { - sizes: [[300, 250], [300, 600]] - } + sizes: [ + [300, 250], + [300, 600], + ], + }, }, bidId: '123456789', bidderRequestId: '987654321', auctionId: '0246810', crumbs: { - pubcid: 'c604130c-0144-4b63-9bf2-c2bd8c8d86da' - } - + pubcid: 'c604130c-0144-4b63-9bf2-c2bd8c8d86da', + }, }); // multiple placements placementInfo = spec.buildRequests(bidArray, bidderRequest).data.p; - expect(placementInfo).to.equal('[{"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}]'); + expect(placementInfo).to.equal( + '[{"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 () { @@ -145,18 +155,23 @@ describe('YieldmoAdapter', function () { adUnitCode: 'adunit-code', mediaTypes: { banner: { - sizes: [[300, 250], [300, 600]] - } + sizes: [ + [300, 250], + [300, 600], + ], + }, }, bidId: '30b31c1838de1e', bidderRequestId: '22edbae2733bf6', auctionId: '1d1a030790a475', userId: { - pubcid: 'c604130c-0144-4b63-9bf2-c2bd8c8d86da2' - } + pubcid: 'c604130c-0144-4b63-9bf2-c2bd8c8d86da2', + }, }; const data = spec.buildRequests([pubcidBid], bidderRequest).data; - expect(data.pubcid).to.deep.equal('c604130c-0144-4b63-9bf2-c2bd8c8d86da2'); + expect(data.pubcid).to.deep.equal( + 'c604130c-0144-4b63-9bf2-c2bd8c8d86da2' + ); }); it('should add unified id as parameter of request', function () { @@ -166,46 +181,79 @@ describe('YieldmoAdapter', function () { adUnitCode: 'adunit-code', mediaTypes: { banner: { - sizes: [[300, 250], [300, 600]] - } + sizes: [ + [300, 250], + [300, 600], + ], + }, }, bidId: '30b31c1838de1e', bidderRequestId: '22edbae2733bf6', auctionId: '1d1a030790a475', userId: { tdid, - } + }, }; const data = spec.buildRequests([unifiedIdBid], bidderRequest).data; expect(data.tdid).to.deep.equal(tdid); }); + it('should add CRITEO RTUS id as parameter of request', function () { + const criteoIdBid = { + bidder: 'yieldmo', + params: {}, + adUnitCode: 'adunit-code', + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [300, 600], + ], + }, + }, + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + userId: { + criteoId, + }, + }; + const data = spec.buildRequests([criteoIdBid], bidderRequest).data; + expect(data.cri_prebid).to.deep.equal(criteoId); + }); + it('should add gdpr information to request if available', () => { bidderRequest.gdprConsent = { - 'consentString': 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', - 'vendorData': {'blerp': 1}, - 'gdprApplies': true - } + consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + vendorData: { blerp: 1 }, + gdprApplies: true, + }; const data = spec.buildRequests(bidArray, bidderRequest).data; - expect(data.userConsent).equal(JSON.stringify({ - 'gdprApplies': true, - 'cmp': 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==' - })); + expect(data.userConsent).equal( + JSON.stringify({ + gdprApplies: true, + cmp: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==', + }) + ); }); it('should add ccpa information to request if available', () => { const privacy = '1YNY'; - bidderRequest.us_privacy = privacy; + bidderRequest.uspConsent = privacy; const data = spec.buildRequests(bidArray, bidderRequest).data; expect(data.us_privacy).equal(privacy); }); it('should add schain if it is in the bidRequest', () => { - const schain = {'ver': '1.0', 'complete': 1, 'nodes': [{'asi': 'indirectseller.com', 'sid': '00001', 'hp': 1}]}; + const schain = { + ver: '1.0', + complete: 1, + nodes: [{ asi: 'indirectseller.com', sid: '00001', hp: 1 }], + }; bidArray[0].schain = schain; const request = spec.buildRequests([bidArray[0]], bidderRequest); expect(request.data.schain).equal(JSON.stringify(schain)); - }) + }); }); describe('interpretResponse', function () { @@ -213,17 +261,20 @@ describe('YieldmoAdapter', function () { beforeEach(function () { serverResponse = { - body: [{ - callback_id: '21989fdbef550a', - cpm: 3.45455, - width: 300, - height: 250, - ad: '
', - creative_id: '9874652394875' - }], - header: 'header?' + body: [ + { + callback_id: '21989fdbef550a', + cpm: 3.45455, + width: 300, + height: 250, + ad: + '
', + creative_id: '9874652394875', + }, + ], + header: 'header?', }; - }) + }); it('should correctly reorder the server response', function () { const newResponse = spec.interpretResponse(serverResponse); @@ -237,7 +288,8 @@ describe('YieldmoAdapter', function () { currency: 'USD', netRevenue: true, ttl: 300, - ad: '
' + ad: + '
', }); }); @@ -248,30 +300,13 @@ describe('YieldmoAdapter', function () { serverResponse.body[0].cpm = null; response = spec.interpretResponse(serverResponse); - expect(response).to.deep.equal([]) + expect(response).to.deep.equal([]); }); }); describe('getUserSync', function () { - const SYNC_ENDPOINT = 'https://static.yieldmo.com/blank.min.html?orig='; - let options = { - iframeEnabled: true, - pixelEnabled: true - }; - it('should return a tracker with type and url as parameters', function () { - if (/iPhone|iPad|iPod/i.test(window.navigator.userAgent)) { - expect(spec.getUserSync(options)).to.deep.equal([{ - type: 'iframe', - url: SYNC_ENDPOINT + utils.getOrigin() - }]); - - options.iframeEnabled = false; - expect(spec.getUserSync(options)).to.deep.equal([]); - } else { - // not ios, so tracker will fail - expect(spec.getUserSync(options)).to.deep.equal([]); - } + expect(spec.getUserSyncs()).to.deep.equal([]); }); }); }); diff --git a/test/spec/modules/yieldoneAnalyticsAdapter_spec.js b/test/spec/modules/yieldoneAnalyticsAdapter_spec.js index eb79fc55806..81a6365bba2 100644 --- a/test/spec/modules/yieldoneAnalyticsAdapter_spec.js +++ b/test/spec/modules/yieldoneAnalyticsAdapter_spec.js @@ -1,5 +1,5 @@ -import yieldoneAnalytics from 'modules/yieldoneAnalyticsAdapter'; -import { targeting } from 'src/targeting'; +import yieldoneAnalytics from 'modules/yieldoneAnalyticsAdapter.js'; +import { targeting } from 'src/targeting.js'; import { expect } from 'chai'; let events = require('src/events'); let adapterManager = require('src/adapterManager').default; @@ -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/yieldoneBidAdapter_spec.js b/test/spec/modules/yieldoneBidAdapter_spec.js index 78b6122aff5..84065682297 100644 --- a/test/spec/modules/yieldoneBidAdapter_spec.js +++ b/test/spec/modules/yieldoneBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/yieldoneBidAdapter'; -import { newBidder } from 'src/adapters/bidderFactory'; +import { spec } from 'modules/yieldoneBidAdapter.js'; +import { newBidder } from 'src/adapters/bidderFactory.js'; const ENDPOINT = 'https://y.one.impact-ad.jp/h_bid'; const USER_SYNC_URL = 'https://y.one.impact-ad.jp/push_sync'; diff --git a/test/spec/modules/yuktamediaAnalyticsAdaptor_spec.js b/test/spec/modules/yuktamediaAnalyticsAdaptor_spec.js index 74d37226e61..24a524c85c7 100644 --- a/test/spec/modules/yuktamediaAnalyticsAdaptor_spec.js +++ b/test/spec/modules/yuktamediaAnalyticsAdaptor_spec.js @@ -1,8 +1,8 @@ -import yuktamediaAnalyticsAdapter from 'modules/yuktamediaAnalyticsAdapter'; +import yuktamediaAnalyticsAdapter from 'modules/yuktamediaAnalyticsAdapter.js'; import { expect } from 'chai'; import adapterManager from 'src/adapterManager.js'; -import * as utils from 'src/utils'; -import { server } from 'test/mocks/xhr'; +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'); 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/native_spec.js b/test/spec/native_spec.js index 2fb2fd810fa..bd56ba53e4a 100644 --- a/test/spec/native_spec.js +++ b/test/spec/native_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { fireNativeTrackers, getNativeTargeting, nativeBidIsValid, getAssetMessage } from 'src/native'; +import { fireNativeTrackers, getNativeTargeting, nativeBidIsValid, getAssetMessage } from 'src/native.js'; import CONSTANTS from 'src/constants.json'; const utils = require('src/utils'); diff --git a/test/spec/refererDetection_spec.js b/test/spec/refererDetection_spec.js index b2ef4e2058f..90892d915fe 100644 --- a/test/spec/refererDetection_spec.js +++ b/test/spec/refererDetection_spec.js @@ -1,4 +1,4 @@ -import { detectReferer } from 'src/refererDetection'; +import { detectReferer } from 'src/refererDetection.js'; import { expect } from 'chai'; var mocks = { diff --git a/test/spec/renderer_spec.js b/test/spec/renderer_spec.js index da10c67f223..77d806e4dbc 100644 --- a/test/spec/renderer_spec.js +++ b/test/spec/renderer_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; -import { Renderer } from 'src/Renderer'; -import * as utils from 'src/utils'; -import { loadExternalScript } from 'src/adloader'; +import { Renderer } from 'src/Renderer.js'; +import * as utils from 'src/utils.js'; +import { loadExternalScript } from 'src/adloader.js'; describe('Renderer', function () { describe('Renderer: A renderer installed on a bid response', function () { @@ -126,10 +126,13 @@ 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 call loadExternalScript() for script not defined on adUnit, only when .render() is called', function() { $$PREBID_GLOBAL$$.adUnits = [{ code: 'video1', renderer: { @@ -143,6 +146,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/sizeMapping_spec.js b/test/spec/sizeMapping_spec.js index 254dcb8003e..78dd9797c36 100644 --- a/test/spec/sizeMapping_spec.js +++ b/test/spec/sizeMapping_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { resolveStatus, setSizeConfig, sizeSupported } from 'src/sizeMapping'; -import includes from 'core-js/library/fn/array/includes'; +import { resolveStatus, setSizeConfig, sizeSupported } from 'src/sizeMapping.js'; +import includes from 'core-js-pure/features/array/includes.js'; let utils = require('src/utils'); let deepClone = utils.deepClone; diff --git a/test/spec/unit/adServerManager_spec.js b/test/spec/unit/adServerManager_spec.js index 4ae475ac013..ec58ff7f5b3 100644 --- a/test/spec/unit/adServerManager_spec.js +++ b/test/spec/unit/adServerManager_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { getGlobal } from 'src/prebidGlobal'; -import { registerVideoSupport } from 'src/adServerManager'; +import { getGlobal } from 'src/prebidGlobal.js'; +import { registerVideoSupport } from 'src/adServerManager.js'; const prebid = getGlobal(); diff --git a/test/spec/unit/adUnits_spec.js b/test/spec/unit/adUnits_spec.js index fb666feb9b8..a8443d36522 100644 --- a/test/spec/unit/adUnits_spec.js +++ b/test/spec/unit/adUnits_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { adunitCounter } from 'src/adUnits'; +import { adunitCounter } from 'src/adUnits.js'; describe('Adunit Counter', function () { const ADUNIT_ID_1 = 'test1'; diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js index bd8f880378b..9ccdd6aef59 100644 --- a/test/spec/unit/core/adapterManager_spec.js +++ b/test/spec/unit/core/adapterManager_spec.js @@ -1,19 +1,19 @@ import { expect } from 'chai'; -import adapterManager, { gdprDataHandler } from 'src/adapterManager'; +import adapterManager, { gdprDataHandler } from 'src/adapterManager.js'; import { getAdUnits, getServerTestingConfig, getServerTestingsAds, getBidRequests -} from 'test/fixtures/fixtures'; +} from 'test/fixtures/fixtures.js'; import CONSTANTS from 'src/constants.json'; -import * as utils from 'src/utils'; -import { config } from 'src/config'; -import { registerBidder } from 'src/adapters/bidderFactory'; -import { setSizeConfig } from 'src/sizeMapping'; -import find from 'core-js/library/fn/array/find'; -import includes from 'core-js/library/fn/array/includes'; -import s2sTesting from 'modules/s2sTesting'; +import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; +import { registerBidder } from 'src/adapters/bidderFactory.js'; +import { setSizeConfig } from 'src/sizeMapping.js'; +import find from 'core-js-pure/features/array/find.js'; +import includes from 'core-js-pure/features/array/includes.js'; +import s2sTesting from 'modules/s2sTesting.js'; var events = require('../../../../src/events'); const CONFIG = { @@ -43,16 +43,23 @@ var rubiconAdapterMock = { callBids: sinon.stub() }; +var badAdapterMock = { + bidder: 'badBidder', + callBids: sinon.stub().throws(Error('some fake error')) +}; + describe('adapterManager tests', function () { let orgAppnexusAdapter; let orgAdequantAdapter; let orgPrebidServerAdapter; let orgRubiconAdapter; + let orgBadBidderAdapter; before(function () { orgAppnexusAdapter = adapterManager.bidderRegistry['appnexus']; orgAdequantAdapter = adapterManager.bidderRegistry['adequant']; orgPrebidServerAdapter = adapterManager.bidderRegistry['prebidServer']; orgRubiconAdapter = adapterManager.bidderRegistry['rubicon']; + orgBadBidderAdapter = adapterManager.bidderRegistry['badBidder']; }); after(function () { @@ -60,6 +67,7 @@ describe('adapterManager tests', function () { adapterManager.bidderRegistry['adequant'] = orgAdequantAdapter; adapterManager.bidderRegistry['prebidServer'] = orgPrebidServerAdapter; adapterManager.bidderRegistry['rubicon'] = orgRubiconAdapter; + adapterManager.bidderRegistry['badBidder'] = orgBadBidderAdapter; config.setConfig({s2sConfig: { enabled: false }}); }); @@ -72,11 +80,16 @@ describe('adapterManager tests', function () { sinon.stub(utils, 'logError'); appnexusAdapterMock.callBids.reset(); adapterManager.bidderRegistry['appnexus'] = appnexusAdapterMock; + adapterManager.bidderRegistry['rubicon'] = rubiconAdapterMock; + adapterManager.bidderRegistry['badBidder'] = badAdapterMock; }); afterEach(function () { utils.logError.restore(); delete adapterManager.bidderRegistry['appnexus']; + delete adapterManager.bidderRegistry['rubicon']; + delete adapterManager.bidderRegistry['badBidder']; + config.resetConfig(); }); it('should log an error if a bidder is used that does not exist', function () { @@ -95,6 +108,34 @@ describe('adapterManager tests', function () { sinon.assert.called(utils.logError); }); + it('should catch a bidder adapter thrown error and continue with other bidders', function () { + const adUnits = [{ + code: 'adUnit-code', + sizes: [[728, 90]], + bids: [ + {bidder: 'appnexus', params: {placementId: 'id'}}, + {bidder: 'badBidder', params: {placementId: 'id'}}, + {bidder: 'rubicon', params: {account: 1111, site: 2222, zone: 3333}} + ] + }]; + let bidRequests = adapterManager.makeBidRequests(adUnits, 1111, 2222, 1000); + + let doneBidders = []; + function mockDoneCB() { + doneBidders.push(this.bidderCode) + } + adapterManager.callBids(adUnits, bidRequests, () => {}, mockDoneCB); + sinon.assert.calledOnce(appnexusAdapterMock.callBids); + sinon.assert.calledOnce(badAdapterMock.callBids); + sinon.assert.calledOnce(rubiconAdapterMock.callBids); + + expect(utils.logError.calledOnce).to.be.true; + expect(utils.logError.calledWith( + 'badBidder Bid Adapter emitted an uncaught error when parsing their bidRequest' + )).to.be.true; + // done should be called for our bidder! + expect(doneBidders.indexOf('badBidder') === -1).to.be.false; + }); it('should emit BID_REQUESTED event', function () { // function to count BID_REQUESTED events let cnt = 0; @@ -175,7 +216,7 @@ describe('adapterManager tests', function () { buildRequests: { data: 1 }, - test1: { speedy: true }, + test1: { speedy: true, fun: { test: true } }, interpretResponse: 'baseInterpret', afterInterpretResponse: 'anotherBaseInterpret' }); @@ -212,7 +253,7 @@ describe('adapterManager tests', function () { data: 1, test: 2 }, - { fun: { safe: true, cheap: false }, speedy: true }, + { fun: { safe: true, cheap: false, test: true }, speedy: true }, { amazing: true }, 'appnexusInterpret', 'anotherBaseInterpret' @@ -221,14 +262,14 @@ describe('adapterManager tests', function () { { data: 1 }, - { speedy: true }, + { fun: { test: true }, speedy: true }, undefined, 'baseInterpret', 'anotherBaseInterpret' ], 'rubicon': [ 'rubiconBuild', - { speedy: true }, + { fun: { test: true }, speedy: true }, { amazing: true }, null, 'anotherBaseInterpret' diff --git a/test/spec/unit/core/bidderFactory_spec.js b/test/spec/unit/core/bidderFactory_spec.js index e1b2f205bf7..cab0655a29d 100644 --- a/test/spec/unit/core/bidderFactory_spec.js +++ b/test/spec/unit/core/bidderFactory_spec.js @@ -1,11 +1,11 @@ -import { newBidder, registerBidder, preloadBidderMappingFile } from 'src/adapters/bidderFactory'; -import adapterManager from 'src/adapterManager'; -import * as ajax from 'src/ajax'; +import { newBidder, registerBidder, preloadBidderMappingFile, storage } from 'src/adapters/bidderFactory.js'; +import adapterManager from 'src/adapterManager.js'; +import * as ajax from 'src/ajax.js'; import { expect } from 'chai'; -import { userSync } from 'src/userSync' -import * as utils from 'src/utils'; -import { config } from 'src/config'; -import { server } from 'test/mocks/xhr'; +import { userSync } from 'src/userSync.js' +import * as utils from 'src/utils.js'; +import { config } from 'src/config.js'; +import { server } from 'test/mocks/xhr.js'; const CODE = 'sampleBidder'; const MOCK_BIDS_REQUEST = { @@ -56,15 +56,66 @@ describe('bidders created by newBidder', function () { describe('when the ajax response is irrelevant', function () { let ajaxStub; + let getConfigSpy; beforeEach(function () { ajaxStub = sinon.stub(ajax, 'ajax'); addBidResponseStub.reset(); + getConfigSpy = sinon.spy(config, 'getConfig'); doneStub.reset(); }); afterEach(function () { ajaxStub.restore(); + getConfigSpy.restore(); + }); + + it('should let registerSyncs run with invalid alias and aliasSync enabled', function () { + config.setConfig({ + userSync: { + aliasSyncEnabled: true + } + }); + spec.code = 'fakeBidder'; + const bidder = newBidder(spec); + bidder.callBids({ bids: [] }, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); + expect(getConfigSpy.withArgs('userSync.filterSettings').calledOnce).to.equal(true); + }); + + it('should let registerSyncs run with valid alias and aliasSync enabled', function () { + config.setConfig({ + userSync: { + aliasSyncEnabled: true + } + }); + spec.code = 'aliasBidder'; + const bidder = newBidder(spec); + bidder.callBids({ bids: [] }, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); + expect(getConfigSpy.withArgs('userSync.filterSettings').calledOnce).to.equal(true); + }); + + it('should let registerSyncs run with invalid alias and aliasSync disabled', function () { + config.setConfig({ + userSync: { + aliasSyncEnabled: false + } + }); + spec.code = 'fakeBidder'; + const bidder = newBidder(spec); + bidder.callBids({ bids: [] }, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); + expect(getConfigSpy.withArgs('userSync.filterSettings').calledOnce).to.equal(true); + }); + + it('should not let registerSyncs run with valid alias and aliasSync disabled', function () { + config.setConfig({ + userSync: { + aliasSyncEnabled: false + } + }); + spec.code = 'aliasBidder'; + const bidder = newBidder(spec); + bidder.callBids({ bids: [] }, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); + expect(getConfigSpy.withArgs('userSync.filterSettings').calledOnce).to.equal(false); }); it('should handle bad bid requests gracefully', function () { @@ -196,7 +247,7 @@ describe('bidders created by newBidder', function () { bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); expect(ajaxStub.calledOnce).to.equal(true); - expect(ajaxStub.firstCall.args[0]).to.equal(`${url}?arg=2&`); + expect(ajaxStub.firstCall.args[0]).to.equal(`${url}?arg=2`); expect(ajaxStub.firstCall.args[2]).to.be.undefined; expect(ajaxStub.firstCall.args[3]).to.deep.equal({ method: 'GET', @@ -220,7 +271,7 @@ describe('bidders created by newBidder', function () { bidder.callBids(MOCK_BIDS_REQUEST, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback); expect(ajaxStub.calledOnce).to.equal(true); - expect(ajaxStub.firstCall.args[0]).to.equal(`${url}?arg=2&`); + expect(ajaxStub.firstCall.args[0]).to.equal(`${url}?arg=2`); expect(ajaxStub.firstCall.args[2]).to.be.undefined; expect(ajaxStub.firstCall.args[3]).to.deep.equal({ method: 'GET', @@ -790,42 +841,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(utils, 'getDataFromLocalStorage'); + 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 { @@ -839,16 +880,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: { @@ -872,19 +918,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 { @@ -909,4 +942,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 new file mode 100644 index 00000000000..0b406242f90 --- /dev/null +++ b/test/spec/unit/core/storageManager_spec.js @@ -0,0 +1,46 @@ +import { resetData, getCoreStorageManager, storageCallbacks, getStorageManager } from 'src/storageManager.js'; +import { config } from 'src/config.js'; +import * as utils from 'src/utils.js'; + +describe('storage manager', function() { + beforeEach(function() { + resetData(); + }); + + afterEach(function() { + config.resetConfig(); + }) + + it('should allow to set cookie for core modules without checking gdpr enforcements', function() { + const coreStorage = getCoreStorageManager(); + let date = new Date(); + date.setTime(date.getTime() + (24 * 60 * 60 * 1000)); + let expires = date.toUTCString(); + coreStorage.setCookie('hello', 'world', expires); + expect(coreStorage.getCookie('hello')).to.equal('world'); + }); + + it('should add done callbacks to storageCallbacks array', function() { + let noop = sinon.spy(); + const coreStorage = getStorageManager(); + + coreStorage.setCookie('foo', 'bar', null, null, null, noop); + coreStorage.getCookie('foo', noop); + coreStorage.localStorageIsEnabled(noop); + coreStorage.cookiesAreEnabled(noop); + coreStorage.setDataInLocalStorage('foo', 'bar', noop); + coreStorage.getDataFromLocalStorage('foo', noop); + coreStorage.removeDataFromLocalStorage('foo', noop); + coreStorage.hasLocalStorage(noop); + + expect(storageCallbacks.length).to.equal(8); + }); + + it('should allow bidder to access device if gdpr enforcement module is not included', function() { + let deviceAccessSpy = sinon.spy(utils, 'hasDeviceAccess'); + const storage = getStorageManager(); + storage.setCookie('foo1', 'baz1'); + expect(deviceAccessSpy.calledOnce).to.equal(true); + deviceAccessSpy.restore(); + }) +}); diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js index ad94ebccfb2..a5da1c904f0 100644 --- a/test/spec/unit/core/targeting_spec.js +++ b/test/spec/unit/core/targeting_spec.js @@ -1,10 +1,10 @@ import { expect } from 'chai'; -import { targeting as targetingInstance, filters, sortByDealAndPriceBucket } from 'src/targeting'; -import { config } from 'src/config'; -import { getAdUnits, createBidReceived } from 'test/fixtures/fixtures'; +import { targeting as targetingInstance, filters, 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'; -import { auctionManager } from 'src/auctionManager'; -import * as utils from 'src/utils'; +import { auctionManager } from 'src/auctionManager.js'; +import * as utils from 'src/utils.js'; const bid1 = { 'bidderCode': 'rubicon', @@ -687,7 +687,7 @@ describe('targeting tests', function () { }); }); - describe('sortByDealAndPriceBucket', function() { + describe('sortByDealAndPriceBucketOrCpm', function() { it('will properly sort bids when some bids have deals and some do not', function () { let bids = [{ adUnitTargeting: { @@ -723,7 +723,7 @@ describe('targeting tests', function () { hb_pb: '100.00', } }]; - bids.sort(sortByDealAndPriceBucket); + 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'); @@ -758,7 +758,7 @@ describe('targeting tests', function () { hb_deal: '9864' } }]; - bids.sort(sortByDealAndPriceBucket); + 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'); @@ -797,7 +797,7 @@ describe('targeting tests', function () { hb_pb: '100.00' } }]; - bids.sort(sortByDealAndPriceBucket); + 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'); @@ -805,6 +805,57 @@ describe('targeting tests', function () { expect(bids[4].adUnitTargeting.hb_adid).to.equal('mno'); expect(bids[5].adUnitTargeting.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: { + hb_adid: 'abc', + hb_pb: '1.00', + hb_deal: '1234' + } + }, { + cpm: 0.50, + adUnitTargeting: { + hb_adid: 'def', + hb_pb: '0.50', + hb_deal: '4532' + } + }, { + cpm: 0.53, + adUnitTargeting: { + hb_adid: 'ghi', + hb_pb: '0.50', + hb_deal: '4532' + } + }, { + cpm: 9.04, + adUnitTargeting: { + hb_adid: 'jkl', + hb_pb: '9.00', + hb_deal: '9864' + } + }, { + cpm: 50.00, + adUnitTargeting: { + hb_adid: 'mno', + hb_pb: '50.00', + } + }, { + cpm: 100.00, + adUnitTargeting: { + 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'); + }); }); describe('setTargetingForAst', function () { diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 6d98830ac42..8a142d7a6aa 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -7,27 +7,22 @@ import { getTargetingKeysBidLandscape, getAdUnits, createBidReceived -} from 'test/fixtures/fixtures'; -import { auctionManager, newAuctionManager } from 'src/auctionManager'; -import { targeting, newTargeting, filters } from 'src/targeting'; -import { config as configObj } from 'src/config'; -import * as ajaxLib from 'src/ajax'; -import * as auctionModule from 'src/auction'; -import { newBidder, registerBidder } from 'src/adapters/bidderFactory'; -import find from 'core-js/library/fn/array/find'; +} from 'test/fixtures/fixtures.js'; +import { auctionManager, newAuctionManager } from 'src/auctionManager.js'; +import { targeting, newTargeting, filters } from 'src/targeting.js'; +import { config as configObj } from 'src/config.js'; +import * as ajaxLib from 'src/ajax.js'; +import * as auctionModule from 'src/auction.js'; +import { registerBidder } from 'src/adapters/bidderFactory.js'; +import { _sendAdToCreative } from 'src/secureCreatives.js'; +import find from 'core-js-pure/features/array/find.js'; var assert = require('chai').assert; var expect = require('chai').expect; -var urlParse = require('url-parse'); - -var prebid = require('src/prebid'); var utils = require('src/utils'); -var bidfactory = require('src/bidfactory'); -var adloader = require('test/mocks/adloaderStub'); var adapterManager = require('src/adapterManager').default; var events = require('src/events'); -var adserver = require('src/adserver'); var CONSTANTS = require('src/constants.json'); // These bid adapters are required to be loaded for the following tests to work @@ -56,7 +51,7 @@ function resetAuction() { var Slot = function Slot(elementId, pathId) { var slot = { - targeting: [], + targeting: {}, getSlotElementId: function getSlotElementId() { return elementId; }, @@ -66,24 +61,24 @@ var Slot = function Slot(elementId, pathId) { }, setTargeting: function setTargeting(key, value) { - var obj = []; - obj[key] = value; - this.targeting.push(obj); + this.targeting[key] = Array.isArray(value) ? value : [value]; }, - getTargeting: function getTargeting() { - return this.targeting; + getTargeting: function getTargeting(key) { + return this.targeting[key] || []; }, getTargetingKeys: function getTargetingKeys() { - return []; + return Object.getOwnPropertyNames(this.targeting); }, clearTargeting: function clearTargeting() { - return googletag.pubads().getSlots(); + this.targeting = {}; + return this; } }; slot.spySetTargeting = sinon.spy(slot, 'setTargeting'); + slot.spyGetSlotElementId = sinon.spy(slot, 'getSlotElementId'); return slot; }; @@ -121,11 +116,15 @@ window.googletag = { }, setTargeting: function(key, arrayOfValues) { - self._targeting[key] = arrayOfValues; + self._targeting[key] = Array.isArray(arrayOfValues) ? arrayOfValues : [arrayOfValues]; + }, + + getTargeting: function(key) { + return self._targeting[key] || []; }, - getTargeting: function() { - return self._targeting; + getTargetingKeys: function() { + return Object.getOwnPropertyNames(self._targeting); }, clearTargeting: function() { @@ -856,17 +855,30 @@ describe('Unit: Prebid Module', function () { it('should set googletag targeting keys after calling setTargetingForGPTAsync function', function () { var slots = createSlotArrayScenario2(); window.googletag.pubads().setSlots(slots); - $$PREBID_GLOBAL$$.setTargetingForGPTAsync(); + $$PREBID_GLOBAL$$.setTargetingForGPTAsync([config.adUnitCodes[0]]); - var targeting = []; - slots[1].getTargeting().map(function (value) { - var temp = []; - temp.push(Object.keys(value).toString()); - temp.push(value[Object.keys(value)]); - targeting.push(temp); + // we need to transform the spySetTargeting into something that looks like + // googletag's targeting structure + // googletag setTargeting will override old value if invoked with same key + + const targeting = []; + slots[1].getTargetingKeys().map(function (key) { + const value = slots[1].getTargeting(key); + targeting.push([key, value]); + }); + + var invokedTargetingMap = {}; + slots[1].spySetTargeting.args.map(function (entry) { + invokedTargetingMap[entry[0]] = entry[1]; }); - assert.deepEqual(slots[1].spySetTargeting.args, targeting, 'google tag targeting options not matching'); + var invokedTargeting = []; + + Object.getOwnPropertyNames(invokedTargetingMap).map(function (key) { + const value = Array.isArray(invokedTargetingMap[key]) ? invokedTargetingMap[key] : [invokedTargetingMap[key]]; // values are always returned as array in googletag + invokedTargeting.push([key, value]); + }); + assert.deepEqual(targeting, invokedTargeting, 'google tag targeting options not matching'); }); it('should set googletag targeting keys to specific slot with customSlotMatching', function () { @@ -925,6 +937,40 @@ describe('Unit: Prebid Module', function () { expect(slots[0].spySetTargeting.args).to.deep.contain.members(expected); }); + it('should find correct gpt slot based on ad id rather than ad unit code when resizing secure creative', function () { + var slots = [ + new Slot('div-not-matching-adunit-code-1', config.adUnitCodes[0]), + new Slot('div-not-matching-adunit-code-2', config.adUnitCodes[0]), + new Slot('div-not-matching-adunit-code-3', config.adUnitCodes[0]) + ]; + + slots[1].setTargeting('hb_adid', ['someAdId']); + slots[1].spyGetSlotElementId.resetHistory(); + window.googletag.pubads().setSlots(slots); + + const mockAdObject = { + adId: 'someAdId', + ad: '', + adUrl: 'http://creative.prebid.org/${AUCTION_PRICE}', + width: 300, + height: 250, + renderer: null, + cpm: '1.00', + adUnitCode: config.adUnitCodes[0], + }; + + const event = { + source: { postMessage: sinon.stub() }, + origin: 'origin.sf.com' + }; + + _sendAdToCreative(mockAdObject, event); + + expect(slots[0].spyGetSlotElementId.called).to.equal(false); + expect(slots[1].spyGetSlotElementId.called).to.equal(true); + expect(slots[2].spyGetSlotElementId.called).to.equal(false); + }); + it('Calling enableSendAllBids should set targeting to include standard keys with bidder' + ' append to key name', function () { var slots = createSlotArray(); @@ -1171,6 +1217,12 @@ describe('Unit: Prebid Module', function () { let makeRequestsStub; let adUnits; let clock; + before(function () { + clock = sinon.useFakeTimers(); + }); + after(function () { + clock.restore(); + }); let bidsBackHandlerStub = sinon.stub(); const BIDDER_CODE = 'sampleBidder'; @@ -1257,7 +1309,6 @@ describe('Unit: Prebid Module', function () { spec.isBidRequestValid.returns(true); spec.interpretResponse.returns(bids); - clock = sinon.useFakeTimers(); let requestObj = { bidsBackHandler: null, // does not need to be defined because of newAuction mock in beforeEach timeout: 2000, @@ -1311,7 +1362,6 @@ describe('Unit: Prebid Module', function () { auction.getBidsReceived = function() { return [adResponse]; } auction.getAuctionId = () => auctionId; - clock = sinon.useFakeTimers(); let requestObj = { bidsBackHandler: null, // does not need to be defined because of newAuction mock in beforeEach timeout: 2000, @@ -1404,7 +1454,7 @@ describe('Unit: Prebid Module', function () { try { $$PREBID_GLOBAL$$.requestBids({}); } catch (e) { - console.log(e); + console.log(e); // eslint-disable-line } assert.ok(logMessageSpy.calledWith('No adUnits configured. No bids requested.'), 'expected message was logged'); }); diff --git a/test/spec/unit/secureCreatives_spec.js b/test/spec/unit/secureCreatives_spec.js index f0f26bf5653..566154f0003 100644 --- a/test/spec/unit/secureCreatives_spec.js +++ b/test/spec/unit/secureCreatives_spec.js @@ -1,8 +1,8 @@ import { _sendAdToCreative -} from '../../../src/secureCreatives'; +} from '../../../src/secureCreatives.js'; import { expect } from 'chai'; -import * as utils from 'src/utils'; +import * as utils from 'src/utils.js'; describe('secureCreatives', () => { describe('_sendAdToCreative', () => { @@ -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/url_spec.js b/test/spec/url_spec.js deleted file mode 100644 index 90047273043..00000000000 --- a/test/spec/url_spec.js +++ /dev/null @@ -1,94 +0,0 @@ -import {format, parse} from '../../src/url'; -import { expect } from 'chai'; - -describe('helpers.url', function () { - describe('parse()', function () { - let parsed; - - beforeEach(function () { - parsed = parse('http://example.com:3000/pathname/?search=test&foo=bar&bar=foo%26foo%3Dxxx#hash'); - }); - - it('extracts the protocol', function () { - expect(parsed).to.have.property('protocol', 'http'); - }); - - it('extracts the hostname', function () { - expect(parsed).to.have.property('hostname', 'example.com'); - }); - - it('extracts the port', function () { - expect(parsed).to.have.property('port', 3000); - }); - - it('extracts the pathname', function () { - expect(parsed).to.have.property('pathname', '/pathname/'); - }); - - it('extracts the search query', function () { - expect(parsed).to.have.property('search'); - expect(parsed.search).to.eql({ - foo: 'xxx', - search: 'test', - bar: 'foo', - }); - }); - - it('extracts the hash', function () { - expect(parsed).to.have.property('hash', 'hash'); - }); - - it('extracts the host', function () { - expect(parsed).to.have.property('host', 'example.com:3000'); - }); - }); - - describe('parse(url, {noDecodeWholeURL: true})', function () { - let parsed; - - beforeEach(function () { - parsed = parse('http://example.com:3000/pathname/?search=test&foo=bar&bar=foo%26foo%3Dxxx#hash', {noDecodeWholeURL: true}); - }); - - it('extracts the search query', function () { - expect(parsed).to.have.property('search'); - expect(parsed.search).to.eql({ - foo: 'bar', - search: 'test', - bar: 'foo%26foo%3Dxxx', - }); - }); - }); - - describe('format()', function () { - it('formats an object in to a URL', function () { - expect(format({ - protocol: 'http', - hostname: 'example.com', - port: 3000, - pathname: '/pathname/', - search: {foo: 'bar', search: 'test', bar: 'foo%26foo%3Dxxx'}, - hash: 'hash' - })).to.equal('http://example.com:3000/pathname/?foo=bar&search=test&bar=foo%26foo%3Dxxx#hash'); - }); - - it('will use defaults for missing properties', function () { - expect(format({ - hostname: 'example.com' - })).to.equal('http://example.com'); - }); - }); - - describe('parse(url, {decodeSearchAsString: true})', function () { - let parsed; - - beforeEach(function () { - parsed = parse('http://example.com:3000/pathname/?search=test&foo=bar&bar=foo%26foo%3Dxxx#hash', {decodeSearchAsString: true}); - }); - - it('extracts the search query', function () { - expect(parsed).to.have.property('search'); - expect(parsed.search).to.equal('?search=test&foo=bar&bar=foo&foo=xxx'); - }); - }); -}); diff --git a/test/spec/userSync_spec.js b/test/spec/userSync_spec.js index 806e86e998b..2b68349ca31 100644 --- a/test/spec/userSync_spec.js +++ b/test/spec/userSync_spec.js @@ -1,8 +1,8 @@ import { expect } from 'chai'; -import { config } from 'src/config'; +import { config } from 'src/config.js'; // Use require since we need to be able to write to these vars const utils = require('../../src/utils'); -let { newUserSync } = require('../../src/userSync'); +let { newUserSync, USERSYNC_DEFAULT_CONFIG } = require('../../src/userSync'); describe('user sync', function () { let triggerPixelStub; @@ -34,6 +34,7 @@ describe('user sync', function () { }); beforeEach(function () { + config.setConfig({ userSync: USERSYNC_DEFAULT_CONFIG }); triggerPixelStub = sinon.stub(utils, 'triggerPixel'); logWarnStub = sinon.stub(utils, 'logWarn'); shuffleStub = sinon.stub(utils, 'shuffle').callsFake((array) => array.reverse()); @@ -47,6 +48,7 @@ describe('user sync', function () { shuffleStub.restore(); getUniqueIdentifierStrStub.restore(); insertUserSyncIframeStub.restore(); + config.resetConfig(); }); it('should register and fire a pixel URL', function () { @@ -374,6 +376,85 @@ describe('user sync', function () { expect(insertUserSyncIframeStub.getCall(0)).to.be.null; }); + it('should still allow default image syncs if setConfig only defined iframe', function () { + const userSync = newUserSync({ + config: config.getConfig('userSync'), + browserSupportsCookies: true + }); + + config.setConfig({ + userSync: { + filterSettings: { + iframe: { + bidders: ['bidderXYZ'], + filter: 'include' + } + } + } + }); + + userSync.registerSync('image', 'testBidder', 'http://example.com'); + userSync.registerSync('iframe', 'bidderXYZ', 'http://example.com/iframe'); + userSync.syncUsers(); + expect(triggerPixelStub.getCall(0)).to.not.be.null; + expect(triggerPixelStub.getCall(0).args[0]).to.exist.and.to.equal('http://example.com'); + expect(insertUserSyncIframeStub.getCall(0).args[0]).to.equal('http://example.com/iframe'); + }); + + it('should override default image syncs if setConfig used image filter', function () { + const userSync = newUserSync({ + config: config.getConfig('userSync'), + browserSupportsCookies: true + }); + + config.setConfig({ + userSync: { + filterSettings: { + image: { + bidders: ['bidderXYZ'], + filter: 'exclude' + } + } + } + }); + + userSync.registerSync('image', 'testBidder', 'http://example.com'); + userSync.registerSync('image', 'bidderXYZ', 'http://example.com/image-blocked'); + userSync.syncUsers(); + expect(triggerPixelStub.getCall(0)).to.not.be.null; + expect(triggerPixelStub.getCall(0).args[0]).to.exist.and.to.equal('http://example.com'); + expect(triggerPixelStub.getCall(1)).to.be.null; + }); + + it('should override default image syncs if setConfig used all filter', function() { + const userSync = newUserSync({ + config: config.getConfig('userSync'), + browserSupportsCookies: true + }); + + config.setConfig({ + userSync: { + filterSettings: { + all: { + bidders: ['bidderXYZ'], + filter: 'exclude' + } + } + } + }); + + userSync.registerSync('image', 'testBidder', 'http://example.com'); + userSync.registerSync('image', 'bidderXYZ', 'http://example.com/image-blocked'); + userSync.registerSync('iframe', 'testBidder', 'http://example.com/iframe'); + userSync.registerSync('iframe', 'bidderXYZ', 'http://example.com/iframe-blocked'); + userSync.syncUsers(); + expect(triggerPixelStub.getCall(0)).to.not.be.null; + expect(triggerPixelStub.getCall(0).args[0]).to.exist.and.to.equal('http://example.com'); + expect(triggerPixelStub.getCall(1)).to.be.null; + expect(insertUserSyncIframeStub.getCall(0).args[0]).to.equal('http://example.com/iframe'); + expect(insertUserSyncIframeStub.getCall(1)).to.be.null; + }); + describe('publicAPI', function () { describe('canBidderRegisterSync', function () { describe('with filterSettings', function () { diff --git a/test/spec/utils_spec.js b/test/spec/utils_spec.js old mode 100755 new mode 100644 index 012dfacd92f..4dbb40557af --- a/test/spec/utils_spec.js +++ b/test/spec/utils_spec.js @@ -1,7 +1,7 @@ -import { getAdServerTargeting } from 'test/fixtures/fixtures'; +import { getAdServerTargeting } from 'test/fixtures/fixtures.js'; import { expect } from 'chai'; import CONSTANTS from 'src/constants.json'; -import * as utils from 'src/utils'; +import * as utils from 'src/utils.js'; var assert = require('assert'); @@ -18,24 +18,6 @@ describe('Utils', function () { type_array = 'Array', type_function = 'Function'; - describe('replaceTokenInString', function () { - it('should replace all given tokens in a String', function () { - var tokensToReplace = { - foo: 'bar', - zap: 'quux' - }; - - var output = utils.replaceTokenInString('hello %FOO%, I am %ZAP%', tokensToReplace, '%'); - assert.equal(output, 'hello bar, I am quux'); - }); - - it('should ignore tokens it does not see', function () { - var output = utils.replaceTokenInString('hello %FOO%', {}, '%'); - - assert.equal(output, 'hello %FOO%'); - }); - }); - describe('getBidIdParameter', function () { it('should return value of the key in input object', function () { var obj = { @@ -81,12 +63,12 @@ describe('Utils', function () { describe('parseQueryStringParameters', function () { it('should append query string to existing using the input obj', function () { var obj = { - a: '1', - b: '2' + a: 'http://example.com/?foo=bar&bar=foo', + b: 'abc["def"]' }; var output = utils.parseQueryStringParameters(obj); - var expectedResult = 'a=' + encodeURIComponent('1') + '&b=' + encodeURIComponent('2') + '&'; + var expectedResult = 'a=' + encodeURIComponent('http://example.com/?foo=bar&bar=foo') + '&b=' + encodeURIComponent('abc["def"]'); assert.equal(output, expectedResult); }); @@ -699,20 +681,6 @@ describe('Utils', function () { }); }); - describe('createContentToExecuteExtScriptInFriendlyFrame', function () { - it('should return empty string if url is not passed', function () { - var output = utils.createContentToExecuteExtScriptInFriendlyFrame(); - assert.equal(output, ''); - }); - - it('should have URL in returned value if url is passed', function () { - var url = 'https://abcd.com/service?a=1&b=2&c=3'; - var output = utils.createContentToExecuteExtScriptInFriendlyFrame(url); - var expected = ``; - assert.equal(output, expected); - }); - }); - describe('getDefinedParams', function () { it('builds an object consisting of defined params', function () { const adUnit = { @@ -833,6 +801,98 @@ describe('Utils', function () { }); }); + describe('URL helpers', function () { + describe('parseUrl()', function () { + let parsed; + + beforeEach(function () { + parsed = utils.parseUrl('http://example.com:3000/pathname/?search=test&foo=bar&bar=foo%26foo%3Dxxx#hash'); + }); + + it('extracts the protocol', function () { + expect(parsed).to.have.property('protocol', 'http'); + }); + + it('extracts the hostname', function () { + expect(parsed).to.have.property('hostname', 'example.com'); + }); + + it('extracts the port', function () { + expect(parsed).to.have.property('port', 3000); + }); + + it('extracts the pathname', function () { + expect(parsed).to.have.property('pathname', '/pathname/'); + }); + + it('extracts the search query', function () { + expect(parsed).to.have.property('search'); + expect(parsed.search).to.eql({ + foo: 'xxx', + search: 'test', + bar: 'foo', + }); + }); + + it('extracts the hash', function () { + expect(parsed).to.have.property('hash', 'hash'); + }); + + it('extracts the host', function () { + expect(parsed).to.have.property('host', 'example.com:3000'); + }); + }); + + describe('parseUrl(url, {noDecodeWholeURL: true})', function () { + let parsed; + + beforeEach(function () { + parsed = utils.parseUrl('http://example.com:3000/pathname/?search=test&foo=bar&bar=foo%26foo%3Dxxx#hash', {noDecodeWholeURL: true}); + }); + + it('extracts the search query', function () { + expect(parsed).to.have.property('search'); + expect(parsed.search).to.eql({ + foo: 'bar', + search: 'test', + bar: 'foo%26foo%3Dxxx', + }); + }); + }); + + describe('buildUrl()', function () { + it('formats an object in to a URL', function () { + expect(utils.buildUrl({ + protocol: 'http', + hostname: 'example.com', + port: 3000, + pathname: '/pathname/', + search: {foo: 'bar', search: 'test', bar: 'foo%26foo%3Dxxx'}, + hash: 'hash' + })).to.equal('http://example.com:3000/pathname/?foo=bar&search=test&bar=foo%26foo%3Dxxx#hash'); + }); + + it('will use defaults for missing properties', function () { + expect(utils.buildUrl({ + hostname: 'example.com' + })).to.equal('http://example.com'); + }); + }); + + describe('parseUrl(url, {decodeSearchAsString: true})', function () { + let parsed; + + beforeEach(function () { + parsed = utils.parseUrl('http://example.com:3000/pathname/?search=test&foo=bar&bar=foo%26foo%3Dxxx#hash', {decodeSearchAsString: true}); + }); + + it('extracts the search query', function () { + expect(parsed).to.have.property('search'); + expect(parsed.search).to.equal('?search=test&foo=bar&bar=foo&foo=xxx'); + }); + }); + }); + describe('transformBidderParamKeywords', function () { it('returns an array of objects when keyvalue is an array', function () { let keywords = { @@ -922,4 +982,137 @@ describe('Utils', function () { }); }); }); + + describe('isSafariBrowser', function () { + let userAgentStub; + let userAgent; + + before(function () { + userAgentStub = sinon.stub(navigator, 'userAgent').get(function () { + return userAgent; + }); + }); + + after(function () { + userAgentStub.restore(); + }); + + it('properly detects safari', function () { + userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.25 (KHTML, like Gecko) Version/6.0 Safari/536.25'; + expect(utils.isSafariBrowser()).to.equal(true); + }); + it('does not flag Chrome on MacOS', function () { + userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'; + expect(utils.isSafariBrowser()).to.equal(false); + }); + it('does not flag Chrome iOS', function () { + userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/80.0.3987.95 Mobile/15E148 Safari/604.1'; + expect(utils.isSafariBrowser()).to.equal(false); + }); + it('does not flag Firefox iOS', function () { + userAgent = 'Mozilla/5.0 (iPhone; CPU OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/23.0 Mobile/15E148 Safari/605.1.15'; + expect(utils.isSafariBrowser()).to.equal(false); + }); + it('does not flag Windows Edge', function () { + userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.74 Safari/537.36 Edg/79.0.309.43'; + expect(utils.isSafariBrowser()).to.equal(false); + }); + }); + + describe('mergeDeep', function() { + it('properly merge objects that share same property names', function() { + const object1 = { + propA: { + subPropA: 'abc' + } + }; + const object2 = { + propA: { + subPropB: 'def' + } + }; + + const resultWithoutMergeDeep = Object.assign({}, object1, object2); + expect(resultWithoutMergeDeep).to.deep.equal({ + propA: { + subPropB: 'def' + } + }); + + const resultWithMergeDeep = utils.mergeDeep({}, object1, object2); + expect(resultWithMergeDeep).to.deep.equal({ + propA: { + subPropA: 'abc', + subPropB: 'def' + } + }); + }); + + it('properly merge objects that have different depths', function() { + const object1 = { + depth0_A: { + depth1_A: { + depth2_A: 123 + } + } + }; + const object2 = { + depth0_A: { + depth1_A: { + depth2_B: { + depth3_A: { + depth4_A: 'def' + } + } + }, + depth1_B: 'abc' + } + }; + const object3 = { + depth0_B: 456 + }; + + const result = utils.mergeDeep({}, object1, object2, object3); + expect(result).to.deep.equal({ + depth0_A: { + depth1_A: { + depth2_A: 123, + depth2_B: { + depth3_A: { + depth4_A: 'def' + } + } + }, + depth1_B: 'abc' + }, + depth0_B: 456 + }); + }); + + it('properly merge objects with various property types', function() { + const object1 = { + depth0_A: { + depth1_A: ['a', 'b', 'c'], + depth1_B: 'abc', + depth1_C: 123 + } + }; + const object2 = { + depth0_A: { + depth1_A: ['d', 'e', 'f'], + depth1_D: true, + } + }; + + const result = utils.mergeDeep({}, object1, object2); + expect(result).to.deep.equal({ + depth0_A: { + depth1_A: ['a', 'b', 'c', 'd', 'e', 'f'], + depth1_B: 'abc', + depth1_C: 123, + depth1_D: true, + } + }); + }); + }); }); diff --git a/test/spec/videoCache_spec.js b/test/spec/videoCache_spec.js index a3864eb22fa..6bb214af8a0 100644 --- a/test/spec/videoCache_spec.js +++ b/test/spec/videoCache_spec.js @@ -1,11 +1,54 @@ -import 'mocha/mocha'; import chai from 'chai'; -import { getCacheUrl, store } from 'src/videoCache'; -import { config } from 'src/config'; -import { server } from 'test/mocks/xhr'; +import { getCacheUrl, store } from 'src/videoCache.js'; +import { config } from 'src/config.js'; +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); @@ -193,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/test/spec/video_spec.js b/test/spec/video_spec.js index dc6c11a7491..72a585049c3 100644 --- a/test/spec/video_spec.js +++ b/test/spec/video_spec.js @@ -1,4 +1,4 @@ -import { isValidVideoBid } from 'src/video'; +import { isValidVideoBid } from 'src/video.js'; describe('video.js', function () { it('validates valid instream bids', function () { diff --git a/wdio.conf.js b/wdio.conf.js index 22765e34346..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,28 +37,29 @@ function getCapabilities() { } exports.config = { - // TODO: below change is only for testing and is to be removed. - specs: [ - './test/spec/e2e/banner/*.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'] +}